From e1cb32630a3f849691639a426cda32c9ef52616b Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 10 May 2024 15:07:13 -0700 Subject: [PATCH 001/177] 1st drop --- PSScriptAnalyzerSettings.psd1 | 4 +- pode.build.ps1 | 4 + src/Private/Authentication.ps1 | 113 +++- src/Private/AutoImport.ps1 | 2 +- src/Private/Context.ps1 | 74 ++- src/Private/CronParser.ps1 | 356 +++++++----- src/Private/Cryptography.ps1 | 155 ++++- src/Private/Endpoints.ps1 | 79 ++- src/Private/FileMonitor.ps1 | 4 +- src/Private/FileWatchers.ps1 | 14 +- src/Private/Helpers.ps1 | 872 +++++++++++++++++++++++------ src/Private/Logging.ps1 | 55 +- src/Private/Metrics.ps1 | 81 ++- src/Private/Middleware.ps1 | 1 + src/Private/OpenApi.ps1 | 137 ++++- src/Private/PodeServer.ps1 | 46 +- src/Private/Routes.ps1 | 32 +- src/Private/Schedules.ps1 | 32 +- src/Private/ScopedVariables.ps1 | 132 ++++- src/Private/Secrets.ps1 | 32 +- src/Private/Server.ps1 | 18 +- src/Private/Serverless.ps1 | 8 +- src/Private/ServiceServer.ps1 | 6 +- src/Private/Setup.ps1 | 29 +- src/Private/SmtpServer.ps1 | 20 +- src/Private/Streams.ps1 | 105 +++- src/Private/TcpServer.ps1 | 16 +- src/Private/Timers.ps1 | 2 +- src/Private/UnusedHelper.ps1 | 124 ++++ src/Private/WebSockets.ps1 | 14 +- src/Public/Authentication.ps1 | 9 + src/Public/Core.ps1 | 10 +- src/Public/FileWatchers.ps1 | 10 +- src/Public/Flash.ps1 | 4 +- src/Public/Logging.ps1 | 3 +- src/Public/Metrics.ps1 | 2 + src/Public/OAComponents.ps1 | 2 +- src/Public/OpenApi.ps1 | 4 +- src/Public/Responses.ps1 | 2 +- src/Public/Routes.ps1 | 51 +- src/Public/SSE.ps1 | 3 + src/Public/Schedules.ps1 | 4 +- src/Public/ScopedVariables.ps1 | 4 + src/Public/Security.ps1 | 8 +- src/Public/Sessions.ps1 | 2 + src/Public/Tasks.ps1 | 1 + src/Public/Utilities.ps1 | 5 +- src/Public/Verbs.ps1 | 8 +- src/Public/WebSockets.ps1 | 1 + tests/unit/CronParser.Tests.ps1 | 48 +- tests/unit/Cryptography.Tests.ps1 | 8 +- tests/unit/Helpers.Tests.ps1 | 70 +-- tests/unit/Routes.Tests.ps1 | 48 +- tests/unit/Schedules.Tests.ps1 | 1 - tests/unit/Server.Tests.ps1 | 14 +- tests/unit/Serverless.Tests.ps1 | 4 +- tests/unit/UnusedHelpers.Tests.ps1 | 62 ++ 57 files changed, 2306 insertions(+), 649 deletions(-) create mode 100644 src/Private/UnusedHelper.ps1 create mode 100644 tests/unit/UnusedHelpers.Tests.ps1 diff --git a/PSScriptAnalyzerSettings.psd1 b/PSScriptAnalyzerSettings.psd1 index 2141ac49d..99840546d 100644 --- a/PSScriptAnalyzerSettings.psd1 +++ b/PSScriptAnalyzerSettings.psd1 @@ -9,7 +9,7 @@ ) } } - ExcludeRules = @('PSAvoidUsingCmdletAliases' ,'PSAvoidUsingPlainTextForPassword','PSAvoidUsingWriteHost','PSAvoidUsingInvokeExpression','PSUseShouldProcessForStateChangingFunctions', - 'PSAvoidUsingUsernameAndPasswordParams','PSUseProcessBlockForPipelineCommand','PSAvoidUsingConvertToSecureStringWithPlainText','PSUseSingularNouns','PSReviewUnusedParameter' ) + ExcludeRules = @( 'PSAvoidUsingPlainTextForPassword','PSUseShouldProcessForStateChangingFunctions', + 'PSAvoidUsingUsernameAndPasswordParams','PSUseProcessBlockForPipelineCommand','PSAvoidUsingConvertToSecureStringWithPlainText','PSReviewUnusedParameter' ) } \ No newline at end of file diff --git a/pode.build.ps1 b/pode.build.ps1 index 6cd1d1010..36cc7e753 100644 --- a/pode.build.ps1 +++ b/pode.build.ps1 @@ -1,5 +1,9 @@ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '')] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingInvokeExpression', '')] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUSeDeclaredVarsMoreThanAssignments', '')] param( [string] $Version = '0.0.0', diff --git a/src/Private/Authentication.ps1 b/src/Private/Authentication.ps1 index 0656f4bf4..377dad84e 100644 --- a/src/Private/Authentication.ps1 +++ b/src/Private/Authentication.ps1 @@ -139,7 +139,7 @@ function Get-PodeAuthOAuth2Type { $result = Invoke-RestMethod -Method Post -Uri $options.Urls.Token -Body $body -ContentType 'application/x-www-form-urlencoded' -ErrorAction Stop } catch [System.Net.WebException], [System.Net.Http.HttpRequestException] { - $response = Read-PodeWebExceptionDetails -ErrorRecord $_ + $response = Read-PodeWebExceptionDetail -ErrorRecord $_ $result = ($response.Body | ConvertFrom-Json) } @@ -158,7 +158,7 @@ function Get-PodeAuthOAuth2Type { $user = Invoke-RestMethod -Method $options.Urls.User.Method -Uri $options.Urls.User.Url -Headers @{ Authorization = "Bearer $($result.access_token)" } } catch [System.Net.WebException], [System.Net.Http.HttpRequestException] { - $response = Read-PodeWebExceptionDetails -ErrorRecord $_ + $response = Read-PodeWebExceptionDetail -ErrorRecord $_ $user = ($response.Body | ConvertFrom-Json) } @@ -688,6 +688,33 @@ function Get-PodeAuthFormType { } } +<# +.SYNOPSIS + Authenticates a user based on a username and password provided as parameters. + +.DESCRIPTION + This function finds a user whose username matches the provided username, and checks the user's password. + If the password is correct, it converts the user into a hashtable and checks if the user is valid for any users/groups specified by the options parameter. If the user is valid, it returns a hashtable containing the user object. If the user is not valid, it returns a hashtable with a message indicating that the user is not authorized to access the website. + +.PARAMETER username + The username of the user to authenticate. + +.PARAMETER password + The password of the user to authenticate. + +.PARAMETER options + A hashtable containing options for the function. It can include the following keys: + - FilePath: The path to the JSON file containing user data. + - HmacSecret: The secret key for computing a HMAC-SHA256 hash of the password. + - Users: A list of valid users. + - Groups: A list of valid groups. + - ScriptBlock: A script block for additional validation. + +.EXAMPLE + Get-PodeAuthUserFileMethod -username "admin" -password "password123" -options @{ FilePath = "C:\Users.json"; HmacSecret = "secret"; Users = @("admin"); Groups = @("Administrators"); ScriptBlock = { param($user) $user.Name -eq "admin" } } + + This example authenticates a user with username "admin" and password "password123". It reads user data from the JSON file at "C:\Users.json", computes a HMAC-SHA256 hash of the password using "secret" as the secret key, and checks if the user is in the "admin" user or "Administrators" group. It also performs additional validation using a script block that checks if the user's name is "admin". +#> function Get-PodeAuthUserFileMethod { return { param($username, $password, $options) @@ -742,7 +769,7 @@ function Get-PodeAuthUserFileMethod { } # is the user valid for any users/groups? - if (!(Test-PodeAuthUserGroups -User $user -Users $_options.Users -Groups $_options.Groups)) { + if (!(Test-PodeAuthUserGroup -User $user -Users $_options.Users -Groups $_options.Groups)) { return @{ Message = 'You are not authorised to access this website' } } @@ -804,7 +831,7 @@ function Get-PodeAuthWindowsADMethod { } # is the user valid for any users/groups - if not, error! - if (!(Test-PodeAuthUserGroups -User $result.User -Users $_options.Users -Groups $_options.Groups)) { + if (!(Test-PodeAuthUserGroup -User $result.User -Users $_options.Users -Groups $_options.Groups)) { return @{ Message = 'You are not authorised to access this website' } } @@ -891,7 +918,7 @@ function Get-PodeAuthWindowsLocalMethod { } # is the user valid for any users/groups - if not, error! - if (!(Test-PodeAuthUserGroups -User $user -Users $_options.Users -Groups $_options.Groups)) { + if (!(Test-PodeAuthUserGroup -User $user -Users $_options.Users -Groups $_options.Groups)) { return @{ Message = 'You are not authorised to access this website' } } @@ -978,7 +1005,7 @@ function Get-PodeAuthWindowsADIISMethod { # get the users groups $directGroups = $options.DirectGroups - $user.Groups = (Get-PodeAuthADGroups -Connection $connection -DistinguishedName $user.DistinguishedName -Username $user.Username -Direct:$directGroups -Provider $options.Provider) + $user.Groups = (Get-PodeAuthADGroup -Connection $connection -DistinguishedName $user.DistinguishedName -Username $user.Username -Direct:$directGroups -Provider $options.Provider) } } finally { @@ -1023,7 +1050,7 @@ function Get-PodeAuthWindowsADIISMethod { } # is the user valid for any users/groups - if not, error! - if (!(Test-PodeAuthUserGroups -User $user -Users $options.Users -Groups $options.Groups)) { + if (!(Test-PodeAuthUserGroup -User $user -Users $options.Users -Groups $options.Groups)) { return @{ Message = 'You are not authorised to access this website' } } @@ -1039,7 +1066,31 @@ function Get-PodeAuthWindowsADIISMethod { } } -function Test-PodeAuthUserGroups { +<# + .SYNOPSIS + Authenticates a user based on group membership or specific user authorization. + + .DESCRIPTION + This function checks if a given user is authorized based on supplied lists of users and groups. The user is considered authorized if their username is directly specified in the list of users, or if they are a member of any of the specified groups. + + .PARAMETER User + A hashtable representing the user, expected to contain at least the 'Username' and 'Groups' keys. + + .PARAMETER Users + An optional array of usernames. If specified, the function checks if the user's username exists in this list. + + .PARAMETER Groups + An optional array of group names. If specified, the function checks if the user belongs to any of these groups. + + .EXAMPLE + $user = @{ Username = 'john.doe'; Groups = @('Administrators', 'Users') } + $authorizedUsers = @('john.doe', 'jane.doe') + $authorizedGroups = @('Administrators') + + Test-PodeAuthUserGroup -User $user -Users $authorizedUsers -Groups $authorizedGroups + # Returns true if John Doe is either listed as an authorized user or is a member of an authorized group. +#> +function Test-PodeAuthUserGroup { param( [Parameter(Mandatory = $true)] [hashtable] @@ -1289,6 +1340,7 @@ function Get-PodeAuthMiddlewareScript { function Test-PodeAuthInternal { [CmdletBinding()] + [OutputType([bool])] param( [Parameter(Mandatory = $true)] [string] @@ -1731,7 +1783,7 @@ function Get-PodeAuthADResult { # get the users groups $groups = @() if (!$NoGroups) { - $groups = (Get-PodeAuthADGroups -Connection $connection -DistinguishedName $user.DistinguishedName -Username $Username -Direct:$DirectGroups -Provider $Provider) + $groups = (Get-PodeAuthADGroup -Connection $connection -DistinguishedName $user.DistinguishedName -Username $Username -Direct:$DirectGroups -Provider $Provider) } # check if we want to keep the credentials in the User object @@ -1983,8 +2035,41 @@ function Get-PodeOpenLdapValue { } } } +<# +.SYNOPSIS + Retrieves Active Directory (AD) group information for a user. + +.DESCRIPTION + This function retrieves AD group information for a specified user. It supports two modes of operation: + 1. Direct: Retrieves groups directly associated with the user. + 2. All: Retrieves all groups within the specified distinguished name (DN). + +.PARAMETER Connection + The AD connection object or credentials for connecting to the AD server. -function Get-PodeAuthADGroups { +.PARAMETER DistinguishedName + The distinguished name (DN) of the user or group. If not provided, the default DN is used. + +.PARAMETER Username + The username for which to retrieve group information. + +.PARAMETER Provider + The AD provider to use (e.g., 'DirectoryServices', 'ActiveDirectory', 'OpenLDAP'). + +.PARAMETER Direct + Switch parameter. If specified, retrieves only direct group memberships for the user. + +.OUTPUTS + Returns AD group information as needed based on the mode of operation. + +.EXAMPLE + Get-PodeAuthADGroup -Connection $adConnection -Username "john.doe" + # Retrieves all AD groups for the user "john.doe". + + Get-PodeAuthADGroup -Connection $adConnection -Username "jane.smith" -Direct + # Retrieves only direct group memberships for the user "jane.smith". +#> +function Get-PodeAuthADGroup { param( [Parameter(Mandatory = $true)] $Connection, @@ -2007,13 +2092,13 @@ function Get-PodeAuthADGroups { ) if ($Direct) { - return (Get-PodeAuthADGroupsDirect -Connection $Connection -Username $Username -Provider $Provider) + return (Get-PodeAuthADGroupDirect -Connection $Connection -Username $Username -Provider $Provider) } - return (Get-PodeAuthADGroupsAll -Connection $Connection -DistinguishedName $DistinguishedName -Provider $Provider) + return (Get-PodeAuthADGroupAll -Connection $Connection -DistinguishedName $DistinguishedName -Provider $Provider) } -function Get-PodeAuthADGroupsDirect { +function Get-PodeAuthADGroupDirect { param( [Parameter(Mandatory = $true)] $Connection, @@ -2062,7 +2147,7 @@ function Get-PodeAuthADGroupsDirect { return $groups } -function Get-PodeAuthADGroupsAll { +function Get-PodeAuthADGroupAll { param( [Parameter(Mandatory = $true)] $Connection, diff --git a/src/Private/AutoImport.ps1 b/src/Private/AutoImport.ps1 index a200cdbc8..a618711ea 100644 --- a/src/Private/AutoImport.ps1 +++ b/src/Private/AutoImport.ps1 @@ -70,7 +70,7 @@ function Import-PodeModulesIntoRunspaceState { # work out which order the modules need to be loaded $modulesOrder = @(foreach ($module in $modules) { - Get-PodeModuleDependencies -Module $module + Get-PodeModuleDependency -Module $module }) | Where-Object { ($_.Name -inotin @('pode', 'pode.internal')) -and ($_.Name -inotlike 'microsoft.powershell.*') diff --git a/src/Private/Context.ps1 b/src/Private/Context.ps1 index 457352788..88869c4f5 100644 --- a/src/Private/Context.ps1 +++ b/src/Private/Context.ps1 @@ -90,7 +90,7 @@ function New-PodeContext { $ctx.Server.Logic = $ScriptBlock $ctx.Server.LogicPath = $FilePath $ctx.Server.Interval = $Interval - $ctx.Server.PodeModule = (Get-PodeModuleDetails) + $ctx.Server.PodeModule = (Get-PodeModuleInfo) $ctx.Server.DisableTermination = $DisableTermination.IsPresent $ctx.Server.Quiet = $Quiet.IsPresent $ctx.Server.ComputerName = [System.Net.DNS]::GetHostName() @@ -147,7 +147,7 @@ function New-PodeContext { # set socket details for pode server $ctx.Server.Sockets = @{ Ssl = @{ - Protocols = Get-PodeDefaultSslProtocols + Protocols = Get-PodeDefaultSslProtocol } ReceiveTimeout = 100 } @@ -505,7 +505,17 @@ function New-PodeRunspaceState { $PodeContext.RunspaceState = $state } -function New-PodeRunspacePools { +<# +.SYNOPSIS + Creates and initializes runspace pools for various Pode components. + +.DESCRIPTION + This function sets up runspace pools for different Pode components, such as timers, schedules, web endpoints, web sockets, SMTP, TCP, and more. It dynamically adjusts the thread counts based on the presence of specific components and their configuration. + +.OUTPUTS + Initializes and configures runspace pools for various Pode components. +#> +function New-PodeRunspacePool { if ($PodeContext.Server.IsServerless) { return } @@ -539,7 +549,7 @@ function New-PodeRunspacePools { } # web runspace - if we have any http/s endpoints - if (Test-PodeEndpoints -Type Http) { + if (Test-PodeEndpoint -Type Http) { $PodeContext.RunspacePools.Web = @{ Pool = [runspacefactory]::CreateRunspacePool(1, ($PodeContext.Threads.General + 1), $PodeContext.RunspaceState, $Host) State = 'Waiting' @@ -547,7 +557,7 @@ function New-PodeRunspacePools { } # smtp runspace - if we have any smtp endpoints - if (Test-PodeEndpoints -Type Smtp) { + if (Test-PodeEndpoint -Type Smtp) { $PodeContext.RunspacePools.Smtp = @{ Pool = [runspacefactory]::CreateRunspacePool(1, ($PodeContext.Threads.General + 1), $PodeContext.RunspaceState, $Host) State = 'Waiting' @@ -555,7 +565,7 @@ function New-PodeRunspacePools { } # tcp runspace - if we have any tcp endpoints - if (Test-PodeEndpoints -Type Tcp) { + if (Test-PodeEndpoint -Type Tcp) { $PodeContext.RunspacePools.Tcp = @{ Pool = [runspacefactory]::CreateRunspacePool(1, ($PodeContext.Threads.General + 1), $PodeContext.RunspaceState, $Host) State = 'Waiting' @@ -563,7 +573,7 @@ function New-PodeRunspacePools { } # signals runspace - if we have any ws/s endpoints - if (Test-PodeEndpoints -Type Ws) { + if (Test-PodeEndpoint -Type Ws) { $PodeContext.RunspacePools.Signals = @{ Pool = [runspacefactory]::CreateRunspacePool(1, ($PodeContext.Threads.General + 2), $PodeContext.RunspaceState, $Host) State = 'Waiting' @@ -615,13 +625,23 @@ function New-PodeRunspacePools { } } -function Open-PodeRunspacePools { +<# +.SYNOPSIS + Opens and initializes runspace pools for various Pode components. + +.DESCRIPTION + This function opens and initializes runspace pools for different Pode components, such as timers, schedules, web endpoints, web sockets, SMTP, TCP, and more. It asynchronously opens the pools and waits for them to be in the 'Opened' state. If any pool fails to open, it reports an error. + +.OUTPUTS + Opens and initializes runspace pools for various Pode components. +#> +function Open-PodeRunspacePool { if ($PodeContext.Server.IsServerless) { return } $start = [datetime]::Now - Write-Verbose 'Opening RunspacePools' + Write-Verbose 'Opening RunspacePool' # open pools async foreach ($key in $PodeContext.RunspacePools.Keys) { @@ -670,16 +690,26 @@ function Open-PodeRunspacePools { } } - Write-Verbose "RunspacePools opened [duration: $(([datetime]::Now - $start).TotalSeconds)s]" + Write-Verbose "RunspacePool opened [duration: $(([datetime]::Now - $start).TotalSeconds)s]" } -function Close-PodeRunspacePools { +<# +.SYNOPSIS + Closes and disposes runspace pools for various Pode components. + +.DESCRIPTION + This function closes and disposes runspace pools for different Pode components, such as timers, schedules, web endpoints, web sockets, SMTP, TCP, and more. It asynchronously closes the pools and waits for them to be in the 'Closed' state. If any pool fails to close, it reports an error. + +.OUTPUTS + Closes and disposes runspace pools for various Pode components. +#> +function Close-PodeRunspacePool { if ($PodeContext.Server.IsServerless -or ($null -eq $PodeContext.RunspacePools)) { return } $start = [datetime]::Now - Write-Verbose 'Closing RunspacePools' + Write-Verbose 'Closing RunspacePool' # close pools async foreach ($key in $PodeContext.RunspacePools.Keys) { @@ -736,7 +766,7 @@ function Close-PodeRunspacePools { Close-PodeDisposable -Disposable $item.Pool } - Write-Verbose "RunspacePools closed [duration: $(([datetime]::Now - $start).TotalSeconds)s]" + Write-Verbose "RunspacePool closed [duration: $(([datetime]::Now - $start).TotalSeconds)s]" } function New-PodeStateContext { @@ -824,7 +854,7 @@ function Set-PodeServerConfiguration { # sockets if (!(Test-PodeIsEmpty $Configuration.Ssl.Protocols)) { - $Context.Server.Sockets.Ssl.Protocols = (ConvertTo-PodeSslProtocols -Protocols $Configuration.Ssl.Protocols) + $Context.Server.Sockets.Ssl.Protocols = (ConvertTo-PodeSslProtocol -Protocol $Configuration.Ssl.Protocols) } if ([int]$Configuration.ReceiveTimeout -gt 0) { @@ -929,6 +959,9 @@ function Set-PodeWebConfiguration { } function New-PodeAutoRestartServer { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSPossibleIncorrectComparisonWithNull', '')] + [CmdletBinding()] + param() # don't configure if not supplied, or running as serverless $config = (Get-PodeConfig) if (($null -eq $config) -or ($null -eq $config.Server.Restart) -or $PodeContext.Server.IsServerless) { @@ -969,7 +1002,18 @@ function New-PodeAutoRestartServer { } } -function Set-PodeOutputVariables { +<# +.SYNOPSIS + Sets global output variables based on the Pode server context. + +.DESCRIPTION + This function sets global output variables based on the Pode server context. It retrieves output variables from the server context and assigns them as global variables. These output variables can be accessed and used in other parts of your code. + +.OUTPUTS + Sets global output variables based on the Pode server context. + +#> +function Set-PodeOutputVariable { if (Test-PodeIsEmpty $PodeContext.Server.Output.Variables) { return } diff --git a/src/Private/CronParser.ps1 b/src/Private/CronParser.ps1 index 55336397d..60936ac7b 100644 --- a/src/Private/CronParser.ps1 +++ b/src/Private/CronParser.ps1 @@ -1,5 +1,21 @@ -function Get-PodeCronFields { - return @( +<# +.SYNOPSIS + Provides a list of cron expression fields. + +.DESCRIPTION + This function returns an array of strings representing the different fields in a cron expression. These fields include 'Minute', 'Hour', 'DayOfMonth', 'Month', and 'DayOfWeek'. + +.OUTPUTS + Returns an array of strings representing cron expression fields. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Get-PodeCronField { + [CmdletBinding()] + [OutputType([string[]])] + param() + return [string[]]@( 'Minute', 'Hour', 'DayOfMonth', @@ -8,7 +24,23 @@ function Get-PodeCronFields { ) } -function Get-PodeCronFieldConstraints { +<# +.SYNOPSIS + Provides constraints and information for cron expression fields. + +.DESCRIPTION + This function returns a hashtable containing constraints and information for various cron expression fields. It includes details such as valid ranges for minutes, hours, days of the month, months, and days of the week. + +.OUTPUTS + Returns a hashtable with constraints and information for cron expression fields. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Get-PodeCronFieldConstraint { + [CmdletBinding()] + [OutputType([hashtable])] + param() return @{ MinMax = @( @(0, 59), @@ -49,7 +81,23 @@ function Get-PodeCronPredefined { } } -function Get-PodeCronFieldAliases { +<# +.SYNOPSIS + Provides aliases for cron expression fields. + +.DESCRIPTION + This function returns a hashtable containing aliases for cron expression fields. It includes mappings for month abbreviations (e.g., 'Jan' to 1) and day of the week abbreviations (e.g., 'Sun' to 0). + +.OUTPUTS + Returns a hashtable with aliases for cron expression fields. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Get-PodeCronFieldAlias { + [CmdletBinding()] + [OutputType([hashtable])] + param() return @{ Month = @{ Jan = 1 @@ -77,193 +125,214 @@ function Get-PodeCronFieldAliases { } } -function ConvertFrom-PodeCronExpressions { - param( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string[]] - $Expressions - ) +<# +.SYNOPSIS + Converts a Pode-style cron expression into a hashtable representation. - return @(@($Expressions) | ForEach-Object { - ConvertFrom-PodeCronExpression -Expression $_ - }) -} +.DESCRIPTION + This function takes an array of Pode-style cron expressions and converts them into a hashtable format. Each hashtable represents a cron expression with its individual components. + +.PARAMETER Expression + An array of Pode-style cron expressions to convert. + +.OUTPUTS + A hashtable representing the cron expression with the following keys: + - 'Minute' + - 'Hour' + - 'DayOfMonth' + - 'Month' + - 'DayOfWeek' + +.NOTES + This is an internal function and may change in future releases of Pode. +#> function ConvertFrom-PodeCronExpression { + [CmdletBinding()] + [OutputType([hashtable])] param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [string] + [string[]] $Expression ) + $cronList = @() - $Expression = $Expression.Trim() - - # check predefineds - $predef = Get-PodeCronPredefined - if (!(Test-PodeIsEmpty $predef[$Expression])) { - $Expression = $predef[$Expression] - } + foreach ($item in $Expression) { + if ([string]::IsNullOrEmpty($item)) { + continue + } + $item = $item.Trim() - # split and check atoms length - $atoms = @($Expression -isplit '\s+') - if ($atoms.Length -ne 5) { - throw "Cron expression should only consist of 5 parts: $($Expression)" - } + # check predefineds + $predef = Get-PodeCronPredefined + if (!(Test-PodeIsEmpty $predef[$item])) { + $item = $predef[$item] + } - # basic variables - $aliasRgx = '(?[a-z]{3})' - - # get cron obj and validate atoms - $fields = Get-PodeCronFields - $constraints = Get-PodeCronFieldConstraints - $aliases = Get-PodeCronFieldAliases - $cron = @{} - - for ($i = 0; $i -lt $atoms.Length; $i++) { - $_cronExp = @{ - Range = $null - Values = $null - Constraints = $null - Random = $false - WildCard = $false + # split and check atoms length + $atoms = @($item -isplit '\s+') + if ($atoms.Length -ne 5) { + throw "Cron expression should only consist of 5 parts: $($item)" } - $_atom = $atoms[$i] - $_field = $fields[$i] - $_constraint = $constraints.MinMax[$i] - $_aliases = $aliases[$_field] - - # replace day of week and months with numbers - if (@('month', 'dayofweek') -icontains $_field) { - while ($_atom -imatch $aliasRgx) { - $_alias = $_aliases[$Matches['tag']] - if ($null -eq $_alias) { - throw "Invalid $($_field) alias found: $($Matches['tag'])" + # basic variables + $aliasRgx = '(?[a-z]{3})' + + # get cron obj and validate atoms + $fields = Get-PodeCronField + $constraints = Get-PodeCronFieldConstraint + $aliases = Get-PodeCronFieldAlias + $cron = @{} + + for ($i = 0; $i -lt $atoms.Length; $i++) { + $_cronExp = @{ + Range = $null + Values = $null + Constraints = $null + Random = $false + WildCard = $false + } + + $_atom = $atoms[$i] + $_field = $fields[$i] + $_constraint = $constraints.MinMax[$i] + $_aliases = $aliases[$_field] + + # replace day of week and months with numbers + if (@('month', 'dayofweek') -icontains $_field) { + while ($_atom -imatch $aliasRgx) { + $_alias = $_aliases[$Matches['tag']] + if ($null -eq $_alias) { + throw "Invalid $($_field) alias found: $($Matches['tag'])" + } + + $_atom = $_atom -ireplace $Matches['tag'], $_alias + $null = $_atom -imatch $aliasRgx } + } - $_atom = $_atom -ireplace $Matches['tag'], $_alias - $null = $_atom -imatch $aliasRgx + # ensure atom is a valid value + if (!($_atom -imatch '^[\d|/|*|\-|,r]+$')) { + throw "Invalid atom character: $($_atom)" } - } - # ensure atom is a valid value - if (!($_atom -imatch '^[\d|/|*|\-|,r]+$')) { - throw "Invalid atom character: $($_atom)" - } + # replace * with min/max constraint + if ($_atom -ieq '*') { + $_cronExp.WildCard = $true + $_atom = ($_constraint -join '-') + } - # replace * with min/max constraint - if ($_atom -ieq '*') { - $_cronExp.WildCard = $true - $_atom = ($_constraint -join '-') - } + # parse the atom for either a literal, range, array, or interval + # literal + if ($_atom -imatch '^(\d+|r)$') { + # check if it's random + if ($_atom -ieq 'r') { + $_cronExp.Values = @(Get-Random -Minimum $_constraint[0] -Maximum ($_constraint[1] + 1)) + $_cronExp.Random = $true + } + else { + $_cronExp.Values = @([int]$_atom) + } + } - # parse the atom for either a literal, range, array, or interval - # literal - if ($_atom -imatch '^(\d+|r)$') { - # check if it's random - if ($_atom -ieq 'r') { - $_cronExp.Values = @(Get-Random -Minimum $_constraint[0] -Maximum ($_constraint[1] + 1)) - $_cronExp.Random = $true + # range + elseif ($_atom -imatch '^(?\d+)\-(?\d+)$') { + $_cronExp.Range = @{ 'Min' = [int]($Matches['min'].Trim()); 'Max' = [int]($Matches['max'].Trim()); } } - else { - $_cronExp.Values = @([int]$_atom) + + # array + elseif ($_atom -imatch '^[\d,]+$') { + $_cronExp.Values = [int[]](@($_atom -split ',').Trim()) } - } - # range - elseif ($_atom -imatch '^(?\d+)\-(?\d+)$') { - $_cronExp.Range = @{ 'Min' = [int]($Matches['min'].Trim()); 'Max' = [int]($Matches['max'].Trim()); } - } + # interval + elseif ($_atom -imatch '(?(\d+|\*))\/(?(\d+|r))$') { + $start = $Matches['start'] + $interval = $Matches['interval'] - # array - elseif ($_atom -imatch '^[\d,]+$') { - $_cronExp.Values = [int[]](@($_atom -split ',').Trim()) - } + if ($interval -ieq '0') { + $interval = '1' + } - # interval - elseif ($_atom -imatch '(?(\d+|\*))\/(?(\d+|r))$') { - $start = $Matches['start'] - $interval = $Matches['interval'] + if ([string]::IsNullOrWhiteSpace($start) -or ($start -ieq '*')) { + $start = '0' + } - if ($interval -ieq '0') { - $interval = '1' - } + # set the initial trigger value + $_cronExp.Values = @([int]$start) - if ([string]::IsNullOrWhiteSpace($start) -or ($start -ieq '*')) { - $start = '0' + # check if it's random + if ($interval -ieq 'r') { + $_cronExp.Random = $true + } + else { + # loop to get all next values + $next = [int]$start + [int]$interval + while ($next -le $_constraint[1]) { + $_cronExp.Values += $next + $next += [int]$interval + } + } } - # set the initial trigger value - $_cronExp.Values = @([int]$start) - - # check if it's random - if ($interval -ieq 'r') { - $_cronExp.Random = $true - } + # error else { - # loop to get all next values - $next = [int]$start + [int]$interval - while ($next -le $_constraint[1]) { - $_cronExp.Values += $next - $next += [int]$interval - } + throw "Invalid cron atom format found: $($_atom)" } - } - # error - else { - throw "Invalid cron atom format found: $($_atom)" - } + # ensure cron expression values are valid + if ($null -ne $_cronExp.Range) { + if ($_cronExp.Range.Min -gt $_cronExp.Range.Max) { + throw "Min value for $($_field) should not be greater than the max value" + } - # ensure cron expression values are valid - if ($null -ne $_cronExp.Range) { - if ($_cronExp.Range.Min -gt $_cronExp.Range.Max) { - throw "Min value for $($_field) should not be greater than the max value" - } + if ($_cronExp.Range.Min -lt $_constraint[0]) { + throw "Min value '$($_cronExp.Range.Min)' for $($_field) is invalid, should be greater than/equal to $($_constraint[0])" + } - if ($_cronExp.Range.Min -lt $_constraint[0]) { - throw "Min value '$($_cronExp.Range.Min)' for $($_field) is invalid, should be greater than/equal to $($_constraint[0])" + if ($_cronExp.Range.Max -gt $_constraint[1]) { + throw "Max value '$($_cronExp.Range.Max)' for $($_field) is invalid, should be less than/equal to $($_constraint[1])" + } } - if ($_cronExp.Range.Max -gt $_constraint[1]) { - throw "Max value '$($_cronExp.Range.Max)' for $($_field) is invalid, should be less than/equal to $($_constraint[1])" + if ($null -ne $_cronExp.Values) { + $_cronExp.Values | ForEach-Object { + if ($_ -lt $_constraint[0] -or $_ -gt $_constraint[1]) { + throw "Value '$($_)' for $($_field) is invalid, should be between $($_constraint[0]) and $($_constraint[1])" + } + } } + + # assign value + $_cronExp.Constraints = $_constraint + $cron[$_field] = $_cronExp } - if ($null -ne $_cronExp.Values) { - $_cronExp.Values | ForEach-Object { - if ($_ -lt $_constraint[0] -or $_ -gt $_constraint[1]) { - throw "Value '$($_)' for $($_field) is invalid, should be between $($_constraint[0]) and $($_constraint[1])" + # post validation for month/days in month + if (($null -ne $cron['Month'].Values) -and ($null -ne $cron['DayOfMonth'].Values)) { + foreach ($mon in $cron['Month'].Values) { + foreach ($day in $cron['DayOfMonth'].Values) { + if ($day -gt $constraints.DaysInMonths[$mon - 1]) { + throw "$($constraints.Months[$mon - 1]) only has $($constraints.DaysInMonths[$mon - 1]) days, but $($day) was supplied" + } } } } - # assign value - $_cronExp.Constraints = $_constraint - $cron[$_field] = $_cronExp - } + # flag if this cron contains a random atom + $cron['Random'] = (($cron.Values | Where-Object { $_.Random } | Measure-Object).Count -gt 0) - # post validation for month/days in month - if (($null -ne $cron['Month'].Values) -and ($null -ne $cron['DayOfMonth'].Values)) { - foreach ($mon in $cron['Month'].Values) { - foreach ($day in $cron['DayOfMonth'].Values) { - if ($day -gt $constraints.DaysInMonths[$mon - 1]) { - throw "$($constraints.Months[$mon - 1]) only has $($constraints.DaysInMonths[$mon - 1]) days, but $($day) was supplied" - } - } - } + # add the cron to the list + $cronList += $cron } - # flag if this cron contains a random atom - $cron['Random'] = (($cron.Values | Where-Object { $_.Random } | Measure-Object).Count -gt 0) - - # return the parsed cron expression - return $cron + # return the cronlist + return $cronList } function Reset-PodeRandomCronExpressions { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] param( [Parameter(Mandatory = $true)] [ValidateNotNull()] @@ -308,6 +377,7 @@ function Reset-PodeRandomCronExpression { } function Test-PodeCronExpressions { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] param( [Parameter(Mandatory = $true)] [ValidateNotNull()] diff --git a/src/Private/Cryptography.ps1 b/src/Private/Cryptography.ps1 index 76805e20a..cbccbf3e0 100644 --- a/src/Private/Cryptography.ps1 +++ b/src/Private/Cryptography.ps1 @@ -1,5 +1,37 @@ +<# +.SYNOPSIS + Computes an HMAC-SHA256 hash for a given value using a secret key. + +.DESCRIPTION + This function calculates an HMAC-SHA256 hash for the specified value using either a secret provided as a string or as a byte array. It supports two parameter sets: + 1. String: The secret is provided as a string. + 2. Bytes: The secret is provided as a byte array. + +.PARAMETER Value + The value for which the HMAC-SHA256 hash needs to be computed. + +.PARAMETER Secret + The secret key as a string. If this parameter is provided, it will be converted to a byte array. + +.PARAMETER SecretBytes + The secret key as a byte array. If this parameter is provided, it will be used directly. + +.OUTPUTS + Returns the computed HMAC-SHA256 hash as a base64-encoded string. + +.EXAMPLE + $value = "MySecretValue" + $secret = "MySecretKey" + $hash = Invoke-PodeHMACSHA256Hash -Value $value -Secret $secret + Write-Host "HMAC-SHA256 hash: $hash" + + This example computes the HMAC-SHA256 hash for the value "MySecretValue" using the secret key "MySecretKey". +.NOTES + - This function is intended for internal use. +#> function Invoke-PodeHMACSHA256Hash { [CmdletBinding(DefaultParameterSetName = 'String')] + [OutputType([String])] param( [Parameter(Mandatory = $true)] [string] @@ -14,20 +46,56 @@ function Invoke-PodeHMACSHA256Hash { $SecretBytes ) + # Convert secret to byte array if provided as a string if (![string]::IsNullOrWhiteSpace($Secret)) { $SecretBytes = [System.Text.Encoding]::UTF8.GetBytes($Secret) } + # Validate secret length if ($SecretBytes.Length -eq 0) { throw 'No secret supplied for HMAC256 hash' } + # Compute HMAC-SHA384 hash $crypto = [System.Security.Cryptography.HMACSHA256]::new($SecretBytes) return [System.Convert]::ToBase64String($crypto.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($Value))) } +<# +.SYNOPSIS + Computes a private HMAC-SHA384 hash for a given value using a secret key. + +.DESCRIPTION + This function calculates a private HMAC-SHA384 hash for the specified value using either a secret provided as a string or as a byte array. It supports two parameter sets: + 1. String: The secret is provided as a string. + 2. Bytes: The secret is provided as a byte array. + +.PARAMETER Value + The value for which the private HMAC-SHA384 hash needs to be computed. + +.PARAMETER Secret + The secret key as a string. If this parameter is provided, it will be converted to a byte array. + +.PARAMETER SecretBytes + The secret key as a byte array. If this parameter is provided, it will be used directly. + +.OUTPUTS + Returns the computed private HMAC-SHA384 hash as a base64-encoded string. + +.EXAMPLE + $value = "MySecretValue" + $secret = "MySecretKey" + $hash = Invoke-PodeHMACSHA384Hash -Value $value -Secret $secret + Write-Host "Private HMAC-SHA384 hash: $hash" + + This example computes the private HMAC-SHA384 hash for the value "MySecretValue" using the secret key "MySecretKey". + +.NOTES + - This function is intended for internal use. +#> function Invoke-PodeHMACSHA384Hash { [CmdletBinding(DefaultParameterSetName = 'String')] + [OutputType([String])] param( [Parameter(Mandatory = $true)] [string] @@ -42,20 +110,56 @@ function Invoke-PodeHMACSHA384Hash { $SecretBytes ) + # Convert secret to byte array if provided as a string if (![string]::IsNullOrWhiteSpace($Secret)) { $SecretBytes = [System.Text.Encoding]::UTF8.GetBytes($Secret) } + # Validate secret length if ($SecretBytes.Length -eq 0) { throw 'No secret supplied for HMAC384 hash' } + # Compute private HMAC-SHA384 hash $crypto = [System.Security.Cryptography.HMACSHA384]::new($SecretBytes) return [System.Convert]::ToBase64String($crypto.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($Value))) } +<# +.SYNOPSIS + Computes a private HMAC-SHA512 hash for a given value using a secret key. + +.DESCRIPTION + This function calculates a private HMAC-SHA512 hash for the specified value using either a secret provided as a string or as a byte array. It supports two parameter sets: + 1. String: The secret is provided as a string. + 2. Bytes: The secret is provided as a byte array. + +.PARAMETER Value + The value for which the private HMAC-SHA512 hash needs to be computed. + +.PARAMETER Secret + The secret key as a string. If this parameter is provided, it will be converted to a byte array. + +.PARAMETER SecretBytes + The secret key as a byte array. If this parameter is provided, it will be used directly. + +.OUTPUTS + Returns the computed private HMAC-SHA512 hash as a base64-encoded string. + +.EXAMPLE + $value = "MySecretValue" + $secret = "MySecretKey" + $hash = Invoke-PodeHMACSHA512Hash -Value $value -Secret $secret + Write-Host "Private HMAC-SHA512 hash: $hash" + + This example computes the private HMAC-SHA512 hash for the value "MySecretValue" using the secret key "MySecretKey". + +.NOTES + - This function is intended for internal use. +#> function Invoke-PodeHMACSHA512Hash { [CmdletBinding(DefaultParameterSetName = 'String')] + [OutputType([string])] param( [Parameter(Mandatory = $true)] [string] @@ -70,19 +174,24 @@ function Invoke-PodeHMACSHA512Hash { $SecretBytes ) + # Convert secret to byte array if provided as a string if (![string]::IsNullOrWhiteSpace($Secret)) { $SecretBytes = [System.Text.Encoding]::UTF8.GetBytes($Secret) } + # Validate secret length if ($SecretBytes.Length -eq 0) { throw 'No secret supplied for HMAC512 hash' } + # Compute private HMAC-SHA512 hash $crypto = [System.Security.Cryptography.HMACSHA512]::new($SecretBytes) return [System.Convert]::ToBase64String($crypto.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($Value))) } function Invoke-PodeSHA256Hash { + [CmdletBinding()] + [OutputType([string])] param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] @@ -95,6 +204,8 @@ function Invoke-PodeSHA256Hash { } function Invoke-PodeSHA1Hash { + [CmdletBinding()] + [OutputType([string])] param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] @@ -107,6 +218,8 @@ function Invoke-PodeSHA1Hash { } function ConvertTo-PodeBase64Auth { + [CmdletBinding()] + [OutputType([string])] param( [Parameter(Mandatory = $true)] [string] @@ -121,6 +234,8 @@ function ConvertTo-PodeBase64Auth { } function Invoke-PodeMD5Hash { + [CmdletBinding()] + [OutputType([string])] param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] @@ -132,7 +247,25 @@ function Invoke-PodeMD5Hash { return [System.BitConverter]::ToString($crypto.ComputeHash([System.Text.Encoding]::ASCII.GetBytes($Value))).Replace('-', '').ToLowerInvariant() } -function Get-PodeRandomBytes { +<# +.SYNOPSIS +Generates a random byte array of specified length. + +.DESCRIPTION +This function generates a random byte array using the .NET `System.Security.Cryptography.RandomNumberGenerator` class. You can specify the desired length of the byte array. + +.PARAMETER Length +The length of the byte array to generate (default is 16). + +.OUTPUTS +An array of bytes representing the random byte array. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Get-PodeRandomByte { + [CmdletBinding()] + [OutputType([System.Object[]])] param( [Parameter()] [int] @@ -148,17 +281,21 @@ function Get-PodeRandomBytes { } function New-PodeSalt { + [CmdletBinding()] + [OutputType([string])] param( [Parameter()] [int] $Length = 8 ) - $bytes = [byte[]](Get-PodeRandomBytes -Length $Length) + $bytes = [byte[]](Get-PodeRandomByte -Length $Length) return [System.Convert]::ToBase64String($bytes) } function New-PodeGuid { + [CmdletBinding()] + [OutputType([string])] param( [Parameter()] [int] @@ -173,7 +310,7 @@ function New-PodeGuid { # generate a cryptographically secure guid if ($Secure) { - $bytes = [byte[]](Get-PodeRandomBytes -Length $Length) + $bytes = [byte[]](Get-PodeRandomByte -Length $Length) $guid = ([guid]::new($bytes)).ToString() } @@ -190,6 +327,8 @@ function New-PodeGuid { } function Invoke-PodeValueSign { + [CmdletBinding()] + [OutputType([string])] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] @@ -213,6 +352,8 @@ function Invoke-PodeValueSign { } function Invoke-PodeValueUnsign { + [CmdletBinding()] + [OutputType([string])] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] @@ -256,6 +397,8 @@ function Invoke-PodeValueUnsign { } function Test-PodeValueSigned { + [CmdletBinding()] + [OutputType([bool])] param( [Parameter(ValueFromPipeline = $true)] [string] @@ -289,6 +432,8 @@ function ConvertTo-PodeStrictSecret { } function New-PodeJwtSignature { + [CmdletBinding()] + [OutputType([string])] param( [Parameter(Mandatory = $true)] [string] @@ -342,6 +487,8 @@ function New-PodeJwtSignature { } function ConvertTo-PodeBase64UrlValue { + [CmdletBinding()] + [OutputType([string])] param( [Parameter(Mandatory = $true)] [string] @@ -363,6 +510,8 @@ function ConvertTo-PodeBase64UrlValue { } function ConvertFrom-PodeJwtBase64Value { + [CmdletBinding()] + [OutputType([string])] param( [Parameter(Mandatory = $true)] [string] diff --git a/src/Private/Endpoints.ps1 b/src/Private/Endpoints.ps1 index 0e0f6c3c7..307482bf3 100644 --- a/src/Private/Endpoints.ps1 +++ b/src/Private/Endpoints.ps1 @@ -1,4 +1,31 @@ -function Find-PodeEndpoints { +<# +.SYNOPSIS + Finds Pode endpoints based on protocol, address, or endpoint name. + +.DESCRIPTION + This function allows you to search for Pode endpoints based on different criteria. You can specify the protocol (HTTP or HTTPS), the address, or the endpoint name. It returns an array of hashtable objects representing the matching endpoints. + +.PARAMETER Protocol + The protocol of the endpoint (HTTP or HTTPS). + +.PARAMETER Address + The address of the endpoint. + +.PARAMETER EndpointName + The name of the endpoint. + +.OUTPUTS + An array of hashtables representing the matching endpoints, with the following keys: + - 'Protocol' + - 'Address' + - 'Name' + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Find-PodeEndpoint { + [CmdletBinding()] + [OutputType([hashtable[]])] param( [Parameter()] [ValidateSet('', 'Http', 'Https')] @@ -50,7 +77,33 @@ function Find-PodeEndpoints { return $endpoints } -function Get-PodeEndpoints { +<# +.SYNOPSIS + Retrieves internal endpoints based on the specified types. + +.DESCRIPTION + The `Get-PodeEndpointInternal` function returns internal endpoints from the PodeContext + based on the specified types (HTTP, WebSocket, SMTP, or TCP). + +.PARAMETER Type + Specifies the type of endpoints to retrieve. Valid values are 'Http', 'Ws', 'Smtp', and 'Tcp'. + This parameter is mandatory. + +.OUTPUTS + Returns an array of internal endpoints matching the specified types. + +.EXAMPLE + # Example usage: + $httpEndpoints = Get-PodeEndpointInternal -Type 'Http' + $wsEndpoints = Get-PodeEndpointInternal -Type 'Ws' + # Retrieve HTTP and WebSocket endpoints from the PodeContext. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Get-PodeEndpointInternal { + [CmdletBinding()] + [OutputType([object[]])] param( [Parameter(Mandatory = $true)] [ValidateSet('Http', 'Ws', 'Smtp', 'Tcp')] @@ -157,7 +210,25 @@ function Get-PodeEndpointRunspacePoolName { } } -function Test-PodeEndpoints { +<# +.SYNOPSIS +Tests whether Pode endpoints of a specified type exist. + +.DESCRIPTION +This function checks if there are any Pode endpoints of the specified type (HTTP, WebSocket, SMTP, or TCP). It returns a boolean value indicating whether endpoints of that type are available. + +.PARAMETER Type +The type of Pode endpoint to test (HTTP, WebSocket, SMTP, or TCP). + +.OUTPUTS +A boolean value (True if endpoints exist, False otherwise). + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Test-PodeEndpoint { + [CmdletBinding()] + [OutputType([bool])] param( [Parameter(Mandatory = $true)] [ValidateSet('Http', 'Ws', 'Smtp', 'Tcp')] @@ -165,7 +236,7 @@ function Test-PodeEndpoints { $Type ) - $endpoints = (Get-PodeEndpoints -Type $Type) + $endpoints = (Get-PodeEndpointInternal -Type $Type) return (($null -ne $endpoints) -and ($endpoints.Length -gt 0)) } diff --git a/src/Private/FileMonitor.ps1 b/src/Private/FileMonitor.ps1 index deee38e46..1415b567a 100644 --- a/src/Private/FileMonitor.ps1 +++ b/src/Private/FileMonitor.ps1 @@ -68,10 +68,10 @@ function Start-PodeFileMonitor { # if enabled, show the files that triggered the restart if ($Event.MessageData.FileSettings.ShowFiles) { if (!$Event.MessageData.Quiet) { - Write-Host 'The following files have changed:' -ForegroundColor Magenta + Write-PodeHost 'The following files have changed:' -ForegroundColor Magenta foreach ($file in $Event.MessageData.FileSettings.Files) { - Write-Host "> $($file)" -ForegroundColor Magenta + Write-PodeHost "> $($file)" -ForegroundColor Magenta } } diff --git a/src/Private/FileWatchers.ps1 b/src/Private/FileWatchers.ps1 index b768ef5a7..7c10fc32c 100644 --- a/src/Private/FileWatchers.ps1 +++ b/src/Private/FileWatchers.ps1 @@ -1,13 +1,19 @@ using namespace Pode function Test-PodeFileWatchersExist { + [CmdletBinding()] + [OutputType([bool])] + param() return (($null -ne $PodeContext.Fim) -and (($PodeContext.Fim.Enabled) -or ($PodeContext.Fim.Items.Count -gt 0))) } function New-PodeFileWatcher { + [CmdletBinding()] + [OutputType([PodeWatcher])] + param() $watcher = [PodeWatcher]::new($PodeContext.Tokens.Cancellation.Token) $watcher.ErrorLoggingEnabled = (Test-PodeErrorLoggingEnabled) - $watcher.ErrorLoggingLevels = @(Get-PodeErrorLoggingLevels) + $watcher.ErrorLoggingLevels = @(Get-PodeErrorLoggingLevel) return $watcher } @@ -103,6 +109,7 @@ function Start-PodeFileWatcherRunspace { $null = Invoke-PodeScriptBlock -ScriptBlock $fileWatcher.Script -Arguments $fileWatcher.Arguments -UsingVariables $fileWatcher.UsingVariables -Scoped -Splat } catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug } catch { $_ | Write-PodeErrorLog @@ -116,6 +123,7 @@ function Start-PodeFileWatcherRunspace { } } catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug } catch { $_ | Write-PodeErrorLog @@ -140,7 +148,9 @@ function Start-PodeFileWatcherRunspace { Start-Sleep -Seconds 1 } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index 99b936037..d8abdda43 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -1,6 +1,32 @@ using namespace Pode -# read in the content from a dynamic pode file and invoke its content +<# +.SYNOPSIS + Dynamically executes content as a Pode file, optionally passing data to it. + +.DESCRIPTION + This function takes a string of content, which is expected to be PowerShell code, and optionally a hashtable of data. It constructs a script block that optionally includes a parameter declaration, + and then executes this script block using the provided data. This is useful for dynamically generating content based on a template or script contained in a file or a string. + +.PARAMETER Content + The PowerShell code as a string. This content is dynamically executed as a script block. It can include placeholders or logic that utilizes the passed data. + +.PARAMETER Data + Optional hashtable of data that can be referenced within the content/script. This data is passed to the script block as parameters. + +.EXAMPLE + $scriptContent = '"Hello, world! Today is $(Get-Date)"' + ConvertFrom-PodeFile -Content $scriptContent + + This example will execute the content of the script and output "Hello, world! Today is [current date]". + +.EXAMPLE + $template = '"Hello, $(Name)! Your balance is $$(Amount)"' + $data = @{ Name = 'John Doe'; Amount = '100.50' } + ConvertFrom-PodeFile -Content $template -Data $data + + This example demonstrates using the function with a data parameter to replace placeholders within the content. +#> function ConvertFrom-PodeFile { param( [Parameter(Mandatory = $true)] @@ -611,50 +637,57 @@ function Add-PodeRunspace { } } -function Open-PodeRunspace { - param( - [Parameter(Mandatory = $true)] - [string] - $Type - ) +<# +.SYNOPSIS + Closes and disposes of the Pode runspaces, listeners, receivers, watchers, and optionally runspace pools. - try { - Import-PodeModules - Add-PodePSDrives - $PodeContext.RunspacePools[$Type].State = 'Ready' - } - catch { - if ($PodeContext.RunspacePools[$Type].State -ieq 'waiting') { - $PodeContext.RunspacePools[$Type].State = 'Error' - } +.DESCRIPTION + This function checks and waits for all Listeners, Receivers, and Watchers to be disposed of + before proceeding to close and dispose of the runspaces and optionally the runspace pools. + It ensures a clean shutdown by managing the disposal of resources in a specified order. + The function handles serverless and regular server environments differently, skipping + disposal actions in serverless contexts. - $_ | Out-Default - $_.ScriptStackTrace | Out-Default - throw - } -} +.PARAMETER ClosePool + Specifies whether to close and dispose of the runspace pools along with the runspaces. + This is optional and should be specified if the pools need to be explicitly closed. + +.EXAMPLE + Close-PodeRunspace -ClosePool + This example closes all runspaces and their associated pools, ensuring that all resources are properly disposed of. -function Close-PodeRunspaces { +.OUTPUTS + None + Outputs from this function are primarily internal state changes and verbose logging. + +.NOTES + It is recommended to use verbose logging to monitor the steps and understand the closing sequence during execution. +#> +function Close-PodeRunspace { param( [switch] $ClosePool ) + # Early return if server is serverless, as disposal is not required. if ($PodeContext.Server.IsServerless) { return } try { + # Only proceed if there are runspaces to dispose of. if (!(Test-PodeIsEmpty $PodeContext.Runspaces)) { Write-Verbose 'Waiting until all Listeners are disposed' $count = 0 $continue = $false + # Attempts to dispose of resources for up to 10 seconds. while ($count -le 10) { Start-Sleep -Seconds 1 $count++ $continue = $false + # Check each listener, receiver, and watcher; if any are not disposed, continue waiting. foreach ($listener in $PodeContext.Listeners) { if (!$listener.IsDisposed) { $continue = $true @@ -675,7 +708,7 @@ function Close-PodeRunspaces { break } } - + # If undisposed resources exist, continue waiting. if ($continue) { continue } @@ -726,10 +759,10 @@ function Close-PodeRunspaces { # close/dispose the runspace pools if ($ClosePool) { - Close-PodeRunspacePools + Close-PodeRunspacePool } - # check for runspace errors + # Check for and throw runspace errors if any occurred during disposal. if (($null -ne $runspaceErrors) -and ($runspaceErrors.Length -gt 0)) { foreach ($err in $runspaceErrors) { if ($null -eq $err) { @@ -820,7 +853,7 @@ function Close-PodeServerInternal { # stop all current runspaces Write-Verbose 'Closing runspaces' - Close-PodeRunspaces -ClosePool + Close-PodeRunspace -ClosePool # stop the file monitor if it's running Write-Verbose 'Stopping file monitor' @@ -843,7 +876,7 @@ function Close-PodeServerInternal { # remove all of the pode temp drives Write-Verbose 'Removing internal PSDrives' - Remove-PodePSDrives + Remove-PodePSDrive if ($ShowDoneMessage -and ($PodeContext.Server.Types.Length -gt 0) -and !$PodeContext.Server.IsServerless) { Write-PodeHost ' Done' -ForegroundColor Green @@ -928,13 +961,42 @@ function Test-PodePSDrive { return $true } -function Add-PodePSDrives { +<# +.SYNOPSIS + Adds Pode PS drives to the session. + +.DESCRIPTION + This function iterates through the keys of Pode drives stored in the `$PodeContext.Server.Drives` collection and creates corresponding PS drives using `New-PodePSDrive`. The drive paths are specified by the values associated with each key. + +.EXAMPLE + Add-PodePSDrivesInternal + # Creates Pode PS drives in the session based on the configured drive paths. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Add-PodePSDrivesInternal { foreach ($key in $PodeContext.Server.Drives.Keys) { $null = New-PodePSDrive -Path $PodeContext.Server.Drives[$key] -Name $key } } -function Import-PodeModules { +<# +.SYNOPSIS + Imports other Pode modules into the session. + +.DESCRIPTION + This function iterates through the paths of other Pode modules stored in the `$PodeContext.Server.Modules.Values` collection and imports them into the session. + It uses the `-DisableNameChecking` switch to suppress name checking during module import. + +.EXAMPLE + Import-PodeModulesInternal + # Imports other Pode modules into the session. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Import-PodeModulesInternal { # import other modules in the session foreach ($path in $PodeContext.Server.Modules.Values) { $null = Import-Module $path -DisableNameChecking -Scope Global -ErrorAction Stop @@ -958,9 +1020,7 @@ Add-PodePSInbuiltDrive This example is typically called within the Pode server setup script or internally by the Pode framework to initialize the PowerShell drives for the server's default folders. .NOTES -- The function is designed to be used within the Pode framework and relies on the global `$PodeContext` variable for configuration. -- It specifically checks for the existence of paths for views, public content, and errors before attempting to create drives for them. -- This is an internal function and may change in future releases of Pode. +This is an internal function and may change in future releases of Pode. #> function Add-PodePSInbuiltDrive { @@ -983,11 +1043,66 @@ function Add-PodePSInbuiltDrive { } } -function Remove-PodePSDrives { - $null = Get-PSDrive PodeDir* | Remove-PSDrive +<# +.SYNOPSIS + Removes Pode PS drives from the session. + +.DESCRIPTION + This function removes Pode PS drives from the session based on the specified drive name or pattern. + If no specific name or pattern is provided, it removes all Pode PS drives by default. + It uses `Get-PSDrive` to retrieve the drives and `Remove-PSDrive` to remove them. + +.PARAMETER Name + The name or pattern of the Pode PS drives to remove. Defaults to 'PodeDir*'. + +.EXAMPLE + Remove-PodePSDrive -Name 'myDir*' + # Removes all PS drives with names matching the pattern 'myDir*'. + +.EXAMPLE + Remove-PodePSDrive + # Removes all Pode PS drives. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Remove-PodePSDrive { + [CmdletBinding()] + param( + $Name = 'PodeDir*' + ) + $null = Get-PSDrive -Name $Name | Remove-PSDrive } +<# +.SYNOPSIS + Joins a folder and file path to the root path of the server. + +.DESCRIPTION + This function combines a folder path, file path (optional), and the root path of the server to create a complete path. If the root path is not explicitly provided, it uses the default root path from the Pode context. + +.PARAMETER Folder + The folder path to join. + +.PARAMETER FilePath + The file path (optional) to join. If not provided, only the folder path is used. + +.PARAMETER Root + The root path of the server. If not provided, the default root path from the Pode context is used. + +.OUTPUTS + Returns the combined path as a string. + +.EXAMPLE + Join-PodeServerRoot -Folder "uploads" -FilePath "document.txt" + # Output: "/uploads/document.txt" + + This example combines the folder path "uploads" and the file path "document.txt" with the default root path from the Pode context. + +#> function Join-PodeServerRoot { + [CmdletBinding()] + [OutputType([string])] param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] @@ -1012,7 +1127,30 @@ function Join-PodeServerRoot { return [System.IO.Path]::Combine($Root, $Folder, $FilePath) } +<# +.SYNOPSIS + Removes empty items (empty strings) from an array. + +.DESCRIPTION + This function filters out empty items (empty strings) from an array. It returns a new array containing only non-empty items. + +.PARAMETER Array + The array from which to remove empty items. + +.OUTPUTS + Returns an array containing non-empty items. + +.EXAMPLE + $myArray = "apple", "", "banana", "", "cherry" + $filteredArray = Remove-PodeEmptyItemsFromArray -Array $myArray + Write-Host "Filtered array: $filteredArray" + + This example removes empty items from the array and displays the filtered array. +#> function Remove-PodeEmptyItemsFromArray { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSPossibleIncorrectComparisonWithNull', '')] + [CmdletBinding()] + [OutputType([System.Object[]])] param( [Parameter(ValueFromPipeline = $true)] $Array @@ -1065,7 +1203,34 @@ function Remove-PodeNullKeysFromHashtable { } } +<# +.SYNOPSIS + Retrieves the file extension from a given path. + +.DESCRIPTION + This function extracts the file extension (including the period) from a specified path. Optionally, it can trim the period from the extension. + +.PARAMETER Path + The path from which to extract the file extension. + +.PARAMETER TrimPeriod + Switch parameter. If specified, trims the period from the file extension. + +.OUTPUTS + Returns the file extension (with or without the period) as a string. + +.EXAMPLE + Get-PodeFileExtension -Path "C:\MyFiles\document.txt" + # Output: ".txt" + + Get-PodeFileExtension -Path "C:\MyFiles\document.txt" -TrimPeriod + # Output: "txt" + + This example demonstrates how to retrieve the file extension with and without the period from a given path. +#> function Get-PodeFileExtension { + [CmdletBinding()] + [OutputType([string])] param( [Parameter()] [string] @@ -1075,7 +1240,10 @@ function Get-PodeFileExtension { $TrimPeriod ) + # Get the file extension $ext = [System.IO.Path]::GetExtension($Path) + + # Trim the period if requested if ($TrimPeriod) { $ext = $ext.Trim('.') } @@ -1083,7 +1251,39 @@ function Get-PodeFileExtension { return $ext } + +<# +.SYNOPSIS + Retrieves the file name from a given path. + +.DESCRIPTION + This function extracts the file name (including the extension) or the file name without the extension from a specified path. + +.PARAMETER Path + The path from which to extract the file name. + +.PARAMETER WithoutExtension + Switch parameter. If specified, returns the file name without the extension. + +.OUTPUTS + Returns the file name (with or without extension) as a string. + +.EXAMPLE + Get-PodeFileName -Path "C:\MyFiles\document.txt" + # Output: "document.txt" + + Get-PodeFileName -Path "C:\MyFiles\document.txt" -WithoutExtension + # Output: "document" + + This example demonstrates how to retrieve the file name with and without the extension from a given path. + +.NOTES + - If the path is a directory, the function returns the directory name. + - Use this function to extract file names for further processing or display. +#> function Get-PodeFileName { + [CmdletBinding()] + [OutputType([string])] param( [Parameter()] [string] @@ -1100,7 +1300,29 @@ function Get-PodeFileName { return [System.IO.Path]::GetFileName($Path) } +<# +.SYNOPSIS + Tests whether an exception message indicates a valid network failure. + +.DESCRIPTION + This function checks if an exception message contains specific phrases that commonly indicate network-related failures. It returns a boolean value indicating whether the exception message matches any of these network failure patterns. + +.PARAMETER Exception + The exception object whose message needs to be tested. + +.OUTPUTS + Returns $true if the exception message indicates a valid network failure, otherwise returns $false. + +.EXAMPLE + $exception = [System.Exception]::new("The network name is no longer available.") + $isNetworkFailure = Test-PodeValidNetworkFailure -Exception $exception + Write-Host "Is network failure: $isNetworkFailure" + + This example tests whether the exception message "The network name is no longer available." indicates a network failure. +#> function Test-PodeValidNetworkFailure { + [CmdletBinding()] + [OutputType([bool])] param( [Parameter()] $Exception @@ -1241,7 +1463,42 @@ function Get-PodeAcceptEncoding { return $found.Name } -function Get-PodeRanges { +<# +.SYNOPSIS + Parses a range string and converts it into a hashtable array of start and end values. + +.DESCRIPTION + This function takes a range string (typically used in HTTP headers) and extracts the relevant start and end values. It supports the 'bytes' unit and handles multiple ranges separated by commas. + +.PARAMETER Range + The range string to parse. + +.PARAMETER ThrowError + A switch parameter. If specified, the function throws an exception (HTTP status code 416) when encountering invalid range formats. + +.OUTPUTS + An array of hashtables, each containing 'Start' and 'End' properties representing the parsed ranges. + +.EXAMPLE + Get-PodeRange -Range 'bytes=100-200,300-400' + # Returns an array of hashtables: + # [ + # @{ + # Start = 100 + # End = 200 + # }, + # @{ + # Start = 300 + # End = 400 + # } + # ] + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Get-PodeRange { + [CmdletBinding()] + [OutputType([hashtable[]])] param( [Parameter()] [string] @@ -1643,7 +1900,27 @@ function ConvertFrom-PodeRequestContent { $Content = $null return $Result } +<# +.SYNOPSIS + Extracts the base MIME type from a Content-Type string that may include additional parameters. + +.DESCRIPTION + This function takes a Content-Type string as input and returns only the base MIME type by splitting the string at the semicolon (';') and trimming any excess whitespace. + It is useful for handling HTTP headers or other contexts where Content-Type strings include parameters like charset, boundary, etc. + +.PARAMETER ContentType + The Content-Type string from which to extract the base MIME type. This string can include additional parameters separated by semicolons. + +.EXAMPLE + Split-PodeContentType -ContentType "text/html; charset=UTF-8" + + This example returns 'text/html', stripping away the 'charset=UTF-8' parameter. + +.EXAMPLE + Split-PodeContentType -ContentType "application/json; charset=utf-8" + This example returns 'application/json', removing the charset parameter. +#> function Split-PodeContentType { param( [Parameter()] @@ -1651,10 +1928,13 @@ function Split-PodeContentType { $ContentType ) + # Check if the input string is null, empty, or consists only of whitespace. if ([string]::IsNullOrWhiteSpace($ContentType)) { - return [string]::Empty + return [string]::Empty # Return an empty string if the input is not valid. } + # Split the Content-Type string by the semicolon, which separates the base MIME type from other parameters. + # Trim any leading or trailing whitespace from the resulting MIME type to ensure clean output. return @($ContentType -isplit ';')[0].Trim() } @@ -1682,27 +1962,68 @@ function ConvertFrom-PodeNameValueToHashTable { return $ht } +<# +.SYNOPSIS + Gets the count of elements in the provided object or the length of a string. + +.DESCRIPTION + This function returns the count of elements in various types of objects including strings, collections, and arrays. + If the object is a string, it returns the length of the string. If the object is null or an empty collection, it returns 0. + This function is useful for determining the size or length of data containers in PowerShell scripts. + +.PARAMETER Object + The object from which the count or length will be determined. This can be a string, array, collection, or any other object that has a Count property. + +.OUTPUTS + [int] + Returns an integer representing the count of elements or length of the string. + +.EXAMPLE + $array = @(1, 2, 3) + Get-PodeCount -Object $array + + This example returns 3, as there are three elements in the array. + +.EXAMPLE + $string = "hello" + Get-PodeCount -Object $string + + This example returns 5, as there are five characters in the string. + +.EXAMPLE + $nullObject = $null + Get-PodeCount -Object $nullObject + + This example returns 0, as the object is null. +#> function Get-PodeCount { + [CmdletBinding()] + [OutputType([int])] param( [Parameter()] - $Object + $Object # The object to be evaluated for its count. ) + # Check if the object is null. if ($null -eq $Object) { - return 0 + return 0 # Return 0 if the object is null. } + # Check if the object is a string and return its length. if ($Object -is [string]) { return $Object.Length } + # Check if the object is a NameValueCollection and is empty. if ($Object -is [System.Collections.Specialized.NameValueCollection] -and $Object.Count -eq 0) { - return 0 + return 0 # Return 0 if the collection is empty. } + # For other types of collections, return their Count property. return $Object.Count } + <# .SYNOPSIS Tests if a given file system path is valid and optionally if it is not a directory. @@ -1741,7 +2062,6 @@ function Get-PodeCount { This function is used within the Pode framework to validate file system paths for serving static content. #> - function Test-PodePath { param( [Parameter()] @@ -1853,18 +2173,7 @@ function Test-PodePathIsDirectory { return ([string]::IsNullOrWhiteSpace([System.IO.Path]::GetExtension($Path))) } -function Convert-PodePathSeparators { - param( - [Parameter()] - $Paths - ) - return @($Paths | ForEach-Object { - if (![string]::IsNullOrWhiteSpace($_)) { - $_ -ireplace '[\\/]', [System.IO.Path]::DirectorySeparatorChar - } - }) -} function Convert-PodePathPatternToRegex { param( @@ -1932,57 +2241,144 @@ function Convert-PodePathPatternsToRegex { return "^$($joined)$" } -function Get-PodeDefaultSslProtocols { +<# +.SYNOPSIS + Gets the default SSL protocol(s) based on the operating system. + +.DESCRIPTION + This function determines the appropriate default SSL protocol(s) based on the operating system. On macOS, it returns TLS 1.2. On other platforms, it combines SSL 3.0 and TLS 1.2. + +.OUTPUTS + A [System.Security.Authentication.SslProtocols] enum value representing the default SSL protocol(s). + +.EXAMPLE + Get-PodeDefaultSslProtocol + # Returns [System.Security.Authentication.SslProtocols]::Ssl3, [System.Security.Authentication.SslProtocols]::Tls12 (on non-macOS systems) + # Returns [System.Security.Authentication.SslProtocols]::Tls12 (on macOS) + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Get-PodeDefaultSslProtocol { + [CmdletBinding()] + [OutputType([System.Security.Authentication.SslProtocols])] + param() if (Test-PodeIsMacOS) { - return (ConvertTo-PodeSslProtocols -Protocols Tls12) + return (ConvertTo-PodeSslProtocol -Protocol Tls12) } - return (ConvertTo-PodeSslProtocols -Protocols Ssl3, Tls12) + return (ConvertTo-PodeSslProtocol -Protocol Ssl3, Tls12) } -function ConvertTo-PodeSslProtocols { +<# +.SYNOPSIS + Converts a string representation of SSL protocols to the corresponding SslProtocols enum value. + +.DESCRIPTION + This function takes an array of SSL protocol strings (such as 'Tls', 'Tls12', etc.) and combines them into a single SslProtocols enum value. It's useful for configuring SSL/TLS settings in Pode or other PowerShell scripts. + +.PARAMETER Protocol + An array of SSL protocol strings. Valid values are 'Ssl2', 'Ssl3', 'Tls', 'Tls11', 'Tls12', and 'Tls13'. + +.OUTPUTS + A [System.Security.Authentication.SslProtocols] enum value representing the combined protocols. + +.EXAMPLE + ConvertTo-PodeSslProtocol -Protocol 'Tls', 'Tls12' + # Returns [System.Security.Authentication.SslProtocols]::Tls12 + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function ConvertTo-PodeSslProtocol { + [CmdletBinding()] + [OutputType([System.Security.Authentication.SslProtocols])] param( [Parameter()] [ValidateSet('Ssl2', 'Ssl3', 'Tls', 'Tls11', 'Tls12', 'Tls13')] [string[]] - $Protocols + $Protocol ) $protos = 0 - foreach ($protocol in $Protocols) { - $protos = [int]($protos -bor [System.Security.Authentication.SslProtocols]::$protocol) + foreach ($item in $Protocol) { + $protos = [int]($protos -bor [System.Security.Authentication.SslProtocols]::$item) } return [System.Security.Authentication.SslProtocols]($protos) } -function Get-PodeModuleDetails { +<# +.SYNOPSIS + Retrieves details about the Pode module. + +.DESCRIPTION + This function determines the relevant details of the Pode module. It first checks if the module is already imported. + If so, it uses that module. Otherwise, it attempts to identify the module used for the 'engine' and retrieves its details. + If there are multiple versions of the module, it selects the newest version. If no module is imported, it uses the latest installed version. + +.OUTPUTS + A hashtable containing the module details. + +.EXAMPLE + Get-PodeModuleInfo + # Returns a hashtable with module details such as name, path, base path, data path, internal path, and whether it's in the system path. + + .NOTES + This is an internal function and may change in future releases of Pode. +#> +function Get-PodeModuleInfo { + [CmdletBinding()] + [OutputType([hashtable])] + param() # if there's 1 module imported already, use that $importedModule = @(Get-Module -Name Pode) if (($importedModule | Measure-Object).Count -eq 1) { - return (Convert-PodeModuleDetails -Module @($importedModule)[0]) + return (Convert-PodeModuleInfo -Module @($importedModule)[0]) } # if there's none or more, attempt to get the module used for 'engine' try { $usedModule = (Get-Command -Name 'Set-PodeViewEngine').Module if (($usedModule | Measure-Object).Count -eq 1) { - return (Convert-PodeModuleDetails -Module $usedModule) + return (Convert-PodeModuleInfo -Module $usedModule) } } catch { + $_ | Write-PodeErrorLog -Level Debug } # if there were multiple to begin with, use the newest version if (($importedModule | Measure-Object).Count -gt 1) { - return (Convert-PodeModuleDetails -Module @($importedModule | Sort-Object -Property Version)[-1]) + return (Convert-PodeModuleInfo -Module @($importedModule | Sort-Object -Property Version)[-1]) } # otherwise there were none, use the latest installed - return (Convert-PodeModuleDetails -Module @(Get-Module -ListAvailable -Name Pode | Sort-Object -Property Version)[-1]) + return (Convert-PodeModuleInfo -Module @(Get-Module -ListAvailable -Name Pode | Sort-Object -Property Version)[-1]) } -function Convert-PodeModuleDetails { +<# +.SYNOPSIS + Converts Pode module details to a hashtable. + +.DESCRIPTION + This function takes a Pode module and extracts relevant details such as name, path, base path, data path, internal path, and whether it's in the system path. + +.PARAMETER Module + The Pode module to convert. + +.OUTPUTS + A hashtable containing the module details. + +.EXAMPLE + Convert-PodeModuleInfo -Module (Get-Module Pode) + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Convert-PodeModuleInfo { + [CmdletBinding()] + [OutputType([hashtable])] param( [Parameter(Mandatory = $true)] [psmoduleinfo] @@ -2002,45 +2398,96 @@ function Convert-PodeModuleDetails { return $details } +<# +.SYNOPSIS + Checks if a PowerShell module is located within the directories specified in the PSModulePath environment variable. + +.DESCRIPTION + This function determines if the path of a provided PowerShell module starts with any path included in the system's PSModulePath environment variable. + This is used to ensure that the module is being loaded from expected locations, which can be important for security and configuration verification. + +.PARAMETER Module + The module to be checked. This should be a module info object, typically obtained via Get-Module or Import-Module. + +.OUTPUTS + [bool] + Returns $true if the module's path is under a path listed in PSModulePath, otherwise returns $false. + +.EXAMPLE + $module = Get-Module -Name Pode + Test-PodeModuleInPath -Module $module + + This example checks if the 'Pode' module is located within the paths specified by the PSModulePath environment variable. +#> function Test-PodeModuleInPath { + [CmdletBinding()] + [OutputType([bool])] param( [Parameter(Mandatory = $true)] [psmoduleinfo] $Module ) - $separator = ';' - if (Test-PodeIsUnix) { - $separator = ':' - } + # Determine the path separator based on the operating system. + $separator = if (Test-PodeIsUnix) { ':' } else { ';' } + # Split the PSModulePath environment variable to get individual paths. $paths = @($env:PSModulePath -split $separator) + # Check each path to see if the module's path starts with it. foreach ($path in $paths) { + # Return true if the module is in one of the paths. if ($Module.Path.StartsWith($path)) { return $true } } + # Return false if no matching path is found. return $false } +<# +.SYNOPSIS + Retrieves a module and all of its recursive dependencies. + +.DESCRIPTION + This function takes a PowerShell module as input and returns an array containing + the module and all of its required dependencies, retrieved recursively. This is + useful for understanding the full set of dependencies a module has. + +.PARAMETER Module + The module for which to retrieve dependencies. This must be a valid PowerShell module object. -function Get-PodeModuleDependencies { +.EXAMPLE + $module = Get-Module -Name SomeModuleName + $dependencies = Get-PodeModuleDependency -Module $module + This example retrieves all dependencies for "SomeModuleName". + +.OUTPUTS + Array[psmoduleinfo] + Returns an array of psmoduleinfo objects, each representing a module in the dependency tree. +#> + +function Get-PodeModuleDependency { param( [Parameter(Mandatory = $true)] [psmoduleinfo] $Module ) + # Check if the module has any required modules (dependencies). if (!$Module.RequiredModules) { - return $Module + return $Module # } - + # Initialize an array to hold all dependencies. $mods = @() + + # Iterate through each required module and recursively retrieve their dependencies. foreach ($mod in $Module.RequiredModules) { - $mods += (Get-PodeModuleDependencies -Module $mod) + # Recursive call for each dependency. + $mods += (Get-PodeModuleDependency -Module $mod) } + # Return the list of all dependencies plus the original module. return ($mods + $module) } @@ -2337,7 +2784,37 @@ function Get-PodeRelativePath { return $Path } -function Get-PodeWildcardFiles { +<# +.SYNOPSIS + Retrieves files based on a wildcard pattern in a given path. + +.DESCRIPTION + The `Get-PodeWildcardFile` function returns files from the specified path based on a wildcard pattern. + You can customize the wildcard and provide an optional root path for relative paths. + +.PARAMETER Path + Specifies the path to search for files. This parameter is mandatory. + +.PARAMETER Wildcard + Specifies the wildcard pattern for file matching. Default is '*.*'. + +.PARAMETER RootPath + Specifies an optional root path for relative paths. If provided, the function will join the root path with the specified path. + +.OUTPUTS + Returns an array of file paths matching the wildcard pattern. + +.EXAMPLE + # Example usage: + $files = Get-PodeWildcardFile -Path '/path/to/files' -Wildcard '*.txt' + # Returns an array of .txt files in the specified path. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Get-PodeWildcardFile { + [CmdletBinding()] + [OutputType([object[]])] param( [Parameter(Mandatory = $true)] [string] @@ -2544,54 +3021,6 @@ function Convert-PodeQueryStringToHashTable { return (ConvertFrom-PodeNameValueToHashTable -Collection $tmpQuery) } -function Get-PodeDotSourcedFiles { - param( - [Parameter(Mandatory = $true)] - [System.Management.Automation.Language.Ast] - $Ast, - - [Parameter()] - [string] - $RootPath - ) - - # set default root path - if ([string]::IsNullOrWhiteSpace($RootPath)) { - $RootPath = $PodeContext.Server.Root - } - - # get all dot-sourced files - $cmdTypes = @('dot', 'ampersand') - $files = ($Ast.FindAll({ - ($args[0] -is [System.Management.Automation.Language.CommandAst]) -and - ($args[0].InvocationOperator -iin $cmdTypes) -and - ($args[0].CommandElements.StaticType.Name -ieq 'string') - }, $false)).CommandElements.Value - - $fileOrder = @() - - # no files found - if (($null -eq $files) -or ($files.Length -eq 0)) { - return $fileOrder - } - - # get any sub sourced files - foreach ($file in $files) { - $file = Get-PodeRelativePath -Path $file -RootPath $RootPath -JoinRoot - $fileOrder += $file - - $ast = Get-PodeAstFromFile -FilePath $file - - $result = Get-PodeDotSourcedFiles -Ast $ast -RootPath (Split-Path -Parent -Path $file) - if (($null -ne $result) -and ($result.Length -gt 0)) { - $fileOrder += $result - } - } - - # return all found files - return $fileOrder -} - function Get-PodeAstFromFile { param( [Parameter(Mandatory = $true)] @@ -2681,7 +3110,34 @@ function Get-PodeFunctionsFromScriptBlock { return $foundFuncs } -function Read-PodeWebExceptionDetails { +<# +.SYNOPSIS + Reads details from a web exception and returns relevant information. + +.DESCRIPTION + The `Read-PodeWebExceptionDetail` function processes a web exception (either `WebException` or `HttpRequestException`) + and extracts relevant details such as status code, status description, and response body. + +.PARAMETER ErrorRecord + Specifies the error record containing the web exception. This parameter is mandatory. + +.OUTPUTS + Returns a hashtable with the following keys: + - `Status`: A nested hashtable with `Code` (status code) and `Description` (status description). + - `Body`: The response body from the web exception. + +.EXAMPLE + # Example usage: + $errorRecord = Get-ErrorRecordFromWebException + $details = Read-PodeWebExceptionDetail -ErrorRecord $errorRecord + # Returns a hashtable with status code, description, and response body. + +.NOTES + This is an internal function and may change in future releases of Pode +#> +function Read-PodeWebExceptionDetail { + [CmdletBinding()] + [OutputType([hashtable])] param( [Parameter(Mandatory = $true)] [System.Management.Automation.ErrorRecord] @@ -2803,7 +3259,28 @@ function Find-PodeModuleFile { return $path } -function Clear-PodeHashtableInnerKeys { +<# +.SYNOPSIS + Clears the inner keys of a hashtable. + +.DESCRIPTION + This function takes a hashtable as input and clears the values associated with each inner key. If the input hashtable is empty or null, no action is taken. + +.PARAMETER InputObject + The hashtable to process. + +.EXAMPLE + $myHashtable = @{ + 'Key1' = 'Value1' + 'Key2' = 'Value2' + } + Clear-PodeHashtableInnerKey -InputObject $myHashtable + # Clears the values associated with 'Key1' and 'Key2' in the hashtable. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Clear-PodeHashtableInnerKey { param( [Parameter(ValueFromPipeline = $true)] [hashtable] @@ -2868,7 +3345,45 @@ function Get-PodePlaceholderRegex { return '\:(?[\w]+)' } -function Resolve-PodePlaceholders { +<# +.SYNOPSIS + Resolves placeholders in a given path using a specified regex pattern. + +.DESCRIPTION + The `Resolve-PodePlaceholder` function replaces placeholders in the provided path + with custom placeholders based on the specified regex pattern. You can customize + the prepend and append strings for the new placeholders. Additionally, you can + choose to escape slashes in the path. + +.PARAMETER Path + Specifies the path to resolve. This parameter is mandatory. + +.PARAMETER Pattern + Specifies the regex pattern for identifying placeholders. If not provided, the default + placeholder regex pattern from `Get-PodePlaceholderRegex` is used. + +.PARAMETER Prepend + Specifies the string to prepend to the new placeholders. Default is '(?<'. + +.PARAMETER Append + Specifies the string to append to the new placeholders. Default is '>[^\/]+?)'. + +.PARAMETER Slashes + If specified, escapes slashes in the path. + +.OUTPUTS + Returns the resolved path with replaced placeholders. + +.EXAMPLE + # Example usage: + $originalPath = '/api/users/{id}' + $resolvedPath = Resolve-PodePlaceholder -Path $originalPath + # Returns '/api/users/(?[^\/]+?)' with custom placeholders. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Resolve-PodePlaceholder { param( [Parameter(Mandatory = $true)] [string] @@ -2903,10 +3418,46 @@ function Resolve-PodePlaceholders { $Path = "$($Path)[\\\/]" } - return (Convert-PodePlaceholders -Path $Path -Pattern $Pattern -Prepend $Prepend -Append $Append) + return (Convert-PodePlaceholder -Path $Path -Pattern $Pattern -Prepend $Prepend -Append $Append) } -function Convert-PodePlaceholders { +<# +.SYNOPSIS + Converts placeholders in a given path using a specified regex pattern. + +.DESCRIPTION + The `Convert-PodePlaceholder` function replaces placeholders in the provided path + with custom placeholders based on the specified regex pattern. You can customize + the prepend and append strings for the new placeholders. + +.PARAMETER Path + Specifies the path to convert. This parameter is mandatory. + +.PARAMETER Pattern + Specifies the regex pattern for identifying placeholders. If not provided, the default + placeholder regex pattern from `Get-PodePlaceholderRegex` is used. + +.PARAMETER Prepend + Specifies the string to prepend to the new placeholders. Default is '(?<'. + +.PARAMETER Append + Specifies the string to append to the new placeholders. Default is '>[^\/]+?)'. + +.OUTPUTS + Returns the path with replaced placeholders. + +.EXAMPLE + # Example usage: + $originalPath = '/api/users/{id}' + $convertedPath = Convert-PodePlaceholder -Path $originalPath + # Returns '/api/users/(?[^\/]+?)' with custom placeholders. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Convert-PodePlaceholder { + [CmdletBinding()] + [OutputType([string])] param( [Parameter(Mandatory = $true)] [string] @@ -2936,7 +3487,33 @@ function Convert-PodePlaceholders { return $Path } -function Test-PodePlaceholders { +<# +.SYNOPSIS + Tests whether a given path contains a placeholder based on a specified regex pattern. + +.DESCRIPTION + The `Test-PodePlaceholder` function checks if the provided path contains a placeholder + by matching it against a regex pattern. Placeholders are typically used for dynamic values. + +.PARAMETER Path + Specifies the path to test. This parameter is mandatory. + +.PARAMETER Placeholder + Specifies the regex pattern for identifying placeholders. If not provided, the default + placeholder regex pattern from `Get-PodePlaceholderRegex` is used. + +.OUTPUTS + Returns `$true` if the path contains a placeholder; otherwise, returns `$false`. + +.EXAMPLE + # Example usage: + $isPlaceholder = Test-PodePlaceholder -Path '/api/users/{id}' + # Returns $true because the path contains a placeholder. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Test-PodePlaceholder { param( [Parameter(Mandatory = $true)] [string] @@ -2979,41 +3556,6 @@ function Get-PodeModuleManifest { return $moduleManifest } - -<# -.SYNOPSIS -Tests if the Pode module is from the development branch. - -.DESCRIPTION -The Test-PodeVersionDev function checks if the Pode module's version matches the placeholder value ('$version$'), which is used to indicate the development branch of the module. It returns $true if the version matches, indicating the module is from the development branch, and $false otherwise. - -.PARAMETER None -This function does not accept any parameters. - -.OUTPUTS -System.Boolean -Returns $true if the Pode module version is '$version$', indicating the development branch. Returns $false for any other version. - -.EXAMPLE -PS> $moduleManifest = @{ ModuleVersion = '$version$' } -PS> Test-PodeVersionDev - -Returns $true, indicating the development branch. - -.EXAMPLE -PS> $moduleManifest = @{ ModuleVersion = '1.2.3' } -PS> Test-PodeVersionDev - -Returns $false, indicating a specific release version. - -.NOTES -This function assumes that $moduleManifest is a hashtable representing the loaded module manifest, with a key of ModuleVersion. - -#> -function Test-PodeVersionDev { - return (Get-PodeModuleManifest).ModuleVersion -eq '$version$' -} - <# .SYNOPSIS Tests the running PowerShell version for compatibility with Pode, identifying end-of-life (EOL) and untested versions. @@ -3080,14 +3622,19 @@ function Test-PodeVersionPwshEOL { <# .SYNOPSIS creates a YAML description of the data in the object - based on https://github.com/Phil-Factor/PSYaml + .DESCRIPTION This produces YAML from any object you pass to it. It isn't suitable for the huge objects produced by some of the cmdlets such as Get-Process, but fine for simple objects + .PARAMETER Object the object that you want scripted out + .PARAMETER Depth The depth that you want your object scripted to + .EXAMPLE Get-PodeOpenApiDefinition|ConvertTo-PodeYaml + #> function ConvertTo-PodeYaml { [CmdletBinding()] @@ -3148,7 +3695,6 @@ function ConvertTo-PodeYaml { It converts only basic PowerShell types, such as strings, integers, booleans, arrays, hashtables, and ordered dictionaries into a YAML format. #> - function ConvertTo-PodeYamlInternal { [CmdletBinding()] [OutputType([string])] diff --git a/src/Private/Logging.ps1 b/src/Private/Logging.ps1 index ad67d42ad..21ad5b56c 100644 --- a/src/Private/Logging.ps1 +++ b/src/Private/Logging.ps1 @@ -104,6 +104,7 @@ function Get-PodeLoggingEventViewerMethod { $entryLog.WriteEvent($entryInstance, $message) } catch { + $_ | Write-PodeErrorLog -Level Debug } } } @@ -207,7 +208,25 @@ function Get-PodeErrorLoggingName { return '__pode_log_errors__' } +<# +.SYNOPSIS + Retrieves a Pode logger by name. + +.DESCRIPTION + This function allows you to retrieve a Pode logger by specifying its name. It returns the logger object associated with the given name. + +.PARAMETER Name + The name of the Pode logger to retrieve. + +.OUTPUTS + A Pode logger object. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> function Get-PodeLogger { + [CmdletBinding()] + [OutputType([hashtable])] param( [Parameter(Mandatory = $true)] [string] @@ -227,7 +246,23 @@ function Test-PodeLoggerEnabled { return ($PodeContext.Server.Logging.Enabled -and $PodeContext.Server.Logging.Types.ContainsKey($Name)) } -function Get-PodeErrorLoggingLevels { +<# +.SYNOPSIS + Gets the error logging levels for Pode. + +.DESCRIPTION + This function retrieves the error logging levels configured for Pode. It returns an array of available error levels. + +.PARAMETER Name + The name of the Pode logger to retrieve. + +.OUTPUTS + An array of error logging levels. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Get-PodeErrorLoggingLevel { return (Get-PodeLogger -Name (Get-PodeErrorLoggingName)).Arguments.Levels } @@ -343,7 +378,7 @@ function Start-PodeLoggingRunspace { while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { # if there are no logs to process, just sleep for a few seconds - but after checking the batch if ($PodeContext.LogsToProcess.Count -eq 0) { - Test-PodeLoggerBatches + Test-PodeLoggerBatch Start-Sleep -Seconds 5 continue } @@ -406,13 +441,25 @@ function Start-PodeLoggingRunspace { Add-PodeRunspace -Type Main -ScriptBlock $script } -function Test-PodeLoggerBatches { +<# +.SYNOPSIS + Tests whether Pode logger batches need to be written. + +.DESCRIPTION + This function checks each Pode logger and determines if its batch needs to be written. It evaluates the batch size, timeout, and last update timestamp to decide whether to process the batch and write the log entries. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Test-PodeLoggerBatch { $now = [datetime]::Now # check each logger, and see if its batch needs to be written foreach ($logger in $PodeContext.Server.Logging.Types.Values) { $batch = $logger.Method.Batch - if (($batch.Size -gt 1) -and ($batch.Items.Length -gt 0) -and ($batch.Timeout -gt 0) -and ($null -ne $batch.LastUpdate) -and ($batch.LastUpdate.AddSeconds($batch.Timeout) -le $now)) { + if (($batch.Size -gt 1) -and ($batch.Items.Length -gt 0) -and ($batch.Timeout -gt 0) ` + -and ($null -ne $batch.LastUpdate) -and ($batch.LastUpdate.AddSeconds($batch.Timeout) -le $now) + ) { $result = $batch.Items $rawItems = $batch.RawItems diff --git a/src/Private/Metrics.ps1 b/src/Private/Metrics.ps1 index d510ddd29..3b004d3b5 100644 --- a/src/Private/Metrics.ps1 +++ b/src/Private/Metrics.ps1 @@ -1,4 +1,40 @@ -function Update-PodeServerRequestMetrics { +<# +.SYNOPSIS + Updates server request metrics based on the provided web event. + +.DESCRIPTION + The `Update-PodeServerRequestMetric` function increments relevant metrics associated with server requests. + It takes a web event (represented as a hashtable) and updates the appropriate metrics. + +.PARAMETER WebEvent + Specifies the web event to process. This parameter is optional. + +.INPUTS + None. You cannot pipe objects to Update-PodeServerRequestMetric. + +.OUTPUTS + None. The function modifies the state of metrics in the PodeContext. + +.EXAMPLE + # Example usage: + $webEvent = @{ + Response = @{ + StatusCode = 200 + } + Route = @{ + Metrics = @{ + Requests = $routeMetrics + } + } + } + + Update-PodeServerRequestMetric -WebEvent $webEvent + # Metrics associated with the web event are updated. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Update-PodeServerRequestMetric { param( [Parameter()] [hashtable] @@ -9,16 +45,16 @@ function Update-PodeServerRequestMetrics { return } - # status code + # Extract the status code from the web event $status = "$($WebEvent.Response.StatusCode)" - # metrics to update + # Determine which metrics to update $metrics = @($PodeContext.Metrics.Requests) if ($null -ne $WebEvent.Route) { $metrics += $WebEvent.Route.Metrics.Requests } - # increment the request metrics + # Increment the request metrics and status code counts foreach ($metric in $metrics) { Lock-PodeObject -Object $metric -ScriptBlock { $metric.Total++ @@ -32,7 +68,40 @@ function Update-PodeServerRequestMetrics { } } -function Update-PodeServerSignalMetrics { +<# +.SYNOPSIS + Updates server signal metrics based on the provided signal event. + +.DESCRIPTION + The `Update-PodeServerSignalMetric` function increments relevant metrics associated with server signals. + It takes a signal event (represented as a hashtable) and updates the appropriate metrics. + +.PARAMETER SignalEvent + Specifies the signal event to process. This parameter is optional. + +.INPUTS + None. You cannot pipe objects to Update-PodeServerSignalMetric. + +.OUTPUTS + None. The function modifies the state of metrics in the PodeContext. + +.EXAMPLE + # Example usage: + $signalEvent = @{ + Route = @{ + Metrics = @{ + Requests = $routeMetrics + } + } + } + + Update-PodeServerSignalMetric -SignalEvent $signalEvent + # Metrics associated with the signal event are updated. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Update-PodeServerSignalMetric { param( [Parameter()] [hashtable] @@ -43,7 +112,7 @@ function Update-PodeServerSignalMetrics { return } - # metrics to update + # Determine which metrics to update $metrics = @($PodeContext.Metrics.Signals) if ($null -ne $SignalEvent.Route) { $metrics += $SignalEvent.Route.Metrics.Requests diff --git a/src/Private/Middleware.ps1 b/src/Private/Middleware.ps1 index 4f5d74599..ac72b5716 100644 --- a/src/Private/Middleware.ps1 +++ b/src/Private/Middleware.ps1 @@ -58,6 +58,7 @@ function Invoke-PodeMiddleware { } function New-PodeMiddlewareInternal { + [CmdletBinding()] [OutputType([hashtable])] param( [Parameter(Mandatory = $true)] diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index c0c14be1b..67fd8a4b4 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -350,7 +350,32 @@ function ConvertTo-PodeOAOfProperty { return $schema } +<# +.SYNOPSIS + Converts a hashtable representing a property into a schema property format compliant with the OpenAPI Specification (OAS). + +.DESCRIPTION + This function takes a hashtable input representing a property and converts it into a schema property format based on the OpenAPI Specification. + It handles various property types including primitives, arrays, and complex types with allOf, oneOf, anyOf constructs. + +.PARAMETER Property + A hashtable containing property details that need to be converted to an OAS schema property. + +.PARAMETER NoDescription + A switch parameter. If set, the description of the property will not be included in the output schema. + +.PARAMETER DefinitionTag + A mandatory string parameter specifying the definition context used for schema validation and compatibility checks with OpenAPI versions. + +.EXAMPLE + $propertyDetails = @{ + type = 'string'; + description = 'A sample property'; + } + ConvertTo-PodeOASchemaProperty -Property $propertyDetails -DefinitionTag 'v1' + This example will convert a simple string property into an OpenAPI schema property. +#> function ConvertTo-PodeOASchemaProperty { param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] @@ -926,9 +951,6 @@ function Get-PodeOpenApiDefinitionInternal { # auth/security components if ($PodeContext.Server.Authentications.Methods.Count -gt 0) { - #if ($null -eq $def.components.securitySchemes) { - # $def.components.securitySchemes = @{} - # } $authNames = (Expand-PodeAuthMerge -Names $PodeContext.Server.Authentications.Methods.Keys) foreach ($authName in $authNames) { @@ -1116,6 +1138,16 @@ function Get-PodeOpenApiDefinitionInternal { return $def } +<# +.SYNOPSIS + Converts a Cmdlet parameter into an OpenAPI-compliant property definition based on its type. + +.DESCRIPTION + This function analyzes the metadata of a Cmdlet parameter and generates an OpenAPI schema property. It supports Boolean, Integer, Number, and defaults to String type properties. + +.PARAMETER Parameter + The metadata of the Cmdlet parameter that is being converted to an OpenAPI property. +#> function ConvertTo-PodeOAPropertyFromCmdletParameter { param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] @@ -1411,6 +1443,36 @@ function Set-PodeOAGlobalAuth { } } +<# +.SYNOPSIS + Resolves references in an OpenAPI schema component based on definitions within a specified definition tag context. + +.DESCRIPTION + This function navigates through a schema's properties and resolves `$ref` references to actual schemas defined within the specified definition context. + It handles complex constructs such as 'allOf', 'oneOf', and 'anyOf', merging properties and ensuring the schema is fully resolved without unresolved references. + +.PARAMETER ComponentSchema + A hashtable representing the schema of a component where references need to be resolved. + +.PARAMETER DefinitionTag + A string identifier for the specific set of schema definitions under which references should be resolved. + +.EXAMPLE + $schema = @{ + type = 'object'; + properties = @{ + name = @{ + type = 'string' + }; + details = @{ + '$ref' = '#/components/schemas/UserDetails' + } + }; + } + Resolve-PodeOAReference -ComponentSchema $schema -DefinitionTag 'v1' + + This example demonstrates resolving a reference to 'UserDetails' within a given component schema. +#> function Resolve-PodeOAReference { param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] @@ -1423,11 +1485,13 @@ function Resolve-PodeOAReference { ) begin { + # Initialize schema storage and a list to track keys that need resolution $Schemas = $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.schemaJson $Keys = @() } process { + # Gather all keys from properties and directly from the schema that might have references if ($ComponentSchema.properties) { foreach ($item in $ComponentSchema.properties.Keys) { $Keys += $item @@ -1439,49 +1503,59 @@ function Resolve-PodeOAReference { } } + # Process each key to resolve references or merge schema definitions foreach ($key in $Keys) { if ( @('allof', 'oneof', 'anyof') -icontains $key ) { - if ($key -ieq 'allof') { - $tmpProp = @() - foreach ( $comp in $ComponentSchema[$key] ) { - if ($comp.'$ref') { - if (($comp.'$ref').StartsWith('#/components/schemas/')) { - $refName = ($comp.'$ref') -replace '#/components/schemas/', '' - if ($Schemas.ContainsKey($refName)) { - $tmpProp += $Schemas[$refName].schema + # Handle complex schema constructs like allOf, oneOf, and anyOf + switch ($key.ToLower()) { + 'allof' { + $tmpProp = @() + foreach ( $comp in $ComponentSchema[$key] ) { + if ($comp.'$ref') { + # Resolve $ref to a schema if it starts with the expected path + if (($comp.'$ref').StartsWith('#/components/schemas/')) { + $refName = ($comp.'$ref') -replace '#/components/schemas/', '' + if ($Schemas.ContainsKey($refName)) { + $tmpProp += $Schemas[$refName].schema + } } } - } - elseif ( $comp.properties) { - if ($comp.type -eq 'object') { - $tmpProp += Resolve-PodeOAReference -DefinitionTag $DefinitionTag -ComponentSchema$comp + elseif ( $comp.properties) { + # Recursively resolve nested schemas + if ($comp.type -eq 'object') { + $tmpProp += Resolve-PodeOAReference -DefinitionTag $DefinitionTag -ComponentSchema$comp + } + else { + throw 'Unsupported object' + } } - else { - throw 'Unsupported object' + } + # Update the main schema to be an object and add resolved properties + $ComponentSchema.type = 'object' + $ComponentSchema.remove('allOf') + if ($tmpProp.count -gt 0) { + foreach ($t in $tmpProp) { + $ComponentSchema.properties += $t.properties } } - } - $ComponentSchema.type = 'object' - $ComponentSchema.remove('allOf') - if ($tmpProp.count -gt 0) { - foreach ($t in $tmpProp) { - $ComponentSchema.properties += $t.properties - } } - - } - elseif ($key -ieq 'oneof') { - throw 'Validation of schema with oneof is not supported' - } - elseif ($key -ieq 'anyof') { - throw 'Validation of schema with anyof is not supported' + 'oneof' { + # Throw an error for unsupported schema constructs to notify the user + throw "Validation of schema with `$key is not supported" + } + 'anyof' { + # Throw an error for unsupported schema constructs to notify the user + throw "Validation of schema with `$key is not supported" + } } } elseif ($ComponentSchema.properties[$key].type -eq 'object') { + # Recursively resolve object-type properties $ComponentSchema.properties[$key].properties = Resolve-PodeOAReference -DefinitionTag $DefinitionTag -ComponentSchema $ComponentSchema.properties[$key].properties } elseif ($ComponentSchema.properties[$key].'$ref') { + # Resolve property references within the main properties of the schema if (($ComponentSchema.properties[$key].'$ref').StartsWith('#/components/schemas/')) { $refName = ($ComponentSchema.properties[$key].'$ref') -replace '#/components/schemas/', '' if ($Schemas.ContainsKey($refName)) { @@ -1501,6 +1575,7 @@ function Resolve-PodeOAReference { } end { + # Return the fully resolved component schema return $ComponentSchema } } diff --git a/src/Private/PodeServer.ps1 b/src/Private/PodeServer.ps1 index 1b7fa9865..44cae39ff 100644 --- a/src/Private/PodeServer.ps1 +++ b/src/Private/PodeServer.ps1 @@ -24,7 +24,7 @@ function Start-PodeWebServer { $endpoints = @() $endpointsMap = @{} - @(Get-PodeEndpoints -Type Http, Ws) | ForEach-Object { + @(Get-PodeEndpointInternal -Type Http, Ws) | ForEach-Object { # get the ip address $_ip = [string]($_.Address) $_ip = Get-PodeIPAddressesForHostname -Hostname $_ip -Type All | Select-Object -First 1 @@ -71,7 +71,7 @@ function Start-PodeWebServer { # create the listener $listener = (. ([scriptblock]::Create("New-Pode$($PodeContext.Server.ListenerType)Listener -CancellationToken `$PodeContext.Tokens.Cancellation.Token"))) $listener.ErrorLoggingEnabled = (Test-PodeErrorLoggingEnabled) - $listener.ErrorLoggingLevels = @(Get-PodeErrorLoggingLevels) + $listener.ErrorLoggingLevels = @(Get-PodeErrorLoggingLevel) $listener.RequestTimeout = $PodeContext.Server.Request.Timeout $listener.RequestBodySize = $PodeContext.Server.Request.BodySize $listener.ShowServerDetails = [bool]$PodeContext.Server.Security.ServerDetails @@ -103,7 +103,7 @@ function Start-PodeWebServer { } # only if HTTP endpoint - if (Test-PodeEndpoints -Type Http) { + if (Test-PodeEndpoint -Type Http) { # script for listening out for incoming requests $listenScript = { param( @@ -169,7 +169,7 @@ function Start-PodeWebServer { # accept/transfer encoding $WebEvent.TransferEncoding = (Get-PodeTransferEncoding -TransferEncoding (Get-PodeHeader -Name 'Transfer-Encoding') -ThrowError) $WebEvent.AcceptEncoding = (Get-PodeAcceptEncoding -AcceptEncoding (Get-PodeHeader -Name 'Accept-Encoding') -ThrowError) - $WebEvent.Ranges = (Get-PodeRanges -Range (Get-PodeHeader -Name 'Range') -ThrowError) + $WebEvent.Ranges = (Get-PodeRange -Range (Get-PodeHeader -Name 'Range') -ThrowError) # add logging endware for post-request Add-PodeRequestLogEndware -WebEvent $WebEvent @@ -234,7 +234,9 @@ function Start-PodeWebServer { } } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch [System.Net.Http.HttpRequestException] { if ($Response.StatusCode -ge 500) { $_.Exception | Write-PodeErrorLog -CheckInnerException @@ -253,7 +255,7 @@ function Start-PodeWebServer { Set-PodeResponseStatus -Code 500 -Exception $_ } finally { - Update-PodeServerRequestMetrics -WebEvent $WebEvent + Update-PodeServerRequestMetric -WebEvent $WebEvent } # invoke endware specifc to the current web event @@ -266,7 +268,9 @@ function Start-PodeWebServer { } } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException @@ -281,7 +285,7 @@ function Start-PodeWebServer { } # only if WS endpoint - if (Test-PodeEndpoints -Type Ws) { + if (Test-PodeEndpoint -Type Ws) { # script to write messages back to the client(s) $signalScript = { param( @@ -329,7 +333,9 @@ function Start-PodeWebServer { } } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException @@ -339,7 +345,9 @@ function Start-PodeWebServer { } } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException @@ -351,7 +359,7 @@ function Start-PodeWebServer { } # only if WS endpoint - if (Test-PodeEndpoints -Type Ws) { + if (Test-PodeEndpoint -Type Ws) { # script to queue messages from clients to send back to other clients from the server $clientScript = { param( @@ -405,18 +413,22 @@ function Start-PodeWebServer { Send-PodeSignal -Value $SignalEvent.Data.Message -Path $SignalEvent.Data.Path -ClientId $SignalEvent.Data.ClientId } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException } finally { - Update-PodeServerSignalMetrics -SignalEvent $SignalEvent + Update-PodeServerSignalMetric -SignalEvent $SignalEvent Close-PodeDisposable -Disposable $context } } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException @@ -443,7 +455,9 @@ function Start-PodeWebServer { Start-Sleep -Seconds 1 } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException @@ -455,7 +469,7 @@ function Start-PodeWebServer { } $waitType = 'Web' - if (!(Test-PodeEndpoints -Type Http)) { + if (!(Test-PodeEndpoint -Type Http)) { $waitType = 'Signals' } diff --git a/src/Private/Routes.ps1 b/src/Private/Routes.ps1 index 301f45d90..1b8035d3f 100644 --- a/src/Private/Routes.ps1 +++ b/src/Private/Routes.ps1 @@ -376,10 +376,34 @@ function ConvertTo-PodeOpenApiRoutePath { $Path ) - return (Resolve-PodePlaceholders -Path $Path -Pattern '\:(?[\w]+)' -Prepend '{' -Append '}') + return (Resolve-PodePlaceholder -Path $Path -Pattern '\:(?[\w]+)' -Prepend '{' -Append '}') } -function Update-PodeRouteSlashes { +<# +.SYNOPSIS + Updates a Pode route path to ensure proper formatting. + +.DESCRIPTION + This function takes a Pode route path and ensures that it starts with a leading slash ('/') and follows the correct format for static routes. It also replaces '*' with '.*' for proper regex matching. + +.PARAMETER Path + The Pode route path to update. + +.PARAMETER Static + Indicates whether the route is a static route (default is false). + +.PARAMETER NoLeadingSlash + Indicates whether the route should not have a leading slash (default is false). + +.OUTPUTS + The updated Pode route path. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Update-PodeRouteSlash { + [CmdletBinding()] + [OutputType([string])] param( [Parameter(Mandatory = $true)] [string] @@ -432,8 +456,8 @@ function ConvertTo-PodeRouteRegex { $Path = Protect-PodeValue -Value $Path -Default '/' $Path = Split-PodeRouteQuery -Path $Path $Path = Protect-PodeValue -Value $Path -Default '/' - $Path = Update-PodeRouteSlashes -Path $Path - $Path = Resolve-PodePlaceholders -Path $Path + $Path = Update-PodeRouteSlash -Path $Path + $Path = Resolve-PodePlaceholder -Path $Path return $Path } diff --git a/src/Private/Schedules.ps1 b/src/Private/Schedules.ps1 index a59981ef8..79b365b92 100644 --- a/src/Private/Schedules.ps1 +++ b/src/Private/Schedules.ps1 @@ -50,7 +50,7 @@ function Start-PodeScheduleRunspace { } # complete any schedules - Complete-PodeInternalSchedules -Now $_now + Complete-PodeInternalSchedule -Now $_now # first, sleep for a period of time to get to 00 seconds (start of minute) Start-Sleep -Seconds (60 - [DateTime]::Now.Second) @@ -70,7 +70,7 @@ function Start-PodeScheduleRunspace { } # complete any schedules - Complete-PodeInternalSchedules -Now $_now + Complete-PodeInternalSchedule -Now $_now # cron expression only goes down to the minute, so sleep for 1min Start-Sleep -Seconds (60 - [DateTime]::Now.Second) @@ -95,7 +95,33 @@ function Close-PodeScheduleInternal { $null = $PodeContext.Schedules.Processes.Remove($Process.ID) } -function Complete-PodeInternalSchedules { +<# +.SYNOPSIS + Completes schedules that have exceeded their end time. + +.DESCRIPTION + The `Complete-PodeInternalSchedule` function checks for schedules that have an end time + and marks them as completed if their end time is earlier than the current time. + +.PARAMETER Now + Specifies the current date and time. This parameter is mandatory. + +.INPUTS + None. You cannot pipe objects to Complete-PodeInternalSchedule. + +.OUTPUTS + None. The function modifies the state of schedules in the PodeContext. + +.EXAMPLE + # Example usage: + $now = Get-Date + Complete-PodeInternalSchedule -Now $now + # Schedules that have ended are marked as completed. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Complete-PodeInternalSchedule { param( [Parameter(Mandatory = $true)] [datetime] diff --git a/src/Private/ScopedVariables.ps1 b/src/Private/ScopedVariables.ps1 index d13950111..55dabdc90 100644 --- a/src/Private/ScopedVariables.ps1 +++ b/src/Private/ScopedVariables.ps1 @@ -59,36 +59,99 @@ function Add-PodeScopedVariableInbuiltUsing { } # get any using variables - $usingVars = Get-PodeScopedVariableUsingVariables -ScriptBlock $ScriptBlock + $usingVars = Get-PodeScopedVariableUsingVariable -ScriptBlock $ScriptBlock if (($null -eq $usingVars) -or ($usingVars.Count -eq 0)) { return $ScriptBlock, $null } # convert any using vars to use new names - $usingVars = Find-PodeScopedVariableUsingVariableValues -UsingVariables $usingVars -PSSession $PSSession + $usingVars = Find-PodeScopedVariableUsingVariableValue -UsingVariable $usingVars -PSSession $PSSession # now convert the script - $newScriptBlock = Convert-PodeScopedVariableUsingVariables -ScriptBlock $ScriptBlock -UsingVariables $usingVars + $newScriptBlock = Convert-PodeScopedVariableUsingVariable -ScriptBlock $ScriptBlock -UsingVariables $usingVars # return converted script return $newScriptBlock, $usingVars } } -function Get-PodeScopedVariableUsingVariables { +<# +.SYNOPSIS + Retrieves all occurrences of using variables within a given script block. + +.DESCRIPTION + The `Get-PodeScopedVariableUsingVariable` function analyzes a script block and identifies all instances of using variables. + It returns an array of `UsingExpressionAst` objects representing these occurrences. + +.PARAMETER ScriptBlock + Specifies the script block to analyze. This parameter is mandatory. + +.OUTPUTS + Returns an array of `UsingExpressionAst` objects representing using variables found in the script block. + +.EXAMPLE + # Example usage: + $scriptBlock = { + $usingVar1 = "Hello" + $usingVar2 = "World" + Write-Host "Using variables: $usingVar1, $usingVar2" + } + + $usingVariables = Get-PodeScopedVariableUsingVariable -ScriptBlock $scriptBlock + # Process the identified using variables as needed. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Get-PodeScopedVariableUsingVariable { param( [Parameter(Mandatory = $true)] [scriptblock] $ScriptBlock ) + # Analyze the script block AST to find using variables return $ScriptBlock.Ast.FindAll({ $args[0] -is [System.Management.Automation.Language.UsingExpressionAst] }, $true) } -function Find-PodeScopedVariableUsingVariableValues { +<# +.SYNOPSIS + Finds and maps using variables within a given script block to their corresponding values. + +.DESCRIPTION + The `Find-PodeScopedVariableUsingVariableValue` function analyzes a collection of using variables + (represented as `UsingExpressionAst` objects) within a script block. It retrieves the values of these + variables from the specified session state (`$PSSession`) and maps them for further processing. + +.PARAMETER UsingVariable + Specifies an array of `UsingExpressionAst` objects representing using variables found in the script block. + This parameter is mandatory. + +.PARAMETER PSSession + Specifies the session state from which to retrieve variable values. This parameter is mandatory. + +.OUTPUTS + Returns an array of custom objects, each containing the following properties: + - `OldName`: The original expression text for the using variable. + - `NewName`: The modified name for the using variable (prefixed with "__using_"). + - `NewNameWithDollar`: The modified name with a dollar sign prefix (e.g., `$__using_VariableName`). + - `SubExpressions`: An array of sub-expressions associated with the using variable. + - `Value`: The value of the using variable retrieved from the session state. + +.EXAMPLE + # Example usage: + $usingVariables = Get-PodeScopedVariableUsingVariable -ScriptBlock $scriptBlock + $mappedVariables = Find-PodeScopedVariableUsingVariableValue -UsingVariable $usingVariables -PSSession $sessionState + # Process the mapped variables as needed. + +.NOTES + - The function handles both direct using variables and child script using variables (prefixed with "__using_"). + - This is an internal function and may change in future releases of Pode. +#> +function Find-PodeScopedVariableUsingVariableValue { param( [Parameter(Mandatory = $true)] - $UsingVariables, + $UsingVariable, [Parameter(Mandatory = $true)] [System.Management.Automation.SessionState] @@ -97,8 +160,8 @@ function Find-PodeScopedVariableUsingVariableValues { $mapped = @{} - foreach ($usingVar in $UsingVariables) { - # var name + foreach ($usingVar in $UsingVariable) { + # Extract variable name $varName = $usingVar.SubExpression.VariablePath.UserPath # only retrieve value if new var @@ -113,7 +176,7 @@ function Find-PodeScopedVariableUsingVariableValues { throw "Value for `$using:$($varName) could not be found" } - # add to mapped + # Add to mapped variables $mapped[$varName] = @{ OldName = $usingVar.SubExpression.Extent.Text NewName = "__using_$($varName)" @@ -123,14 +186,56 @@ function Find-PodeScopedVariableUsingVariableValues { } } - # add the vars sub-expression for replacing later + # Add the variable's sub-expression for later replacement $mapped[$varName].SubExpressions += $usingVar.SubExpression } return @($mapped.Values) } -function Convert-PodeScopedVariableUsingVariables { +<# +.SYNOPSIS + Converts a script block by replacing using variables with their corresponding values. + +.DESCRIPTION + The `Convert-PodeScopedVariableUsingVariable` function takes a script block and a collection of using variables. + It replaces the using variables within the script block with their associated values. + +.PARAMETER ScriptBlock + Specifies the script block to convert. This parameter is mandatory. + +.PARAMETER UsingVariables + Specifies an array of custom objects representing using variables and their values. + Each object should have the following properties: + - `OldName`: The original expression text for the using variable. + - `NewNameWithDollar`: The modified name with a dollar sign prefix (e.g., `$__using_VariableName`). + - `SubExpressions`: An array of sub-expressions associated with the using variable. + - `Value`: The value of the using variable. + +.OUTPUTS + Returns a new script block with replaced using variables. + +.EXAMPLE + # Example usage: + $usingVariables = @( + @{ + OldName = '$usingVar1' + NewNameWithDollar = '$__using_usingVar1' + SubExpressions = @($usingVar1.SubExpression1, $usingVar1.SubExpression2) + Value = 'SomeValue1' + }, + # Add other using variables here... + ) + + $convertedScriptBlock = Convert-PodeScopedVariableUsingVariable -ScriptBlock $originalScriptBlock -UsingVariables $usingVariables + # Use the converted script block as needed. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Convert-PodeScopedVariableUsingVariable { + [CmdletBinding()] + [OutputType([scriptblock])] param( [Parameter(Mandatory = $true)] [scriptblock] @@ -140,7 +245,7 @@ function Convert-PodeScopedVariableUsingVariables { [hashtable[]] $UsingVariables ) - + # Create a list of variable expressions for replacement $varsList = New-Object 'System.Collections.Generic.List`1[System.Management.Automation.Language.VariableExpressionAst]' $newParams = New-Object System.Collections.ArrayList @@ -150,10 +255,12 @@ function Convert-PodeScopedVariableUsingVariables { } } + # Create a comma-separated list of new parameters $null = $newParams.AddRange(@($UsingVariables.NewNameWithDollar)) $newParams = ($newParams -join ', ') $tupleParams = [tuple]::Create($varsList, $newParams) + # Invoke the internal method to replace variables in the script block $bindingFlags = [System.Reflection.BindingFlags]'Default, NonPublic, Instance' $_varReplacerMethod = $ScriptBlock.Ast.GetType().GetMethod('GetWithInputHandlingForInvokeCommandImpl', $bindingFlags) $convertedScriptBlockStr = $_varReplacerMethod.Invoke($ScriptBlock.Ast, @($tupleParams)) @@ -164,6 +271,7 @@ function Convert-PodeScopedVariableUsingVariables { $convertedScriptBlock = [scriptblock]::Create($convertedScriptBlockStr) + # Handle cases where the script block starts with '$input |' if ($convertedScriptBlock.Ast.EndBlock[0].Statements.Extent.Text.StartsWith('$input |')) { $convertedScriptBlockStr = ($convertedScriptBlockStr -ireplace '\$input \|') $convertedScriptBlock = [scriptblock]::Create($convertedScriptBlockStr) diff --git a/src/Private/Secrets.ps1 b/src/Private/Secrets.ps1 index 612564fa2..324eee35d 100644 --- a/src/Private/Secrets.ps1 +++ b/src/Private/Secrets.ps1 @@ -379,16 +379,46 @@ function Start-PodeSecretVaultUnlocker { } } -function Unregister-PodeSecretVaults { +<# +.SYNOPSIS + Unregisters multiple secret vaults within Pode. + +.DESCRIPTION + The `Unregister-PodeSecretVaultsInternal` function iterates through the list of secret vaults + stored in the PodeContext and unregisters each one. If an error occurs during unregistration, + it can either throw an exception or log the error. + +.PARAMETER ThrowError + If specified, the function will throw an exception when an error occurs during unregistration. + Otherwise, it will log the error and continue processing. + +.INPUTS + None. You cannot pipe objects to Unregister-PodeSecretVaultsInternal. + +.OUTPUTS + None. The function modifies the state of secret vaults in the PodeContext. + +.EXAMPLE + # Example usage: + Unregister-PodeSecretVaultsInternal -ThrowError + # All registered secret vaults are unregistered, and any errors are thrown as exceptions. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Unregister-PodeSecretVaultsInternal { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] param( [switch] $ThrowError ) + # Check if there are any secret vaults to unregister if (Test-PodeIsEmpty $PodeContext.Server.Secrets.Vaults) { return } + # Iterate through each vault and attempt unregistration foreach ($vault in $PodeContext.Server.Secrets.Vaults.Values.Name) { if ([string]::IsNullOrEmpty($vault)) { continue diff --git a/src/Private/Server.ps1 b/src/Private/Server.ps1 index 367d065fd..c1b67888a 100644 --- a/src/Private/Server.ps1 +++ b/src/Private/Server.ps1 @@ -59,8 +59,8 @@ function Start-PodeInternalServer { New-PodeAutoRestartServer # start the runspace pools for web, schedules, etc - New-PodeRunspacePools - Open-PodeRunspacePools + New-PodeRunspacePool + Open-PodeRunspacePool if (!$PodeContext.Server.IsServerless) { # start runspace for loggers @@ -220,18 +220,18 @@ function Restart-PodeInternalServer { $PodeContext.Tokens.Cancellation.Cancel() # close all current runspaces - Close-PodeRunspaces -ClosePool + Close-PodeRunspace -ClosePool # remove all of the pode temp drives - Remove-PodePSDrives + Remove-PodePSDrive # clear-up modules $PodeContext.Server.Modules.Clear() # clear up timers, schedules and loggers - $PodeContext.Server.Routes | Clear-PodeHashtableInnerKeys - $PodeContext.Server.Handlers | Clear-PodeHashtableInnerKeys - $PodeContext.Server.Events | Clear-PodeHashtableInnerKeys + $PodeContext.Server.Routes | Clear-PodeHashtableInnerKey + $PodeContext.Server.Handlers | Clear-PodeHashtableInnerKey + $PodeContext.Server.Events | Clear-PodeHashtableInnerKey if ($null -ne $PodeContext.Server.Verbs) { $PodeContext.Server.Verbs.Clear() @@ -264,7 +264,7 @@ function Restart-PodeInternalServer { # clear security headers $PodeContext.Server.Security.Headers.Clear() - $PodeContext.Server.Security.Cache | Clear-PodeHashtableInnerKeys + $PodeContext.Server.Security.Cache | Clear-PodeHashtableInnerKey # clear endpoints $PodeContext.Server.Endpoints.Clear() @@ -307,7 +307,7 @@ function Restart-PodeInternalServer { $PodeContext.Server.Cache.Storage.Clear() # clear up secret vaults/cache - Unregister-PodeSecretVaults -ThrowError + Unregister-PodeSecretVaultsInternal -ThrowError $PodeContext.Server.Secrets.Vaults.Clear() $PodeContext.Server.Secrets.Keys.Clear() diff --git a/src/Private/Serverless.ps1 b/src/Private/Serverless.ps1 index a7805947c..ec67329a0 100644 --- a/src/Private/Serverless.ps1 +++ b/src/Private/Serverless.ps1 @@ -26,7 +26,7 @@ function Start-PodeAzFuncServer { $response.Headers = @{} # reset event data - $global:WebEvent = @{ + $WebEvent = @{ OnEnd = @() Auth = @{} Response = $response @@ -108,7 +108,7 @@ function Start-PodeAzFuncServer { Set-PodeResponseStatus -Code 500 -Exception $_ } finally { - Update-PodeServerRequestMetrics -WebEvent $WebEvent + Update-PodeServerRequestMetric -WebEvent $WebEvent } # invoke endware specifc to the current web event @@ -154,7 +154,7 @@ function Start-PodeAwsLambdaServer { } # reset event data - $global:WebEvent = @{ + $WebEvent = @{ OnEnd = @() Auth = @{} Response = $response @@ -223,7 +223,7 @@ function Start-PodeAwsLambdaServer { Set-PodeResponseStatus -Code 500 -Exception $_ } finally { - Update-PodeServerRequestMetrics -WebEvent $WebEvent + Update-PodeServerRequestMetric -WebEvent $WebEvent } # invoke endware specifc to the current web event diff --git a/src/Private/ServiceServer.ps1 b/src/Private/ServiceServer.ps1 index 9f39bb535..fa6702d16 100644 --- a/src/Private/ServiceServer.ps1 +++ b/src/Private/ServiceServer.ps1 @@ -12,7 +12,7 @@ function Start-PodeServiceServer { try { while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { # the event object - $ServiceEvent = @{ + $script:ServiceEvent = @{ Lockable = $PodeContext.Threading.Lockables.Global Metadata = @{} } @@ -28,7 +28,9 @@ function Start-PodeServiceServer { Start-Sleep -Seconds $PodeContext.Server.Interval } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog throw $_.Exception diff --git a/src/Private/Setup.ps1 b/src/Private/Setup.ps1 index 340706864..b322d5389 100644 --- a/src/Private/Setup.ps1 +++ b/src/Private/Setup.ps1 @@ -1,4 +1,5 @@ function Invoke-PodePackageScript { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingInvokeExpression', '')] param( [Parameter()] [string] @@ -12,30 +13,44 @@ function Invoke-PodePackageScript { Invoke-Expression -Command $ActionScript } -function Install-PodeLocalModules { +<# +.SYNOPSIS + Installs a local Pode module. + +.DESCRIPTION + This function installs a local Pode module by downloading it from the specified repository. It checks the module version and retrieves the latest version if 'latest' is specified. The module is saved to the specified path. + +.PARAMETER Module + The Pode module to install. It should include the module name, version, and repository information. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Install-PodeLocalModule { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] param( [Parameter()] - $Modules = $null + $Module = $null ) - if ($null -eq $Modules) { + if ($null -eq $Module) { return } $psModules = './ps_modules' # download modules to ps_modules - $Modules.psobject.properties.name | ForEach-Object { + $Module.psobject.properties.name | ForEach-Object { $_name = $_ # get the module version - $_version = $Modules.$_name.version + $_version = $Module.$_name.version if ([string]::IsNullOrWhiteSpace($_version)) { - $_version = $Modules.$_name + $_version = $Module.$_name } # get the module repository - $_repository = Protect-PodeValue -Value $Modules.$_name.repository -Default 'PSGallery' + $_repository = Protect-PodeValue -Value $Module.$_name.repository -Default 'PSGallery' try { # if version is latest, retrieve current diff --git a/src/Private/SmtpServer.ps1 b/src/Private/SmtpServer.ps1 index 603e08dff..3a356515f 100644 --- a/src/Private/SmtpServer.ps1 +++ b/src/Private/SmtpServer.ps1 @@ -9,7 +9,7 @@ function Start-PodeSmtpServer { # work out which endpoints to listen on $endpoints = @() - @(Get-PodeEndpoints -Type Smtp) | ForEach-Object { + @(Get-PodeEndpointInternal -Type Smtp) | ForEach-Object { # get the ip address $_ip = [string]($_.Address) $_ip = Get-PodeIPAddressesForHostname -Hostname $_ip -Type All | Select-Object -First 1 @@ -48,7 +48,7 @@ function Start-PodeSmtpServer { # create the listener $listener = [PodeListener]::new($PodeContext.Tokens.Cancellation.Token) $listener.ErrorLoggingEnabled = (Test-PodeErrorLoggingEnabled) - $listener.ErrorLoggingLevels = @(Get-PodeErrorLoggingLevels) + $listener.ErrorLoggingLevels = @(Get-PodeErrorLoggingLevel) $listener.RequestTimeout = $PodeContext.Server.Request.Timeout $listener.RequestBodySize = $PodeContext.Server.Request.BodySize @@ -98,7 +98,7 @@ function Start-PodeSmtpServer { $Request = $context.Request $Response = $context.Response - $SmtpEvent = @{ + $script:SmtpEvent = @{ Response = $Response Request = $Request Lockable = $PodeContext.Threading.Lockables.Global @@ -150,19 +150,23 @@ function Start-PodeSmtpServer { } } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException } } finally { - $SmtpEvent = $null + $script:SmtpEvent = $null Close-PodeDisposable -Disposable $context } } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException @@ -188,7 +192,9 @@ function Start-PodeSmtpServer { Start-Sleep -Seconds 1 } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException diff --git a/src/Private/Streams.ps1 b/src/Private/Streams.ps1 index 6e44da324..5946760c2 100644 --- a/src/Private/Streams.ps1 +++ b/src/Private/Streams.ps1 @@ -33,7 +33,7 @@ function Read-PodeByteLineFromByteArray { $IncludeNewLine ) - $nlBytes = Get-PodeNewLineBytes -Encoding $Encoding + $nlBytes = Get-PodeNewLineByte -Encoding $Encoding # attempt to find \n $index = [array]::IndexOf($Bytes, $nlBytes.NewLine, $StartIndex) @@ -71,7 +71,7 @@ function Get-PodeByteLinesFromByteArray { # lines $lines = @() - $nlBytes = Get-PodeNewLineBytes -Encoding $Encoding + $nlBytes = Get-PodeNewLineByte -Encoding $Encoding # attempt to find \n $index = 0 @@ -93,26 +93,91 @@ function Get-PodeByteLinesFromByteArray { return $lines } - -function ConvertFrom-PodeStreamToBytes { +<# +.SYNOPSIS + Converts a stream to a byte array. + +.DESCRIPTION + The `ConvertFrom-PodeStreamToByte` function reads data from a stream and converts it to a byte array. + It's useful for scenarios where you need to work with binary data from a stream. + +.PARAMETER Stream + Specifies the input stream to convert. This parameter is mandatory. + +.OUTPUTS + Returns a byte array containing the data read from the input stream. + +.EXAMPLE + # Example usage: + # Read data from a file stream and convert it to a byte array + $stream = [System.IO.File]::OpenRead("C:\path\to\file.bin") + $byteArray = ConvertFrom-PodeStreamToByte -Stream $stream + $stream.Close() + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function ConvertFrom-PodeStreamToByte { param( [Parameter(Mandatory = $true)] $Stream ) + # Initialize a buffer to read data in chunks $buffer = [byte[]]::new(64 * 1024) $ms = New-Object -TypeName System.IO.MemoryStream $read = 0 + # Read data from the stream and write it to the memory stream while (($read = $Stream.Read($buffer, 0, $buffer.Length)) -gt 0) { $ms.Write($buffer, 0, $read) } + # Close the memory stream and return the byte array $ms.Close() return $ms.ToArray() } +<# +.SYNOPSIS + Converts a string value to a byte array using the specified encoding. + +.DESCRIPTION + The `ConvertFrom-PodeValueToByte` function takes a string value and converts it to a byte array. + You can specify the desired encoding (default is UTF-8). + +.PARAMETER Value + Specifies the input string value to convert. + +.PARAMETER Encoding + Specifies the encoding to use when converting the string to bytes. + Default value is UTF-8. + +.OUTPUTS + Returns a byte array containing the encoded representation of the input string. + +.EXAMPLE + # Example usage: + $inputString = "Hello, world!" + $byteArray = ConvertFrom-PodeValueToByte -Value $inputString + # Now you can work with the byte array as needed. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function ConvertFrom-PodeValueToByte { + param( + [Parameter()] + [string] + $Value, + + [Parameter()] + $Encoding = [System.Text.Encoding]::UTF8 + ) + + return $Encoding.GetBytes($Value) +} -function ConvertFrom-PodeValueToBytes { +function ConvertFrom-PodeValueToByte { param( [Parameter()] [string] @@ -150,7 +215,33 @@ function ConvertFrom-PodeBytesToString { return $value } -function Get-PodeNewLineBytes { +<# +.SYNOPSIS + Retrieves information about newline characters in different encodings. + +.DESCRIPTION + The `Get-PodeNewLineByte` function returns a hashtable containing information about newline characters. + It calculates the byte values for newline (`n`) and carriage return (`r`) based on the specified encoding (default is UTF-8). + +.PARAMETER Encoding + Specifies the encoding to use when calculating newline and carriage return byte values. + Default value is UTF-8. + +.OUTPUTS + Returns a hashtable with the following keys: + - `NewLine`: Byte value for newline character (`n`). + - `Return`: Byte value for carriage return character (`r`). + +.EXAMPLE + Get-PodeNewLineByte -Encoding [System.Text.Encoding]::ASCII + # Returns the byte values for newline and carriage return in ASCII encoding. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Get-PodeNewLineByte { + [CmdletBinding()] + [OutputType([hashtable])] param( [Parameter()] $Encoding = [System.Text.Encoding]::UTF8 @@ -199,7 +290,7 @@ function Remove-PodeNewLineBytesFromArray { $Encoding = [System.Text.Encoding]::UTF8 ) - $nlBytes = Get-PodeNewLineBytes -Encoding $Encoding + $nlBytes = Get-PodeNewLineByte -Encoding $Encoding $length = $Bytes.Length - 1 if ($Bytes[$length] -eq $nlBytes.NewLine) { diff --git a/src/Private/TcpServer.ps1 b/src/Private/TcpServer.ps1 index 60156d15b..9de07e93a 100644 --- a/src/Private/TcpServer.ps1 +++ b/src/Private/TcpServer.ps1 @@ -4,7 +4,7 @@ function Start-PodeTcpServer { # work out which endpoints to listen on $endpoints = @() - @(Get-PodeEndpoints -Type Tcp) | ForEach-Object { + @(Get-PodeEndpointInternal -Type Tcp) | ForEach-Object { # get the ip address $_ip = [string]($_.Address) $_ip = Get-PodeIPAddressesForHostname -Hostname $_ip -Type All | Select-Object -First 1 @@ -44,7 +44,7 @@ function Start-PodeTcpServer { # create the listener $listener = [PodeListener]::new($PodeContext.Tokens.Cancellation.Token) $listener.ErrorLoggingEnabled = (Test-PodeErrorLoggingEnabled) - $listener.ErrorLoggingLevels = @(Get-PodeErrorLoggingLevels) + $listener.ErrorLoggingLevels = @(Get-PodeErrorLoggingLevel) $listener.RequestTimeout = $PodeContext.Server.Request.Timeout $listener.RequestBodySize = $PodeContext.Server.Request.BodySize @@ -169,7 +169,9 @@ function Start-PodeTcpServer { $Request.UpgradeToSSL() } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException @@ -181,7 +183,9 @@ function Start-PodeTcpServer { } } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException @@ -207,7 +211,9 @@ function Start-PodeTcpServer { Start-Sleep -Seconds 1 } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException diff --git a/src/Private/Timers.ps1 b/src/Private/Timers.ps1 index ecca314ea..1fddbef8c 100644 --- a/src/Private/Timers.ps1 +++ b/src/Private/Timers.ps1 @@ -72,7 +72,7 @@ function Invoke-PodeInternalTimer { ) try { - $global:TimerEvent = @{ + $script:TimerEvent = @{ Lockable = $PodeContext.Threading.Lockables.Global Sender = $Timer Metadata = @{} diff --git a/src/Private/UnusedHelper.ps1 b/src/Private/UnusedHelper.ps1 new file mode 100644 index 000000000..58f48964e --- /dev/null +++ b/src/Private/UnusedHelper.ps1 @@ -0,0 +1,124 @@ + +function Get-PodeDotSourcedFile { + param( + [Parameter(Mandatory = $true)] + [System.Management.Automation.Language.Ast] + $Ast, + + [Parameter()] + [string] + $RootPath + ) + + # set default root path + if ([string]::IsNullOrWhiteSpace($RootPath)) { + $RootPath = $PodeContext.Server.Root + } + + # get all dot-sourced files + $cmdTypes = @('dot', 'ampersand') + $files = ($Ast.FindAll({ + ($args[0] -is [System.Management.Automation.Language.CommandAst]) -and + ($args[0].InvocationOperator -iin $cmdTypes) -and + ($args[0].CommandElements.StaticType.Name -ieq 'string') + }, $false)).CommandElements.Value + + $fileOrder = @() + + # no files found + if (($null -eq $files) -or ($files.Length -eq 0)) { + return $fileOrder + } + + # get any sub sourced files + foreach ($file in $files) { + $file = Get-PodeRelativePath -Path $file -RootPath $RootPath -JoinRoot + $fileOrder += $file + + $ast = Get-PodeAstFromFile -FilePath $file + + $result = Get-PodeDotSourcedFile -Ast $ast -RootPath (Split-Path -Parent -Path $file) + if (($null -ne $result) -and ($result.Length -gt 0)) { + $fileOrder += $result + } + } + + # return all found files + return $fileOrder +} + + +# Convert-PodePathSeparators +function Convert-PodePathSeparator { + param( + [Parameter()] + $Paths + ) + + return @($Paths | ForEach-Object { + if (![string]::IsNullOrWhiteSpace($_)) { + $_ -ireplace '[\\/]', [System.IO.Path]::DirectorySeparatorChar + } + }) +} + + + +function Open-PodeRunspace { + param( + [Parameter(Mandatory = $true)] + [string] + $Type + ) + + try { + Import-PodeModulesInternal + Add-PodePSDrivesInternal + $PodeContext.RunspacePools[$Type].State = 'Ready' + } + catch { + if ($PodeContext.RunspacePools[$Type].State -ieq 'waiting') { + $PodeContext.RunspacePools[$Type].State = 'Error' + } + + $_ | Out-Default + $_.ScriptStackTrace | Out-Default + throw + } +} + + + +<# +.SYNOPSIS +Tests if the Pode module is from the development branch. + +.DESCRIPTION +The Test-PodeVersionDev function checks if the Pode module's version matches the placeholder value ('$version$'), which is used to indicate the development branch of the module. It returns $true if the version matches, indicating the module is from the development branch, and $false otherwise. + +.PARAMETER None +This function does not accept any parameters. + +.OUTPUTS +System.Boolean +Returns $true if the Pode module version is '$version$', indicating the development branch. Returns $false for any other version. + +.EXAMPLE +PS> $moduleManifest = @{ ModuleVersion = '$version$' } +PS> Test-PodeVersionDev + +Returns $true, indicating the development branch. + +.EXAMPLE +PS> $moduleManifest = @{ ModuleVersion = '1.2.3' } +PS> Test-PodeVersionDev + +Returns $false, indicating a specific release version. + +.NOTES +This function assumes that $moduleManifest is a hashtable representing the loaded module manifest, with a key of ModuleVersion. + +#> +function Test-PodeVersionDev { + return (Get-PodeModuleManifest).ModuleVersion -eq '$version$' +} diff --git a/src/Private/WebSockets.ps1 b/src/Private/WebSockets.ps1 index f72aef50a..b760702c6 100644 --- a/src/Private/WebSockets.ps1 +++ b/src/Private/WebSockets.ps1 @@ -22,7 +22,7 @@ function New-PodeWebSocketReceiver { try { $receiver = [PodeReceiver]::new($PodeContext.Tokens.Cancellation.Token) $receiver.ErrorLoggingEnabled = (Test-PodeErrorLoggingEnabled) - $receiver.ErrorLoggingLevels = @(Get-PodeErrorLoggingLevels) + $receiver.ErrorLoggingLevels = @(Get-PodeErrorLoggingLevel) $PodeContext.Server.WebSockets.Receiver = $receiver $PodeContext.Receivers += $receiver } @@ -81,7 +81,9 @@ function Start-PodeWebSocketRunspace { # invoke websocket script $null = Invoke-PodeScriptBlock -ScriptBlock $websocket.Logic -Arguments $websocket.Arguments -UsingVariables $websocket.UsingVariables -Scoped -Splat } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException @@ -93,7 +95,9 @@ function Start-PodeWebSocketRunspace { } } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException @@ -119,7 +123,9 @@ function Start-PodeWebSocketRunspace { Start-Sleep -Seconds 1 } } - catch [System.OperationCanceledException] {} + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException diff --git a/src/Public/Authentication.ps1 b/src/Public/Authentication.ps1 index 535a29b09..faaf84cd9 100644 --- a/src/Public/Authentication.ps1 +++ b/src/Public/Authentication.ps1 @@ -558,6 +558,7 @@ New-PodeAuthAzureADScheme -Tenant 123-456-678 -ClientId some_id -UsePKCE #> function New-PodeAuthAzureADScheme { [CmdletBinding()] + [OutputType([hashtable])] param( [Parameter()] [ValidateNotNullOrEmpty()] @@ -631,6 +632,7 @@ New-PodeAuthTwitterScheme -ClientId some_id -UsePKCE #> function New-PodeAuthTwitterScheme { [CmdletBinding()] + [OutputType([hashtable])] param( [Parameter(Mandatory = $true)] [string] @@ -1020,6 +1022,7 @@ Get-PodeAuth -Name 'Main' #> function Get-PodeAuth { [CmdletBinding()] + [OutputType([hashtable])] param( [Parameter(Mandatory = $true)] [string] @@ -1050,6 +1053,7 @@ if (Test-PodeAuthExists -Name BasicAuth) { ... } #> function Test-PodeAuthExists { [CmdletBinding()] + [OutputType([bool])] param( [Parameter(Mandatory = $true)] [string] @@ -1081,6 +1085,7 @@ if (Test-PodeAuth -Name 'FormAuth' -IgnoreSession) { ... } #> function Test-PodeAuth { [CmdletBinding()] + [OutputType([boolean])] param( [Parameter(Mandatory = $true)] [string] @@ -1368,6 +1373,7 @@ Add-PodeAuthSession -Name 'SessionAuth' -FailureUrl '/login' #> function Add-PodeAuthSession { [CmdletBinding(DefaultParameterSetName = 'Groups')] + [OutputType([hashtable])] param( [Parameter(Mandatory = $true)] [string] @@ -2079,6 +2085,7 @@ ConvertTo-PodeJwt -Header @{ alg = 'hs256' } -Payload @{ sub = '123'; name = 'Jo #> function ConvertTo-PodeJwt { [CmdletBinding()] + [OutputType([string])] param( [Parameter(Mandatory = $true)] [hashtable] @@ -2140,6 +2147,7 @@ ConvertFrom-PodeJwt -Token "eyJ0eXAiOiJKV1QiLCJhbGciOiJoczI1NiJ9.eyJleHAiOjE2MjI #> function ConvertFrom-PodeJwt { [CmdletBinding(DefaultParameterSetName = 'Secret')] + [OutputType([string])] param( [Parameter(Mandatory = $true)] [string] @@ -2419,6 +2427,7 @@ if (Test-PodeAuthUser) { ... } #> function Test-PodeAuthUser { [CmdletBinding()] + [OutputType([boolean])] param( [switch] $IgnoreSession diff --git a/src/Public/Core.ps1 b/src/Public/Core.ps1 index 0b121bd25..aab2ae6f2 100644 --- a/src/Public/Core.ps1 +++ b/src/Public/Core.ps1 @@ -223,10 +223,10 @@ function Start-PodeServer { Invoke-PodeEvent -Type Stop # set output values - Set-PodeOutputVariables + Set-PodeOutputVariable # unregister secret vaults - Unregister-PodeSecretVaults + Unregister-PodeSecretVaultsInternal # clean the runspaces and tokens Close-PodeServerInternal -ShowDoneMessage:$ShowDoneMessage @@ -545,10 +545,10 @@ function Pode { 'install' { if ($Dev) { - Install-PodeLocalModules -Modules $data.devModules + Install-PodeLocalModule -Module $data.devModules } - Install-PodeLocalModules -Modules $data.modules + Install-PodeLocalModule -Module $data.modules Invoke-PodePackageScript -ActionScript $actionScript } @@ -1007,7 +1007,7 @@ function Add-PodeEndpoint { # set ssl protocols if (!(Test-PodeIsEmpty $SslProtocol)) { - $obj.Ssl.Protocols = (ConvertTo-PodeSslProtocols -Protocols $SslProtocol) + $obj.Ssl.Protocols = (ConvertTo-PodeSslProtocol -Protocol $SslProtocol) } # set the ip for the context (force to localhost for IIS) diff --git a/src/Public/FileWatchers.ps1 b/src/Public/FileWatchers.ps1 index cce9fbd28..2e79e480e 100644 --- a/src/Public/FileWatchers.ps1 +++ b/src/Public/FileWatchers.ps1 @@ -118,20 +118,20 @@ function Add-PodeFileWatcher { # resolve path if relative if (!(Test-PodeIsPSCore)) { - $Path = Convert-PodePlaceholders -Path $Path -Prepend '%' -Append '%' + $Path = Convert-PodePlaceholder -Path $Path -Prepend '%' -Append '%' } $Path = Get-PodeRelativePath -Path $Path -JoinRoot -Resolve if (!(Test-PodeIsPSCore)) { - $Path = Convert-PodePlaceholders -Path $Path -Pattern '\%(?[\w]+)\%' -Prepend ':' -Append ([string]::Empty) + $Path = Convert-PodePlaceholder -Path $Path -Pattern '\%(?[\w]+)\%' -Prepend ':' -Append ([string]::Empty) } # resolve path, and test it - $hasPlaceholders = Test-PodePlaceholders -Path $Path + $hasPlaceholders = Test-PodePlaceholder -Path $Path if ($hasPlaceholders) { - $rgxPath = Update-PodeRouteSlashes -Path $Path -NoLeadingSlash - $rgxPath = Resolve-PodePlaceholders -Path $rgxPath -Slashes + $rgxPath = Update-PodeRouteSlash -Path $Path -NoLeadingSlash + $rgxPath = Resolve-PodePlaceholder -Path $rgxPath -Slashes $Path = $Path -ireplace (Get-PodePlaceholderRegex), '*' } diff --git a/src/Public/Flash.ps1 b/src/Public/Flash.ps1 index ca005ea8c..f579b77ea 100644 --- a/src/Public/Flash.ps1 +++ b/src/Public/Flash.ps1 @@ -86,7 +86,7 @@ Get-PodeFlashMessage -Name 'error' #> function Get-PodeFlashMessage { [CmdletBinding()] - [OutputType([string[]])] + [OutputType([System.Object[]])] param( [Parameter(Mandatory = $true)] [string] @@ -125,7 +125,7 @@ Get-PodeFlashMessageNames #> function Get-PodeFlashMessageNames { [CmdletBinding()] - [OutputType([string[]])] + [OutputType([System.Object[]])] param() # if sessions haven't been setup, error diff --git a/src/Public/Logging.ps1 b/src/Public/Logging.ps1 index 801002f7b..d3e09d130 100644 --- a/src/Public/Logging.ps1 +++ b/src/Public/Logging.ps1 @@ -550,7 +550,7 @@ function Write-PodeErrorLog { } # do nothing if the error level isn't present - $levels = @(Get-PodeErrorLoggingLevels) + $levels = @(Get-PodeErrorLoggingLevel) if ($levels -inotcontains $Level) { return } @@ -648,6 +648,7 @@ $value = Protect-PodeLogItem -Item 'Username=Morty, Password=Hunter2' #> function Protect-PodeLogItem { [CmdletBinding()] + [OutputType([string])] param( [Parameter(ValueFromPipeline = $true)] [string] diff --git a/src/Public/Metrics.ps1 b/src/Public/Metrics.ps1 index f30787caf..fb6797d72 100644 --- a/src/Public/Metrics.ps1 +++ b/src/Public/Metrics.ps1 @@ -16,6 +16,7 @@ $totalUptime = Get-PodeServerUptime -Total #> function Get-PodeServerUptime { [CmdletBinding()] + [OutputType([long])] param( [switch] $Total @@ -70,6 +71,7 @@ $404Reqs = Get-PodeServerRequestMetric -StatusCode 404 #> function Get-PodeServerRequestMetric { [CmdletBinding(DefaultParameterSetName = 'StatusCode')] + [OutputType([int])] param( [Parameter(ParameterSetName = 'StatusCode')] [int] diff --git a/src/Public/OAComponents.ps1 b/src/Public/OAComponents.ps1 index 6a9cf4f62..c598a1109 100644 --- a/src/Public/OAComponents.ps1 +++ b/src/Public/OAComponents.ps1 @@ -371,7 +371,7 @@ function Add-PodeOAComponentParameter { [string[]] $DefinitionTag ) - + $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag foreach ($tag in $DefinitionTag) { diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index 70c13b7f1..6482621f3 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -3114,9 +3114,9 @@ function Add-PodeOAExternalRoute { 'builtin' { # ensure the route has appropriate slashes - $Path = Update-PodeRouteSlashes -Path $Path + $Path = Update-PodeRouteSlash -Path $Path $OpenApiPath = ConvertTo-PodeOpenApiRoutePath -Path $Path - $Path = Resolve-PodePlaceholders -Path $Path + $Path = Resolve-PodePlaceholder -Path $Path $extRoute = @{ Method = $Method.ToLower() Path = $Path diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index e64eb7e55..7e08f933e 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -192,7 +192,7 @@ function Write-PodeTextResponse { else { # convert string to bytes if ($isStringValue) { - $Bytes = ConvertFrom-PodeValueToBytes -Value $Value + $Bytes = ConvertFrom-PodeValueToByte -Value $Value } # check if we only need a range of the bytes diff --git a/src/Public/Routes.ps1 b/src/Public/Routes.ps1 index 716d56b97..6eb919972 100644 --- a/src/Public/Routes.ps1 +++ b/src/Public/Routes.ps1 @@ -288,12 +288,12 @@ function Add-PodeRoute { } # ensure the route has appropriate slashes - $Path = Update-PodeRouteSlashes -Path $Path + $Path = Update-PodeRouteSlash -Path $Path $OpenApiPath = ConvertTo-PodeOpenApiRoutePath -Path $Path - $Path = Resolve-PodePlaceholders -Path $Path + $Path = Resolve-PodePlaceholder -Path $Path # get endpoints from name - $endpoints = Find-PodeEndpoints -EndpointName $EndpointName + $endpoints = Find-PodeEndpoint -EndpointName $EndpointName # get default route IfExists state if ($IfExists -ieq 'Default') { @@ -734,12 +734,12 @@ function Add-PodeStaticRoute { } # ensure the route has appropriate slashes - $Path = Update-PodeRouteSlashes -Path $Path -Static + $Path = Update-PodeRouteSlash -Path $Path -Static $OpenApiPath = ConvertTo-PodeOpenApiRoutePath -Path $Path - $Path = Resolve-PodePlaceholders -Path $Path + $Path = Resolve-PodePlaceholder -Path $Path # get endpoints from name - $endpoints = Find-PodeEndpoints -EndpointName $EndpointName + $endpoints = Find-PodeEndpoint -EndpointName $EndpointName # get default route IfExists state if ($IfExists -ieq 'Default') { @@ -968,10 +968,10 @@ function Add-PodeSignalRoute { $origPath = $Path # ensure the route has appropriate slashes - $Path = Update-PodeRouteSlashes -Path $Path + $Path = Update-PodeRouteSlash -Path $Path # get endpoints from name - $endpoints = Find-PodeEndpoints -EndpointName $EndpointName + $endpoints = Find-PodeEndpoint -EndpointName $EndpointName # get default route IfExists state if ($IfExists -ieq 'Default') { @@ -1673,8 +1673,8 @@ function Remove-PodeRoute { } # ensure the route has appropriate slashes and replace parameters - $Path = Update-PodeRouteSlashes -Path $Path - $Path = Resolve-PodePlaceholders -Path $Path + $Path = Update-PodeRouteSlash -Path $Path + $Path = Resolve-PodePlaceholder -Path $Path # ensure route does exist if (!$PodeContext.Server.Routes[$Method].Contains($Path)) { @@ -1732,7 +1732,7 @@ function Remove-PodeStaticRoute { $Method = 'Static' # ensure the route has appropriate slashes and replace parameters - $Path = Update-PodeRouteSlashes -Path $Path -Static + $Path = Update-PodeRouteSlash -Path $Path -Static # ensure route does exist if (!$PodeContext.Server.Routes[$Method].Contains($Path)) { @@ -1781,7 +1781,7 @@ function Remove-PodeSignalRoute { $Method = 'Signal' # ensure the route has appropriate slashes and replace parameters - $Path = Update-PodeRouteSlashes -Path $Path + $Path = Update-PodeRouteSlash -Path $Path # ensure route does exist if (!$PodeContext.Server.Routes[$Method].Contains($Path)) { @@ -2343,6 +2343,7 @@ Get-PodeRoute -Method Post -Path '/users/:userId' -EndpointName User #> function Get-PodeRoute { [CmdletBinding()] + [OutputType([System.Object[]])] param( [Parameter()] [ValidateSet('', 'Connect', 'Delete', 'Get', 'Head', 'Merge', 'Options', 'Patch', 'Post', 'Put', 'Trace', '*')] @@ -2378,8 +2379,8 @@ function Get-PodeRoute { # if we have a path, filter if (![string]::IsNullOrWhiteSpace($Path)) { $Path = Split-PodeRouteQuery -Path $Path - $Path = Update-PodeRouteSlashes -Path $Path - $Path = Resolve-PodePlaceholders -Path $Path + $Path = Update-PodeRouteSlash -Path $Path + $Path = Resolve-PodePlaceholder -Path $Path $routes = @(foreach ($route in $routes) { if ($route.Path -ine $Path) { @@ -2428,6 +2429,7 @@ Get-PodeStaticRoute -Path '/assets' -EndpointName User #> function Get-PodeStaticRoute { [CmdletBinding()] + [OutputType([System.Object[]])] param( [Parameter()] [string] @@ -2446,7 +2448,7 @@ function Get-PodeStaticRoute { # if we have a path, filter if (![string]::IsNullOrWhiteSpace($Path)) { - $Path = Update-PodeRouteSlashes -Path $Path -Static + $Path = Update-PodeRouteSlash -Path $Path -Static $routes = @(foreach ($route in $routes) { if ($route.Path -ine $Path) { continue @@ -2491,6 +2493,7 @@ Get-PodeSignalRoute -Path '/message' #> function Get-PodeSignalRoute { [CmdletBinding()] + [OutputType([System.Object[]])] param( [Parameter()] [string] @@ -2509,7 +2512,7 @@ function Get-PodeSignalRoute { # if we have a path, filter if (![string]::IsNullOrWhiteSpace($Path)) { - $Path = Update-PodeRouteSlashes -Path $Path + $Path = Update-PodeRouteSlash -Path $Path $routes = @(foreach ($route in $routes) { if ($route.Path -ine $Path) { continue @@ -2655,11 +2658,11 @@ function Test-PodeRoute { } # ensure the route has appropriate slashes - $Path = Update-PodeRouteSlashes -Path $Path - $Path = Resolve-PodePlaceholders -Path $Path + $Path = Update-PodeRouteSlash -Path $Path + $Path = Resolve-PodePlaceholder -Path $Path # get endpoint from name - $endpoint = @(Find-PodeEndpoints -EndpointName $EndpointName)[0] + $endpoint = @(Find-PodeEndpoint -EndpointName $EndpointName)[0] # check for routes $found = (Test-PodeRouteInternal -Method $Method -Path $Path -Protocol $endpoint.Protocol -Address $endpoint.Address) @@ -2708,11 +2711,11 @@ function Test-PodeStaticRoute { } # ensure the route has appropriate slashes - $Path = Update-PodeRouteSlashes -Path $Path -Static - $Path = Resolve-PodePlaceholders -Path $Path + $Path = Update-PodeRouteSlash -Path $Path -Static + $Path = Resolve-PodePlaceholder -Path $Path # get endpoint from name - $endpoint = @(Find-PodeEndpoints -EndpointName $EndpointName)[0] + $endpoint = @(Find-PodeEndpoint -EndpointName $EndpointName)[0] # check for routes return (Test-PodeRouteInternal -Method $Method -Path $Path -Protocol $endpoint.Protocol -Address $endpoint.Address) @@ -2749,10 +2752,10 @@ function Test-PodeSignalRoute { $Method = 'Signal' # ensure the route has appropriate slashes - $Path = Update-PodeRouteSlashes -Path $Path + $Path = Update-PodeRouteSlash -Path $Path # get endpoint from name - $endpoint = @(Find-PodeEndpoints -EndpointName $EndpointName)[0] + $endpoint = @(Find-PodeEndpoint -EndpointName $EndpointName)[0] # check for routes return (Test-PodeRouteInternal -Method $Method -Path $Path -Protocol $endpoint.Protocol -Address $endpoint.Address) diff --git a/src/Public/SSE.ps1 b/src/Public/SSE.ps1 index c3203e8a4..f96721272 100644 --- a/src/Public/SSE.ps1 +++ b/src/Public/SSE.ps1 @@ -373,6 +373,7 @@ if (Test-PodeSseClientIdValid -ClientId 'my-client-id') { ... } #> function Test-PodeSseClientIdValid { [CmdletBinding()] + [OutputType([bool])] param( [Parameter()] [string] @@ -614,6 +615,7 @@ $level = Get-PodeSseBroadcastLevel -Name 'Actions' #> function Get-PodeSseBroadcastLevel { [CmdletBinding()] + [OutputType([string])] param( [Parameter(Mandatory = $true)] [string] @@ -666,6 +668,7 @@ if (Test-PodeSseBroadcastLevel -Name 'Actions' -ClientId 'my-client-id') { ... } #> function Test-PodeSseBroadcastLevel { [CmdletBinding()] + [OutputType([bool])] param( [Parameter(Mandatory = $true)] [string] diff --git a/src/Public/Schedules.ps1 b/src/Public/Schedules.ps1 index e88b577c4..28eaa7d74 100644 --- a/src/Public/Schedules.ps1 +++ b/src/Public/Schedules.ps1 @@ -114,7 +114,7 @@ function Add-PodeSchedule { $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState # add the schedule - $parsedCrons = ConvertFrom-PodeCronExpressions -Expressions @($Cron) + $parsedCrons = ConvertFrom-PodeCronExpression -Expression @($Cron) $nextTrigger = Get-PodeCronNextEarliestTrigger -Expressions $parsedCrons -StartTime $StartTime -EndTime $EndTime $PodeContext.Schedules.Enabled = $true @@ -311,7 +311,7 @@ function Edit-PodeSchedule { # edit cron if supplied if (!(Test-PodeIsEmpty $Cron)) { - $_schedule.Crons = (ConvertFrom-PodeCronExpressions -Expressions @($Cron)) + $_schedule.Crons = (ConvertFrom-PodeCronExpression -Expression @($Cron)) $_schedule.CronsRaw = $Cron $_schedule.NextTriggerTime = Get-PodeCronNextEarliestTrigger -Expressions $_schedule.Crons -StartTime $_schedule.StartTime -EndTime $_schedule.EndTime } diff --git a/src/Public/ScopedVariables.ps1 b/src/Public/ScopedVariables.ps1 index 7a92a1149..88f193832 100644 --- a/src/Public/ScopedVariables.ps1 +++ b/src/Public/ScopedVariables.ps1 @@ -24,6 +24,8 @@ $ScriptBlock = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -Exclude Se #> function Convert-PodeScopedVariables { [CmdletBinding()] + [OutputType([System.Object[]])] + [OutputType([scriptblock])] param( [Parameter(ValueFromPipeline = $true)] [scriptblock] @@ -95,6 +97,7 @@ $ScriptBlock, $otherResults = Convert-PodeScopedVariable -Name Using -ScriptBloc #> function Convert-PodeScopedVariable { [CmdletBinding()] + [OutputType([scriptblock])] param( [Parameter(Mandatory = $true)] [string] @@ -326,6 +329,7 @@ Get-PodeScopedVariable -Name State, Using #> function Get-PodeScopedVariable { [CmdletBinding()] + [OutputType([System.Object[]])] param( [Parameter()] [string[]] diff --git a/src/Public/Security.ps1 b/src/Public/Security.ps1 index 3b360f8af..3dae694b5 100644 --- a/src/Public/Security.ps1 +++ b/src/Public/Security.ps1 @@ -411,7 +411,7 @@ function Set-PodeSecurityContentSecurityPolicy { $values += 'upgrade-insecure-requests' } - $values = ($values -ne $null) + $values = ($null -ne $values) $value = ($values -join '; ') # add the header @@ -581,7 +581,7 @@ function Add-PodeSecurityContentSecurityPolicy { $values += 'upgrade-insecure-requests' } - $values = ($values -ne $null) + $values = ($null -ne $values) $value = ($values -join '; ') # add the header @@ -864,7 +864,7 @@ function Set-PodeSecurityPermissionsPolicy { Protect-PodePermissionsPolicyKeyword -Name 'xr-spatial-tracking' -Value $XrSpatialTracking ) - $values = ($values -ne $null) + $values = ($null -ne $values) $value = ($values -join ', ') # add the header @@ -1129,7 +1129,7 @@ function Add-PodeSecurityPermissionsPolicy { Protect-PodePermissionsPolicyKeyword -Name 'xr-spatial-tracking' -Value $XrSpatialTracking -Append ) - $values = ($values -ne $null) + $values = ($null -ne $values) $value = ($values -join ', ') # add the header diff --git a/src/Public/Sessions.ps1 b/src/Public/Sessions.ps1 index 55b3991e3..92af715ea 100644 --- a/src/Public/Sessions.ps1 +++ b/src/Public/Sessions.ps1 @@ -333,6 +333,7 @@ $duration = Get-PodeSessionDuration #> function Get-PodeSessionDuration { [CmdletBinding()] + [OutputType([int])] param() return [int]$PodeContext.Server.Sessions.Info.Duration @@ -350,6 +351,7 @@ $expiry = Get-PodeSessionExpiry #> function Get-PodeSessionExpiry { [CmdletBinding()] + [OutputType([datetime])] param() # error if session is null diff --git a/src/Public/Tasks.ps1 b/src/Public/Tasks.ps1 index d4f47573c..573687862 100644 --- a/src/Public/Tasks.ps1 +++ b/src/Public/Tasks.ps1 @@ -377,6 +377,7 @@ Invoke-PodeTask -Name 'Example1' | Test-PodeTaskCompleted #> function Test-PodeTaskCompleted { [CmdletBinding()] + [OutputType([bool])] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [hashtable] diff --git a/src/Public/Utilities.ps1 b/src/Public/Utilities.ps1 index d73fa132f..f5af4e189 100644 --- a/src/Public/Utilities.ps1 +++ b/src/Public/Utilities.ps1 @@ -180,7 +180,7 @@ function Use-PodeScript { # we have a path, if it's a directory/wildcard then loop over all files if (![string]::IsNullOrWhiteSpace($_path)) { - $_paths = Get-PodeWildcardFiles -Path $Path -Wildcard '*.ps1' + $_paths = Get-PodeWildcardFile -Path $Path -Wildcard '*.ps1' if (!(Test-PodeIsEmpty $_paths)) { foreach ($_path in $_paths) { Use-PodeScript -Path $_path @@ -337,7 +337,7 @@ function Import-PodeModule { 'path' { $Path = Get-PodeRelativePath -Path $Path -RootPath $rootPath -JoinRoot -Resolve - $paths = Get-PodeWildcardFiles -Path $Path -RootPath $rootPath -Wildcard '*.ps*1' + $paths = Get-PodeWildcardFile -Path $Path -RootPath $rootPath -Wildcard '*.ps*1' if (!(Test-PodeIsEmpty $paths)) { foreach ($_path in $paths) { Import-PodeModule -Path $_path @@ -805,6 +805,7 @@ Show the Object Type 'Some output' | Write-PodeHost -ForegroundColor Cyan #> function Write-PodeHost { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] [CmdletBinding(DefaultParameterSetName = 'inbuilt')] param( [Parameter(Position = 0, ValueFromPipeline = $true)] diff --git a/src/Public/Verbs.ps1 b/src/Public/Verbs.ps1 index 63cd58b9c..d5befdf16 100644 --- a/src/Public/Verbs.ps1 +++ b/src/Public/Verbs.ps1 @@ -70,10 +70,10 @@ function Add-PodeVerb { ) # find placeholder parameters in verb (ie: COMMAND :parameter) - $Verb = Resolve-PodePlaceholders -Path $Verb + $Verb = Resolve-PodePlaceholder -Path $Verb # get endpoints from name - $endpoints = Find-PodeEndpoints -EndpointName $EndpointName + $endpoints = Find-PodeEndpoint -EndpointName $EndpointName # ensure the verb doesn't already exist for each endpoint foreach ($_endpoint in $endpoints) { @@ -146,7 +146,7 @@ function Remove-PodeVerb { ) # ensure the verb placeholders are replaced - $Verb = Resolve-PodePlaceholders -Path $Verb + $Verb = Resolve-PodePlaceholder -Path $Verb # ensure verb does exist if (!$PodeContext.Server.Verbs.Contains($Verb)) { @@ -217,7 +217,7 @@ function Get-PodeVerb { # if we have a verb, filter if (![string]::IsNullOrWhiteSpace($Verb)) { - $Verb = Resolve-PodePlaceholders -Path $Verb + $Verb = Resolve-PodePlaceholder -Path $Verb $verbs = $PodeContext.Server.Verbs[$Verb] } else { diff --git a/src/Public/WebSockets.ps1 b/src/Public/WebSockets.ps1 index 5d2cbd21d..607dc4e52 100644 --- a/src/Public/WebSockets.ps1 +++ b/src/Public/WebSockets.ps1 @@ -338,6 +338,7 @@ Test-PodeWebSocket -Name 'Example' #> function Test-PodeWebSocket { [CmdletBinding()] + [OutputType([bool])] param( [Parameter(Mandatory = $true)] [string] diff --git a/tests/unit/CronParser.Tests.ps1 b/tests/unit/CronParser.Tests.ps1 index b5d7454e4..b063a9860 100644 --- a/tests/unit/CronParser.Tests.ps1 +++ b/tests/unit/CronParser.Tests.ps1 @@ -6,9 +6,9 @@ BeforeAll { Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } } -Describe 'Get-PodeCronFields' { +Describe 'Get-PodeCronField' { It 'Returns valid cron fields' { - Get-PodeCronFields | Should -Be @( + Get-PodeCronField | Should -Be @( 'Minute', 'Hour', 'DayOfMonth', @@ -18,9 +18,9 @@ Describe 'Get-PodeCronFields' { } } -Describe 'Get-PodeCronFieldConstraints' { +Describe 'Get-PodeCronFieldConstraint' { It 'Returns valid cron field constraints' { - $constraints = Get-PodeCronFieldConstraints + $constraints = Get-PodeCronFieldConstraint $constraints | Should -Not -Be $null $constraints.MinMax | Should -Be @( @@ -64,9 +64,9 @@ Describe 'Get-PodeCronPredefined' { } } -Describe 'Get-PodeCronFieldAliases' { +Describe 'Get-PodeCronFieldAlias' { It 'Returns valid aliases' { - $aliases = Get-PodeCronFieldAliases + $aliases = Get-PodeCronFieldAlias $aliases | Should -Not -Be $null $aliases.Month.Jan | Should -Be 1 @@ -99,7 +99,7 @@ Describe 'ConvertFrom-PodeCronExpression' { } It 'Throw empty expression parameter error' { - { ConvertFrom-PodeCronExpression -Expression ([string]::Empty) } | Should -Throw -ExpectedMessage '*The argument is null or empty*' + { ConvertFrom-PodeCronExpression -Expression ([string]::Empty) } | Should -Throw -ExpectedMessage '*The argument is null*' } } @@ -501,50 +501,50 @@ Describe 'Get-PodeCronNextTrigger' { } It 'Returns the next minute' { $exp = '* * * * *' - $cron = ConvertFrom-PodeCronExpressions -Expressions $exp + $cron = ConvertFrom-PodeCronExpression -Expression $exp Get-PodeCronNextTrigger -Expression $cron -StartTime $inputDate | Should -Be ([datetime]::new(2020, 1, 1, 0, 1, 0)) } It 'Returns the next hour' { $exp = '0 * * * *' - $cron = ConvertFrom-PodeCronExpressions -Expressions $exp + $cron = ConvertFrom-PodeCronExpression -Expression $exp Get-PodeCronNextTrigger -Expression $cron -StartTime $inputDate | Should -Be ([datetime]::new(2020, 1, 1, 1, 0, 0)) } It 'Returns the next day' { $exp = '0 0 * * *' - $cron = ConvertFrom-PodeCronExpressions -Expressions $exp + $cron = ConvertFrom-PodeCronExpression -Expression $exp Get-PodeCronNextTrigger -Expression $cron -StartTime $inputDate | Should -Be ([datetime]::new(2020, 1, 2, 0, 0, 0)) } It 'Returns the next month' { $exp = '0 0 1 * *' - $cron = ConvertFrom-PodeCronExpressions -Expressions $exp + $cron = ConvertFrom-PodeCronExpression -Expression $exp Get-PodeCronNextTrigger -Expression $cron -StartTime $inputDate | Should -Be ([datetime]::new(2020, 2, 1, 0, 0, 0)) } It 'Returns the next year' { $exp = '0 0 1 1 *' - $cron = ConvertFrom-PodeCronExpressions -Expressions $exp + $cron = ConvertFrom-PodeCronExpression -Expression $exp Get-PodeCronNextTrigger -Expression $cron -StartTime $inputDate | Should -Be ([datetime]::new(2021, 1, 1, 0, 0, 0)) } It 'Returns the friday 3rd' { $exp = '0 0 * 1 FRI' - $cron = ConvertFrom-PodeCronExpressions -Expressions $exp + $cron = ConvertFrom-PodeCronExpression -Expression $exp Get-PodeCronNextTrigger -Expression $cron -StartTime $inputDate | Should -Be ([datetime]::new(2020, 1, 3, 0, 0, 0)) } It 'Returns the 2023 friday' { $exp = '0 0 13 1 FRI' - $cron = ConvertFrom-PodeCronExpressions -Expressions $exp + $cron = ConvertFrom-PodeCronExpression -Expression $exp Get-PodeCronNextTrigger -Expression $cron -StartTime $inputDate | Should -Be ([datetime]::new(2023, 1, 13, 0, 0, 0)) } It 'Returns the null for after end time' { $exp = '0 0 20 1 FRI' $end = [datetime]::new(2020, 1, 19) - $cron = ConvertFrom-PodeCronExpressions -Expressions $exp + $cron = ConvertFrom-PodeCronExpression -Expression $exp Get-PodeCronNextTrigger -Expression $cron -StartTime $inputDate -EndTime $end | Should -Be $null } } @@ -555,37 +555,37 @@ Describe 'Get-PodeCronNextTrigger' { } It 'Returns the minute but next hour' { $exp = '20 * * * *' - $cron = ConvertFrom-PodeCronExpressions -Expressions $exp + $cron = ConvertFrom-PodeCronExpression -Expression $exp Get-PodeCronNextTrigger -Expression $cron -StartTime $inputDate | Should -Be ([datetime]::new(2020, 1, 15, 3, 20, 0)) } It 'Returns the later minute but same hour' { $exp = '20,40 * * * *' - $cron = ConvertFrom-PodeCronExpressions -Expressions $exp + $cron = ConvertFrom-PodeCronExpression -Expression $exp Get-PodeCronNextTrigger -Expression $cron -StartTime $inputDate | Should -Be ([datetime]::new(2020, 1, 15, 2, 40, 0)) } It 'Returns the next minute but same hour' { $exp = '20-40 * * * *' - $cron = ConvertFrom-PodeCronExpressions -Expressions $exp + $cron = ConvertFrom-PodeCronExpression -Expression $exp Get-PodeCronNextTrigger -Expression $cron -StartTime $inputDate | Should -Be ([datetime]::new(2020, 1, 15, 2, 31, 0)) } It 'Returns the a very specific date' { $exp = '37 13 5 2 FRI' - $cron = ConvertFrom-PodeCronExpressions -Expressions $exp + $cron = ConvertFrom-PodeCronExpression -Expression $exp Get-PodeCronNextTrigger -Expression $cron -StartTime $inputDate | Should -Be ([datetime]::new(2021, 2, 5, 13, 37, 0)) } It 'Returns the 30 March' { $inputDate = [datetime]::new(2020, 1, 31, 0, 0, 0) - $cron = ConvertFrom-PodeCronExpressions -Expressions '* * 30 * *' + $cron = ConvertFrom-PodeCronExpression -Expression '* * 30 * *' Get-PodeCronNextTrigger -Expression $cron -StartTime $inputDate | Should -Be ([datetime]::new(2020, 3, 30, 0, 0, 0)) } It 'Returns the 28 Feb' { $inputDate = [datetime]::new(2020, 1, 31, 0, 0, 0) - $cron = ConvertFrom-PodeCronExpressions -Expressions '* * 28 * *' + $cron = ConvertFrom-PodeCronExpression -Expression '* * 28 * *' Get-PodeCronNextTrigger -Expression $cron -StartTime $inputDate | Should -Be ([datetime]::new(2020, 2, 28, 0, 0, 0)) } } @@ -597,19 +597,19 @@ Describe 'Get-PodeCronNextEarliestTrigger' { } It 'Returns the earliest trigger when both valid' { - $crons = ConvertFrom-PodeCronExpressions -Expressions '* * 11 * FRI', '* * 10 * WED' + $crons = ConvertFrom-PodeCronExpression -Expression '* * 11 * FRI', '* * 10 * WED' Get-PodeCronNextEarliestTrigger -Expressions $crons -StartTime $inputDate | Should -Be ([datetime]::new(2020, 6, 10, 0, 0, 0)) } It 'Returns the earliest trigger when one after end time' { $end = [datetime]::new(2020, 1, 9) - $crons = ConvertFrom-PodeCronExpressions -Expressions '* * 8 * WED', '* * 10 * FRi' + $crons = ConvertFrom-PodeCronExpression -Expression '* * 8 * WED', '* * 10 * FRi' Get-PodeCronNextEarliestTrigger -Expressions $crons -StartTime $inputDate -EndTime $end | Should -Be ([datetime]::new(2020, 1, 8, 0, 0, 0)) } It 'Returns the null when all after end time' { $end = [datetime]::new(2020, 1, 7) - $crons = ConvertFrom-PodeCronExpressions -Expressions '* * 8 * WED', '* * 10 * FRi' + $crons = ConvertFrom-PodeCronExpression -Expression '* * 8 * WED', '* * 10 * FRi' Get-PodeCronNextEarliestTrigger -Expressions $crons -StartTime $inputDate -EndTime $end | Should -Be $null } } \ No newline at end of file diff --git a/tests/unit/Cryptography.Tests.ps1 b/tests/unit/Cryptography.Tests.ps1 index 1345986c5..ffd6c0563 100644 --- a/tests/unit/Cryptography.Tests.ps1 +++ b/tests/unit/Cryptography.Tests.ps1 @@ -36,14 +36,14 @@ Describe 'New-PodeGuid' { } It 'Returns a secure guid' { - Mock Get-PodeRandomBytes { return @(10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10) } + Mock Get-PodeRandomByte { return @(10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10) } New-PodeGuid -Secure -Length 16 | Should -Be '0a0a0a0a-0a0a-0a0a-0a0a-0a0a0a0a0a0a' } } -Describe 'Get-PodeRandomBytes' { +Describe 'Get-PodeRandomByte' { It 'Returns an array of bytes' { - $b = (Get-PodeRandomBytes -Length 16) + $b = (Get-PodeRandomByte -Length 16) $b | Should -Not -Be $null $b.Length | Should -Be 16 } @@ -51,7 +51,7 @@ Describe 'Get-PodeRandomBytes' { Describe 'New-PodeSalt' { It 'Returns a salt' { - Mock Get-PodeRandomBytes { return @(10, 10, 10) } + Mock Get-PodeRandomByte { return @(10, 10, 10) } New-PodeSalt -Length 3 | Should -Be 'CgoK' } } \ No newline at end of file diff --git a/tests/unit/Helpers.Tests.ps1 b/tests/unit/Helpers.Tests.ps1 index d80e5c543..15a92391c 100644 --- a/tests/unit/Helpers.Tests.ps1 +++ b/tests/unit/Helpers.Tests.ps1 @@ -1078,7 +1078,7 @@ Describe 'Get-PodeRelativePath' { } } -Describe 'Get-PodeWildcardFiles' { +Describe 'Get-PodeWildcardFile' { BeforeAll { Mock Get-PodeRelativePath { return $Path } Mock Get-ChildItem { @@ -1088,19 +1088,19 @@ Describe 'Get-PodeWildcardFiles' { } It 'Get files after adding a wildcard to a directory' { - $result = @(Get-PodeWildcardFiles -Path './path' -Wildcard '*.ps1') + $result = @(Get-PodeWildcardFile -Path './path' -Wildcard '*.ps1') $result.Length | Should -Be 1 $result[0] | Should -Be './file1.ps1' } It 'Get files for wildcard path' { - $result = @(Get-PodeWildcardFiles -Path './path/*.png') + $result = @(Get-PodeWildcardFile -Path './path/*.png') $result.Length | Should -Be 1 $result[0] | Should -Be './file1.png' } It 'Returns null for non-wildcard path' { - Get-PodeWildcardFiles -Path './some/path/file.txt' | Should -Be $null + Get-PodeWildcardFile -Path './some/path/file.txt' | Should -Be $null } } @@ -1126,19 +1126,19 @@ Describe 'Test-PodeIsServerless' { } } -Describe 'Close-PodeRunspaces' { +Describe 'Close-PodeRunspace' { It 'Returns and does nothing if serverless' { $PodeContext = @{ 'Server' = @{ 'IsServerless' = $true } } - Close-PodeRunspaces -ClosePool + Close-PodeRunspace -ClosePool } } Describe 'Close-PodeServerInternal' { BeforeAll { - Mock Close-PodeRunspaces { } + Mock Close-PodeRunspace { } Mock Stop-PodeFileMonitor { } Mock Close-PodeDisposable { } - Mock Remove-PodePSDrives { } + Mock Remove-PodePSDrive { } Mock Write-Host { } } It 'Closes out pode, but with no done flag' { @@ -1287,60 +1287,6 @@ Describe 'Get-PodeCount' { } } -Describe 'Convert-PodePathSeparators' { - Context 'Null' { - It 'Null' { - Convert-PodePathSeparators -Path $null | Should -Be $null - } - } - - Context 'String' { - It 'Empty' { - Convert-PodePathSeparators -Path '' | Should -Be $null - Convert-PodePathSeparators -Path ' ' | Should -Be $null - } - - It 'Value' { - Convert-PodePathSeparators -Path 'anyValue' | Should -Be 'anyValue' - Convert-PodePathSeparators -Path 1 | Should -Be 1 - } - - It 'Path' { - Convert-PodePathSeparators -Path 'one/Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)Seperators" - Convert-PodePathSeparators -Path 'one\Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)Seperators" - - Convert-PodePathSeparators -Path 'one/two/Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)two$([System.IO.Path]::DirectorySeparatorChar)Seperators" - Convert-PodePathSeparators -Path 'one\two\Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)two$([System.IO.Path]::DirectorySeparatorChar)Seperators" - Convert-PodePathSeparators -Path 'one/two\Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)two$([System.IO.Path]::DirectorySeparatorChar)Seperators" - Convert-PodePathSeparators -Path 'one\two/Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)two$([System.IO.Path]::DirectorySeparatorChar)Seperators" - } - } - - Context 'Array' { - It 'Null' { - Convert-PodePathSeparators -Path @($null) | Should -Be $null - Convert-PodePathSeparators -Path @($null, $null) | Should -Be $null - } - - It 'Single' { - Convert-PodePathSeparators -Path @('noSeperators') | Should -Be @('noSeperators') - Convert-PodePathSeparators -Path @('some/Seperators') | Should -Be @("some$([System.IO.Path]::DirectorySeparatorChar)Seperators") - Convert-PodePathSeparators -Path @('some\Seperators') | Should -Be @("some$([System.IO.Path]::DirectorySeparatorChar)Seperators") - - Convert-PodePathSeparators -Path @('') | Should -Be $null - Convert-PodePathSeparators -Path @(' ') | Should -Be $null - } - - It 'Double' { - Convert-PodePathSeparators -Path @('noSeperators1', 'noSeperators2') | Should -Be @('noSeperators1', 'noSeperators2') - Convert-PodePathSeparators -Path @('some/Seperators', 'some\Seperators') | Should -Be @("some$([System.IO.Path]::DirectorySeparatorChar)Seperators", "some$([System.IO.Path]::DirectorySeparatorChar)Seperators") - - Convert-PodePathSeparators -Path @('', ' ') | Should -Be $null - Convert-PodePathSeparators -Path @(' ', '') | Should -Be $null - } - } -} - Describe 'Out-PodeHost' { BeforeAll { Mock Out-Default {} diff --git a/tests/unit/Routes.Tests.ps1 b/tests/unit/Routes.Tests.ps1 index 88025a2f7..6f2dd7faa 100644 --- a/tests/unit/Routes.Tests.ps1 +++ b/tests/unit/Routes.Tests.ps1 @@ -638,121 +638,121 @@ Describe 'Add-PodePage' { } } -Describe 'Update-PodeRouteSlashes' { +Describe 'Update-PodeRouteSlash' { Context 'Static' { It 'Update route slashes' { $in = '/route' - Update-PodeRouteSlashes -Path $in -Static | Should -Be '/route[/]{0,1}(?.*)' + Update-PodeRouteSlash -Path $in -Static | Should -Be '/route[/]{0,1}(?.*)' } It 'Update route slashes, no slash' { $in = 'route' - Update-PodeRouteSlashes -Path $in -Static | Should -Be '/route[/]{0,1}(?.*)' + Update-PodeRouteSlash -Path $in -Static | Should -Be '/route[/]{0,1}(?.*)' } It 'Update route slashes, ending with wildcard' { $in = '/route/*' - Update-PodeRouteSlashes -Path $in -Static | Should -Be '/route[/]{0,1}(?.*)' + Update-PodeRouteSlash -Path $in -Static | Should -Be '/route[/]{0,1}(?.*)' } It 'Update route slashes, ending with wildcard, no slash' { $in = 'route/*' - Update-PodeRouteSlashes -Path $in -Static | Should -Be '/route[/]{0,1}(?.*)' + Update-PodeRouteSlash -Path $in -Static | Should -Be '/route[/]{0,1}(?.*)' } It 'Update route slashes, with midpoint wildcard' { $in = '/route/*/ending' - Update-PodeRouteSlashes -Path $in -Static | Should -Be '/route/.*/ending[/]{0,1}(?.*)' + Update-PodeRouteSlash -Path $in -Static | Should -Be '/route/.*/ending[/]{0,1}(?.*)' } It 'Update route slashes, with midpoint wildcard, no slash' { $in = 'route/*/ending' - Update-PodeRouteSlashes -Path $in -Static | Should -Be '/route/.*/ending[/]{0,1}(?.*)' + Update-PodeRouteSlash -Path $in -Static | Should -Be '/route/.*/ending[/]{0,1}(?.*)' } It 'Update route slashes, with midpoint wildcard, ending with wildcard' { $in = '/route/*/ending/*' - Update-PodeRouteSlashes -Path $in -Static | Should -Be '/route/.*/ending[/]{0,1}(?.*)' + Update-PodeRouteSlash -Path $in -Static | Should -Be '/route/.*/ending[/]{0,1}(?.*)' } It 'Update route slashes, with midpoint wildcard, ending with wildcard, no slash' { $in = 'route/*/ending/*' - Update-PodeRouteSlashes -Path $in -Static | Should -Be '/route/.*/ending[/]{0,1}(?.*)' + Update-PodeRouteSlash -Path $in -Static | Should -Be '/route/.*/ending[/]{0,1}(?.*)' } } Context 'Non Static' { It 'Update route slashes' { $in = '/route' - Update-PodeRouteSlashes -Path $in | Should -Be '/route' + Update-PodeRouteSlash -Path $in | Should -Be '/route' } It 'Update route slashes, no slash' { $in = 'route' - Update-PodeRouteSlashes -Path $in | Should -Be '/route' + Update-PodeRouteSlash -Path $in | Should -Be '/route' } It 'Update route slashes, ending with wildcard' { $in = '/route/*' - Update-PodeRouteSlashes -Path $in | Should -Be '/route/.*' + Update-PodeRouteSlash -Path $in | Should -Be '/route/.*' } It 'Update route slashes, ending with wildcard, no slash' { $in = 'route/*' - Update-PodeRouteSlashes -Path $in | Should -Be '/route/.*' + Update-PodeRouteSlash -Path $in | Should -Be '/route/.*' } It 'Update route slashes, with midpoint wildcard' { $in = '/route/*/ending' - Update-PodeRouteSlashes -Path $in | Should -Be '/route/.*/ending' + Update-PodeRouteSlash -Path $in | Should -Be '/route/.*/ending' } It 'Update route slashes, with midpoint wildcard, no slash' { $in = 'route/*/ending' - Update-PodeRouteSlashes -Path $in | Should -Be '/route/.*/ending' + Update-PodeRouteSlash -Path $in | Should -Be '/route/.*/ending' } It 'Update route slashes, with midpoint wildcard, ending with wildcard' { $in = '/route/*/ending/*' - Update-PodeRouteSlashes -Path $in | Should -Be '/route/.*/ending/.*' + Update-PodeRouteSlash -Path $in | Should -Be '/route/.*/ending/.*' } It 'Update route slashes, with midpoint wildcard, ending with wildcard, no slash' { $in = 'route/*/ending/*' - Update-PodeRouteSlashes -Path $in | Should -Be '/route/.*/ending/.*' + Update-PodeRouteSlash -Path $in | Should -Be '/route/.*/ending/.*' } } } -Describe 'Resolve-PodePlaceholders' { +Describe 'Resolve-PodePlaceholder' { It 'Update route placeholders, basic' { $in = 'route' - Resolve-PodePlaceholders -Path $in | Should -Be 'route' + Resolve-PodePlaceholder -Path $in | Should -Be 'route' } It 'Update route placeholders' { $in = ':route' - Resolve-PodePlaceholders -Path $in | Should -Be '(?[^\/]+?)' + Resolve-PodePlaceholder -Path $in | Should -Be '(?[^\/]+?)' } It 'Update route placeholders, double with no spacing' { $in = ':route:placeholder' - Resolve-PodePlaceholders -Path $in | Should -Be '(?[^\/]+?)(?[^\/]+?)' + Resolve-PodePlaceholder -Path $in | Should -Be '(?[^\/]+?)(?[^\/]+?)' } It 'Update route placeholders, double with double ::' { $in = '::route:placeholder' - Resolve-PodePlaceholders -Path $in | Should -Be ':(?[^\/]+?)(?[^\/]+?)' + Resolve-PodePlaceholder -Path $in | Should -Be ':(?[^\/]+?)(?[^\/]+?)' } It 'Update route placeholders, double with slash' { $in = ':route/:placeholder' - Resolve-PodePlaceholders -Path $in | Should -Be '(?[^\/]+?)/(?[^\/]+?)' + Resolve-PodePlaceholder -Path $in | Should -Be '(?[^\/]+?)/(?[^\/]+?)' } It 'Update route placeholders, no update' { $in = ': route' - Resolve-PodePlaceholders -Path $in | Should -Be ': route' + Resolve-PodePlaceholder -Path $in | Should -Be ': route' } } diff --git a/tests/unit/Schedules.Tests.ps1 b/tests/unit/Schedules.Tests.ps1 index 05e688db1..3c0cb49f0 100644 --- a/tests/unit/Schedules.Tests.ps1 +++ b/tests/unit/Schedules.Tests.ps1 @@ -35,7 +35,6 @@ Describe 'Find-PodeSchedule' { Describe 'Add-PodeSchedule' { BeforeAll { - Mock 'ConvertFrom-PodeCronExpression' { @{} } Mock 'Get-PodeCronNextEarliestTrigger' { [datetime]::new(2020, 1, 1) } } It 'Throws error because schedule already exists' { diff --git a/tests/unit/Server.Tests.ps1 b/tests/unit/Server.Tests.ps1 index ff9bd1327..be0967f91 100644 --- a/tests/unit/Server.Tests.ps1 +++ b/tests/unit/Server.Tests.ps1 @@ -18,7 +18,7 @@ Describe 'Start-PodeInternalServer' { Mock Add-PodePSInbuiltDrive { } Mock Invoke-PodeScriptBlock { } Mock New-PodeRunspaceState { } - Mock New-PodeRunspacePools { } + Mock New-PodeRunspacePool { } Mock Start-PodeLoggingRunspace { } Mock Start-PodeTimerRunspace { } Mock Start-PodeScheduleRunspace { } @@ -43,7 +43,7 @@ Describe 'Start-PodeInternalServer' { Start-PodeInternalServer | Out-Null Assert-MockCalled Invoke-PodeScriptBlock -Times 1 -Scope It - Assert-MockCalled New-PodeRunspacePools -Times 1 -Scope It + Assert-MockCalled New-PodeRunspacePool -Times 1 -Scope It Assert-MockCalled New-PodeRunspaceState -Times 1 -Scope It Assert-MockCalled Start-PodeTimerRunspace -Times 1 -Scope It Assert-MockCalled Start-PodeScheduleRunspace -Times 1 -Scope It @@ -57,7 +57,7 @@ Describe 'Start-PodeInternalServer' { Start-PodeInternalServer | Out-Null Assert-MockCalled Invoke-PodeScriptBlock -Times 1 -Scope It - Assert-MockCalled New-PodeRunspacePools -Times 1 -Scope It + Assert-MockCalled New-PodeRunspacePool -Times 1 -Scope It Assert-MockCalled New-PodeRunspaceState -Times 1 -Scope It Assert-MockCalled Start-PodeTimerRunspace -Times 1 -Scope It Assert-MockCalled Start-PodeScheduleRunspace -Times 1 -Scope It @@ -71,7 +71,7 @@ Describe 'Start-PodeInternalServer' { Start-PodeInternalServer | Out-Null Assert-MockCalled Invoke-PodeScriptBlock -Times 1 -Scope It - Assert-MockCalled New-PodeRunspacePools -Times 1 -Scope It + Assert-MockCalled New-PodeRunspacePool -Times 1 -Scope It Assert-MockCalled New-PodeRunspaceState -Times 1 -Scope It Assert-MockCalled Start-PodeTimerRunspace -Times 1 -Scope It Assert-MockCalled Start-PodeScheduleRunspace -Times 1 -Scope It @@ -85,7 +85,7 @@ Describe 'Start-PodeInternalServer' { Start-PodeInternalServer | Out-Null Assert-MockCalled Invoke-PodeScriptBlock -Times 1 -Scope It - Assert-MockCalled New-PodeRunspacePools -Times 1 -Scope It + Assert-MockCalled New-PodeRunspacePool -Times 1 -Scope It Assert-MockCalled New-PodeRunspaceState -Times 1 -Scope It Assert-MockCalled Start-PodeTimerRunspace -Times 1 -Scope It Assert-MockCalled Start-PodeScheduleRunspace -Times 1 -Scope It @@ -98,8 +98,8 @@ Describe 'Start-PodeInternalServer' { Describe 'Restart-PodeInternalServer' { BeforeAll { Mock Write-Host { } - Mock Close-PodeRunspaces { } - Mock Remove-PodePSDrives { } + Mock Close-PodeRunspace { } + Mock Remove-PodePSDrive { } Mock Open-PodeConfiguration { return $null } Mock Start-PodeInternalServer { } Mock Write-PodeErrorLog { } diff --git a/tests/unit/Serverless.Tests.ps1 b/tests/unit/Serverless.Tests.ps1 index 6366d7895..1f44d23f4 100644 --- a/tests/unit/Serverless.Tests.ps1 +++ b/tests/unit/Serverless.Tests.ps1 @@ -23,7 +23,7 @@ Describe 'Start-PodeAzFuncServer' { Mock Invoke-PodeEndware { } Mock Set-PodeServerHeader { } Mock Set-PodeResponseStatus { } - Mock Update-PodeServerRequestMetrics { } + Mock Update-PodeServerRequestMetric { } } It 'Throws error for null data' { { Start-PodeAzFuncServer -Data $null } | Should -Throw -ExpectedMessage '*because it is null*' @@ -154,7 +154,7 @@ Describe 'Start-PodeAwsLambdaServer' { Mock Invoke-PodeEndware { } Mock Set-PodeServerHeader { } Mock Set-PodeResponseStatus { } - Mock Update-PodeServerRequestMetrics { } } + Mock Update-PodeServerRequestMetric { } } It 'Throws error for null data' { { Start-PodeAwsLambdaServer -Data $null } | Should -Throw -ExpectedMessage '*because it is null*' diff --git a/tests/unit/UnusedHelpers.Tests.ps1 b/tests/unit/UnusedHelpers.Tests.ps1 new file mode 100644 index 000000000..cd2cb53a9 --- /dev/null +++ b/tests/unit/UnusedHelpers.Tests.ps1 @@ -0,0 +1,62 @@ +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param() +BeforeAll { + $path = $PSCommandPath + $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' + Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } +} + + +Describe 'Convert-PodePathSeparator' { + Context 'Null' { + It 'Null' { + Convert-PodePathSeparator -Path $null | Should -Be $null + } + } + + Context 'String' { + It 'Empty' { + Convert-PodePathSeparator -Path '' | Should -Be $null + Convert-PodePathSeparator -Path ' ' | Should -Be $null + } + + It 'Value' { + Convert-PodePathSeparator -Path 'anyValue' | Should -Be 'anyValue' + Convert-PodePathSeparator -Path 1 | Should -Be 1 + } + + It 'Path' { + Convert-PodePathSeparator -Path 'one/Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)Seperators" + Convert-PodePathSeparator -Path 'one\Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)Seperators" + + Convert-PodePathSeparator -Path 'one/two/Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)two$([System.IO.Path]::DirectorySeparatorChar)Seperators" + Convert-PodePathSeparator -Path 'one\two\Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)two$([System.IO.Path]::DirectorySeparatorChar)Seperators" + Convert-PodePathSeparator -Path 'one/two\Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)two$([System.IO.Path]::DirectorySeparatorChar)Seperators" + Convert-PodePathSeparator -Path 'one\two/Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)two$([System.IO.Path]::DirectorySeparatorChar)Seperators" + } + } + + Context 'Array' { + It 'Null' { + Convert-PodePathSeparator -Path @($null) | Should -Be $null + Convert-PodePathSeparator -Path @($null, $null) | Should -Be $null + } + + It 'Single' { + Convert-PodePathSeparator -Path @('noSeperators') | Should -Be @('noSeperators') + Convert-PodePathSeparator -Path @('some/Seperators') | Should -Be @("some$([System.IO.Path]::DirectorySeparatorChar)Seperators") + Convert-PodePathSeparator -Path @('some\Seperators') | Should -Be @("some$([System.IO.Path]::DirectorySeparatorChar)Seperators") + + Convert-PodePathSeparator -Path @('') | Should -Be $null + Convert-PodePathSeparator -Path @(' ') | Should -Be $null + } + + It 'Double' { + Convert-PodePathSeparator -Path @('noSeperators1', 'noSeperators2') | Should -Be @('noSeperators1', 'noSeperators2') + Convert-PodePathSeparator -Path @('some/Seperators', 'some\Seperators') | Should -Be @("some$([System.IO.Path]::DirectorySeparatorChar)Seperators", "some$([System.IO.Path]::DirectorySeparatorChar)Seperators") + + Convert-PodePathSeparator -Path @('', ' ') | Should -Be $null + Convert-PodePathSeparator -Path @(' ', '') | Should -Be $null + } + } +} From 7bd18faa58e2b34381cf307ba11d1697f89b7091 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Mon, 13 May 2024 15:06:12 -0700 Subject: [PATCH 002/177] 2nd drop --- src/Private/Authentication.ps1 | 4 +- src/Private/AutoImport.ps1 | 2 +- src/Private/Context.ps1 | 16 +-- src/Private/Endpoints.ps1 | 14 +-- src/Private/Helpers.ps1 | 71 ++++++++++-- src/Private/Middleware.ps1 | 2 +- src/Private/OpenApi.ps1 | 4 +- src/Private/PodeServer.ps1 | 10 +- src/Private/Security.ps1 | 199 ++++++++++++++++++++++++++++++++- src/Private/SmtpServer.ps1 | 2 +- src/Private/Streams.ps1 | 25 +---- src/Private/TcpServer.ps1 | 2 +- src/Private/UnusedHelper.ps1 | 27 ----- src/Public/Metrics.ps1 | 4 +- src/Public/Responses.ps1 | 2 +- src/Public/Security.ps1 | 157 +------------------------- 16 files changed, 305 insertions(+), 236 deletions(-) diff --git a/src/Private/Authentication.ps1 b/src/Private/Authentication.ps1 index 377dad84e..c202ba710 100644 --- a/src/Private/Authentication.ps1 +++ b/src/Private/Authentication.ps1 @@ -139,7 +139,7 @@ function Get-PodeAuthOAuth2Type { $result = Invoke-RestMethod -Method Post -Uri $options.Urls.Token -Body $body -ContentType 'application/x-www-form-urlencoded' -ErrorAction Stop } catch [System.Net.WebException], [System.Net.Http.HttpRequestException] { - $response = Read-PodeWebExceptionDetail -ErrorRecord $_ + $response = Read-PodeWebExceptionInfo -ErrorRecord $_ $result = ($response.Body | ConvertFrom-Json) } @@ -158,7 +158,7 @@ function Get-PodeAuthOAuth2Type { $user = Invoke-RestMethod -Method $options.Urls.User.Method -Uri $options.Urls.User.Url -Headers @{ Authorization = "Bearer $($result.access_token)" } } catch [System.Net.WebException], [System.Net.Http.HttpRequestException] { - $response = Read-PodeWebExceptionDetail -ErrorRecord $_ + $response = Read-PodeWebExceptionInfo -ErrorRecord $_ $user = ($response.Body | ConvertFrom-Json) } diff --git a/src/Private/AutoImport.ps1 b/src/Private/AutoImport.ps1 index a618711ea..0f9c07454 100644 --- a/src/Private/AutoImport.ps1 +++ b/src/Private/AutoImport.ps1 @@ -70,7 +70,7 @@ function Import-PodeModulesIntoRunspaceState { # work out which order the modules need to be loaded $modulesOrder = @(foreach ($module in $modules) { - Get-PodeModuleDependency -Module $module + Get-PodeModuleDependencyList -Module $module }) | Where-Object { ($_.Name -inotin @('pode', 'pode.internal')) -and ($_.Name -inotlike 'microsoft.powershell.*') diff --git a/src/Private/Context.ps1 b/src/Private/Context.ps1 index 88869c4f5..d7139aedd 100644 --- a/src/Private/Context.ps1 +++ b/src/Private/Context.ps1 @@ -549,7 +549,7 @@ function New-PodeRunspacePool { } # web runspace - if we have any http/s endpoints - if (Test-PodeEndpoint -Type Http) { + if (Test-PodeEndpointByProtocolType -Type Http) { $PodeContext.RunspacePools.Web = @{ Pool = [runspacefactory]::CreateRunspacePool(1, ($PodeContext.Threads.General + 1), $PodeContext.RunspaceState, $Host) State = 'Waiting' @@ -557,7 +557,7 @@ function New-PodeRunspacePool { } # smtp runspace - if we have any smtp endpoints - if (Test-PodeEndpoint -Type Smtp) { + if (Test-PodeEndpointByProtocolType -Type Smtp) { $PodeContext.RunspacePools.Smtp = @{ Pool = [runspacefactory]::CreateRunspacePool(1, ($PodeContext.Threads.General + 1), $PodeContext.RunspaceState, $Host) State = 'Waiting' @@ -565,7 +565,7 @@ function New-PodeRunspacePool { } # tcp runspace - if we have any tcp endpoints - if (Test-PodeEndpoint -Type Tcp) { + if (Test-PodeEndpointByProtocolType -Type Tcp) { $PodeContext.RunspacePools.Tcp = @{ Pool = [runspacefactory]::CreateRunspacePool(1, ($PodeContext.Threads.General + 1), $PodeContext.RunspaceState, $Host) State = 'Waiting' @@ -573,7 +573,7 @@ function New-PodeRunspacePool { } # signals runspace - if we have any ws/s endpoints - if (Test-PodeEndpoint -Type Ws) { + if (Test-PodeEndpointByProtocolType -Type Ws) { $PodeContext.RunspacePools.Signals = @{ Pool = [runspacefactory]::CreateRunspacePool(1, ($PodeContext.Threads.General + 2), $PodeContext.RunspaceState, $Host) State = 'Waiting' @@ -641,7 +641,7 @@ function Open-PodeRunspacePool { } $start = [datetime]::Now - Write-Verbose 'Opening RunspacePool' + Write-Verbose 'Opening RunspacePools' # open pools async foreach ($key in $PodeContext.RunspacePools.Keys) { @@ -690,7 +690,7 @@ function Open-PodeRunspacePool { } } - Write-Verbose "RunspacePool opened [duration: $(([datetime]::Now - $start).TotalSeconds)s]" + Write-Verbose "RunspacePools opened [duration: $(([datetime]::Now - $start).TotalSeconds)s]" } <# @@ -709,7 +709,7 @@ function Close-PodeRunspacePool { } $start = [datetime]::Now - Write-Verbose 'Closing RunspacePool' + Write-Verbose 'Closing RunspacePools' # close pools async foreach ($key in $PodeContext.RunspacePools.Keys) { @@ -766,7 +766,7 @@ function Close-PodeRunspacePool { Close-PodeDisposable -Disposable $item.Pool } - Write-Verbose "RunspacePool closed [duration: $(([datetime]::Now - $start).TotalSeconds)s]" + Write-Verbose "RunspacePools closed [duration: $(([datetime]::Now - $start).TotalSeconds)s]" } function New-PodeStateContext { diff --git a/src/Private/Endpoints.ps1 b/src/Private/Endpoints.ps1 index 307482bf3..1e8314d67 100644 --- a/src/Private/Endpoints.ps1 +++ b/src/Private/Endpoints.ps1 @@ -82,7 +82,7 @@ function Find-PodeEndpoint { Retrieves internal endpoints based on the specified types. .DESCRIPTION - The `Get-PodeEndpointInternal` function returns internal endpoints from the PodeContext + The `Get-PodeEndpointByProtocolType` function returns internal endpoints from the PodeContext based on the specified types (HTTP, WebSocket, SMTP, or TCP). .PARAMETER Type @@ -94,14 +94,14 @@ function Find-PodeEndpoint { .EXAMPLE # Example usage: - $httpEndpoints = Get-PodeEndpointInternal -Type 'Http' - $wsEndpoints = Get-PodeEndpointInternal -Type 'Ws' + $httpEndpoints = Get-PodeEndpointByProtocolType -Type 'Http' + $wsEndpoints = Get-PodeEndpointByProtocolType -Type 'Ws' # Retrieve HTTP and WebSocket endpoints from the PodeContext. .NOTES This is an internal function and may change in future releases of Pode. #> -function Get-PodeEndpointInternal { +function Get-PodeEndpointByProtocolType { [CmdletBinding()] [OutputType([object[]])] param( @@ -136,7 +136,7 @@ function Get-PodeEndpointInternal { return $endpoints } -function Test-PodeEndpointProtocol { +function Test-PodeEndpointByProtocolTypeProtocol { param( [Parameter(Mandatory = $true)] [ValidateSet('Http', 'Https', 'Ws', 'Wss', 'Smtp', 'Smtps', 'Tcp', 'Tcps')] @@ -226,7 +226,7 @@ A boolean value (True if endpoints exist, False otherwise). .NOTES This is an internal function and may change in future releases of Pode. #> -function Test-PodeEndpoint { +function Test-PodeEndpointByProtocolType { [CmdletBinding()] [OutputType([bool])] param( @@ -236,7 +236,7 @@ function Test-PodeEndpoint { $Type ) - $endpoints = (Get-PodeEndpointInternal -Type $Type) + $endpoints = (Get-PodeEndpointByProtocolType -Type $Type) return (($null -ne $endpoints) -and ($endpoints.Length -gt 0)) } diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index d8abdda43..eba93770e 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -2459,7 +2459,7 @@ function Test-PodeModuleInPath { .EXAMPLE $module = Get-Module -Name SomeModuleName - $dependencies = Get-PodeModuleDependency -Module $module + $dependencies = Get-PodeModuleDependencyList -Module $module This example retrieves all dependencies for "SomeModuleName". .OUTPUTS @@ -2467,7 +2467,7 @@ function Test-PodeModuleInPath { Returns an array of psmoduleinfo objects, each representing a module in the dependency tree. #> -function Get-PodeModuleDependency { +function Get-PodeModuleDependencyList { param( [Parameter(Mandatory = $true)] [psmoduleinfo] @@ -2476,7 +2476,7 @@ function Get-PodeModuleDependency { # Check if the module has any required modules (dependencies). if (!$Module.RequiredModules) { - return $Module # + return $Module } # Initialize an array to hold all dependencies. $mods = @() @@ -2484,7 +2484,7 @@ function Get-PodeModuleDependency { # Iterate through each required module and recursively retrieve their dependencies. foreach ($mod in $Module.RequiredModules) { # Recursive call for each dependency. - $mods += (Get-PodeModuleDependency -Module $mod) + $mods += (Get-PodeModuleDependencyList -Module $mod) } # Return the list of all dependencies plus the original module. @@ -3115,7 +3115,7 @@ function Get-PodeFunctionsFromScriptBlock { Reads details from a web exception and returns relevant information. .DESCRIPTION - The `Read-PodeWebExceptionDetail` function processes a web exception (either `WebException` or `HttpRequestException`) + The `Read-PodeWebExceptionInfo` function processes a web exception (either `WebException` or `HttpRequestException`) and extracts relevant details such as status code, status description, and response body. .PARAMETER ErrorRecord @@ -3129,13 +3129,13 @@ function Get-PodeFunctionsFromScriptBlock { .EXAMPLE # Example usage: $errorRecord = Get-ErrorRecordFromWebException - $details = Read-PodeWebExceptionDetail -ErrorRecord $errorRecord + $details = Read-PodeWebExceptionInfo -ErrorRecord $errorRecord # Returns a hashtable with status code, description, and response body. .NOTES This is an internal function and may change in future releases of Pode #> -function Read-PodeWebExceptionDetail { +function Read-PodeWebExceptionInfo { [CmdletBinding()] [OutputType([hashtable])] param( @@ -3860,4 +3860,61 @@ function ConvertTo-PodeYamlInternal { throw "Error'$($_)' in script $($_.InvocationInfo.ScriptName) $($_.InvocationInfo.Line.Trim()) (line $($_.InvocationInfo.ScriptLineNumber)) char $($_.InvocationInfo.OffsetInLine) executing $($_.InvocationInfo.MyCommand) on $type object '$($InputObject)' Class: $($InputObject.GetType().Name) BaseClass: $($InputObject.GetType().BaseType.Name) " } } +} +<# +.SYNOPSIS + Opens a runspace for Pode server operations based on the specified type. + +.DESCRIPTION + This function initializes a runspace for Pode server tasks by importing necessary + modules, adding PowerShell drives, and setting the state of the runspace pool to 'Ready'. + If an error occurs during the initialization, the state is adjusted to 'Error' if it + was previously set to 'waiting', and the error details are outputted. + +.PARAMETER Type + The type of the runspace pool to open. This parameter only accepts predefined values, + ensuring the runspace pool corresponds to a supported server operation type. The valid + types are: Main, Signals, Schedules, Gui, Web, Smtp, Tcp, Tasks, WebSockets, Files. + +.EXAMPLE + Open-PodeRunspace -Type "Web" + + Opens a runspace for the 'Web' type, setting it ready for handling web server tasks. + +.NOTES + This function is not invoked directly but indirectly by `Add-PodeRunspace` function using + $null = $ps.AddScript("Open-PodeRunspace -Type '$($Type)'") +#> + +function Open-PodeRunspace { + param( + [Parameter(Mandatory = $true)] + [ValidateSet('Main', 'Signals', 'Schedules', 'Gui', 'Web', 'Smtp', 'Tcp', 'Tasks', 'WebSockets', 'Files')] + [string] + $Type + ) + + try { + # Importing internal Pode modules necessary for the runspace operations. + Import-PodeModulesInternal + + # Adding PowerShell drives required by the runspace. + Add-PodePSDrivesInternal + + # Setting the state of the runspace pool to 'Ready', indicating it is ready to process requests. + $PodeContext.RunspacePools[$Type].State = 'Ready' + } + catch { + # If an error occurs and the current state is 'waiting', set it to 'Error'. + if ($PodeContext.RunspacePools[$Type].State -ieq 'waiting') { + $PodeContext.RunspacePools[$Type].State = 'Error' + } + + # Outputting the error to the default output stream, including the stack trace. + $_ | Out-Default + $_.ScriptStackTrace | Out-Default + + # Rethrowing the error to be handled further up the call stack. + throw + } } \ No newline at end of file diff --git a/src/Private/Middleware.ps1 b/src/Private/Middleware.ps1 index ac72b5716..f633d7e4c 100644 --- a/src/Private/Middleware.ps1 +++ b/src/Private/Middleware.ps1 @@ -167,7 +167,7 @@ function Get-PodeLimitMiddleware { } # check the endpoint - if (!(Test-PodeEndpointLimit -EndpointName $WebEvent.Endpoint.Name)) { + if (!(Test-PodeEndpointByProtocolTypeLimit -EndpointName $WebEvent.Endpoint.Name)) { Set-PodeResponseStatus -Code 429 return $false } diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index 67fd8a4b4..6d6227d1a 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -1542,11 +1542,11 @@ function Resolve-PodeOAReference { } 'oneof' { # Throw an error for unsupported schema constructs to notify the user - throw "Validation of schema with `$key is not supported" + throw "Validation of schema with $key is not supported" } 'anyof' { # Throw an error for unsupported schema constructs to notify the user - throw "Validation of schema with `$key is not supported" + throw "Validation of schema with $key is not supported" } } } diff --git a/src/Private/PodeServer.ps1 b/src/Private/PodeServer.ps1 index 44cae39ff..69dc7107c 100644 --- a/src/Private/PodeServer.ps1 +++ b/src/Private/PodeServer.ps1 @@ -24,7 +24,7 @@ function Start-PodeWebServer { $endpoints = @() $endpointsMap = @{} - @(Get-PodeEndpointInternal -Type Http, Ws) | ForEach-Object { + @(Get-PodeEndpointByProtocolType -Type Http, Ws) | ForEach-Object { # get the ip address $_ip = [string]($_.Address) $_ip = Get-PodeIPAddressesForHostname -Hostname $_ip -Type All | Select-Object -First 1 @@ -103,7 +103,7 @@ function Start-PodeWebServer { } # only if HTTP endpoint - if (Test-PodeEndpoint -Type Http) { + if (Test-PodeEndpointByProtocolType -Type Http) { # script for listening out for incoming requests $listenScript = { param( @@ -285,7 +285,7 @@ function Start-PodeWebServer { } # only if WS endpoint - if (Test-PodeEndpoint -Type Ws) { + if (Test-PodeEndpointByProtocolType -Type Ws) { # script to write messages back to the client(s) $signalScript = { param( @@ -359,7 +359,7 @@ function Start-PodeWebServer { } # only if WS endpoint - if (Test-PodeEndpoint -Type Ws) { + if (Test-PodeEndpointByProtocolType -Type Ws) { # script to queue messages from clients to send back to other clients from the server $clientScript = { param( @@ -469,7 +469,7 @@ function Start-PodeWebServer { } $waitType = 'Web' - if (!(Test-PodeEndpoint -Type Http)) { + if (!(Test-PodeEndpointByProtocolType -Type Http)) { $waitType = 'Signals' } diff --git a/src/Private/Security.ps1 b/src/Private/Security.ps1 index 559f672d0..4cebcbbe6 100644 --- a/src/Private/Security.ps1 +++ b/src/Private/Security.ps1 @@ -180,7 +180,7 @@ function Test-PodeRouteLimit { } } -function Test-PodeEndpointLimit { +function Test-PodeEndpointByProtocolTypeLimit { param( [Parameter()] [string] @@ -1094,4 +1094,201 @@ function Protect-PodePermissionsPolicyKeyword { }) return "$($Name)=($($values -join ' '))" +} + + +<# +.SYNOPSIS +Sets the Content Security Policy (CSP) header for a Pode web server. + +.DESCRIPTION +The `Set-PodeSecurityContentSecurityPolicyInternal` function constructs and sets the Content Security Policy (CSP) header based on the provided parameters. The function supports an optional switch to append the header value and explicitly disables XSS auditors in modern browsers to prevent vulnerabilities. + +.PARAMETER Params +A hashtable containing the various CSP directives to be set. + +.PARAMETER Append +A switch indicating whether to append the header value. + +.EXAMPLE +$policyParams = @{ + Default = "'self'" + ScriptSrc = "'self' 'unsafe-inline'" + StyleSrc = "'self' 'unsafe-inline'" +} +Set-PodeSecurityContentSecurityPolicyInternal -Params $policyParams + +.EXAMPLE +$policyParams = @{ + Default = "'self'" + ImgSrc = "'self' data:" + ConnectSrc = "'self' https://api.example.com" + UpgradeInsecureRequests = $true +} +Set-PodeSecurityContentSecurityPolicyInternal -Params $policyParams -Append + +.NOTES +This is an internal function and may change in future releases of Pode. +#> + +function Set-PodeSecurityContentSecurityPolicyInternal { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSPossibleIncorrectComparisonWithNull', '')] + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [hashtable] + $Params, + + [Parameter()] + [switch] + $Append + ) + + # build the header's value + $values = @( + Protect-PodeContentSecurityKeyword -Name 'default-src' -Value $Params.Default + Protect-PodeContentSecurityKeyword -Name 'child-src' -Value $Params.Child + Protect-PodeContentSecurityKeyword -Name 'connect-src' -Value $Params.Connect + Protect-PodeContentSecurityKeyword -Name 'font-src' -Value $Params.Font + Protect-PodeContentSecurityKeyword -Name 'frame-src' -Value $Params.Frame + Protect-PodeContentSecurityKeyword -Name 'img-src' -Value $Params.Image + Protect-PodeContentSecurityKeyword -Name 'manifest-src' -Value $Params.Manifest + Protect-PodeContentSecurityKeyword -Name 'media-src' -Value $Params.Media + Protect-PodeContentSecurityKeyword -Name 'object-src' -Value $Params.Object + Protect-PodeContentSecurityKeyword -Name 'script-src' -Value $Params.Scripts + Protect-PodeContentSecurityKeyword -Name 'style-src' -Value $Params.Style + Protect-PodeContentSecurityKeyword -Name 'base-uri' -Value $Params.BaseUri + Protect-PodeContentSecurityKeyword -Name 'form-action' -Value $Params.FormAction + Protect-PodeContentSecurityKeyword -Name 'frame-ancestors' -Value $Params.FrameAncestor + ) + + if ($Params.Sandbox -ine 'None') { + $values += "sandbox $($Params.Sandbox.ToLowerInvariant())".Trim() + } + + if ($Params.UpgradeInsecureRequests) { + $values += 'upgrade-insecure-requests' + } + + # Filter out $null values from the $values array using the array filter `-ne $null`. This approach + # is equivalent to using `$values | Where-Object { $_ -ne $null }` but is more efficient. The `-ne $null` + # operator is faster because it is a direct array operation that internally skips the overhead of + # piping through a cmdlet and processing each item individually. + $values = ($values -ne $null) + # Filter out $null values from the $values array using the array filter `-ne $null`. This approach + # is equivalent to using `$values | Where-Object { $_ -ne $null }` but is more efficient. The `-ne $null` + # operator is faster because it is a direct array operation that internally skips the overhead of + # piping through a cmdlet and processing each item individually. + $value = ($values -join '; ') + + # Add the Content Security Policy header to the response or relevant context. This cmdlet + # sets the HTTP header with the name 'Content-Security-Policy' and the constructed value. + + Add-PodeSecurityHeader -Name 'Content-Security-Policy' -Value $value -Append $Append + + # this is done to explicitly disable XSS auditors in modern browsers + # as having it enabled has now been found to cause more vulnerabilities + if ($Params.XssBlock) { + Add-PodeSecurityHeader -Name 'X-XSS-Protection' -Value '1; mode=block' + } + else { + Add-PodeSecurityHeader -Name 'X-XSS-Protection' -Value '0' + } +} + + +<# +.SYNOPSIS +Sets the Permissions Policy header for a Pode web server. + +.DESCRIPTION +The `Set-PodeSecurityPermissionsPolicy` function constructs and sets the Permissions Policy header based on the provided parameters. The function supports an optional switch to append the header value. + +.PARAMETER Params +A hashtable containing the various permissions policies to be set. + +.PARAMETER Append +A switch indicating whether to append the header value. + +.EXAMPLE +$policyParams = @{ + Accelerometer = 'none' + Camera = 'self' + Microphone = '*' +} +Set-PodeSecurityPermissionsPolicy -Params $policyParams + +.EXAMPLE +$policyParams = @{ + Autoplay = 'self' + Geolocation = 'none' +} +Set-PodeSecurityPermissionsPolicy -Params $policyParams -Append + +.NOTES +This is an internal function and may change in future releases of Pode. +#> + +function Set-PodeSecurityPermissionsPolicy { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSPossibleIncorrectComparisonWithNull', '')] + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [hashtable] + $Params, + + [Parameter()] + [switch] + $Append + ) + + # build the header's value + $values = @( + Protect-PodePermissionsPolicyKeyword -Name 'accelerometer' -Value $Params.Accelerometer + Protect-PodePermissionsPolicyKeyword -Name 'ambient-light-sensor' -Value $Params.AmbientLightSensor + Protect-PodePermissionsPolicyKeyword -Name 'autoplay' -Value $Params.Autoplay + Protect-PodePermissionsPolicyKeyword -Name 'battery' -Value $Params.Battery + Protect-PodePermissionsPolicyKeyword -Name 'camera' -Value $Params.Camera + Protect-PodePermissionsPolicyKeyword -Name 'display-capture' -Value $Params.DisplayCapture + Protect-PodePermissionsPolicyKeyword -Name 'document-domain' -Value $Params.DocumentDomain + Protect-PodePermissionsPolicyKeyword -Name 'encrypted-media' -Value $Params.EncryptedMedia + Protect-PodePermissionsPolicyKeyword -Name 'fullscreen' -Value $Params.Fullscreen + Protect-PodePermissionsPolicyKeyword -Name 'gamepad' -Value $Params.Gamepad + Protect-PodePermissionsPolicyKeyword -Name 'geolocation' -Value $Params.Geolocation + Protect-PodePermissionsPolicyKeyword -Name 'gyroscope' -Value $Params.Gyroscope + Protect-PodePermissionsPolicyKeyword -Name 'interest-cohort' -Value $Params.InterestCohort + Protect-PodePermissionsPolicyKeyword -Name 'layout-animations' -Value $Params.LayoutAnimations + Protect-PodePermissionsPolicyKeyword -Name 'legacy-image-formats' -Value $Params.LegacyImageFormats + Protect-PodePermissionsPolicyKeyword -Name 'magnetometer' -Value $Params.Magnetometer + Protect-PodePermissionsPolicyKeyword -Name 'microphone' -Value $Params.Microphone + Protect-PodePermissionsPolicyKeyword -Name 'midi' -Value $Params.Midi + Protect-PodePermissionsPolicyKeyword -Name 'oversized-images' -Value $Params.OversizedImages + Protect-PodePermissionsPolicyKeyword -Name 'payment' -Value $Params.Payment + Protect-PodePermissionsPolicyKeyword -Name 'picture-in-picture' -Value $Params.PictureInPicture + Protect-PodePermissionsPolicyKeyword -Name 'publickey-credentials-get' -Value $Params.PublicKeyCredentials + Protect-PodePermissionsPolicyKeyword -Name 'speaker-selection' -Value $Params.Speakers + Protect-PodePermissionsPolicyKeyword -Name 'sync-xhr' -Value $Params.SyncXhr + Protect-PodePermissionsPolicyKeyword -Name 'unoptimized-images' -Value $Params.UnoptimisedImages + Protect-PodePermissionsPolicyKeyword -Name 'unsized-media' -Value $Params.UnsizedMedia + Protect-PodePermissionsPolicyKeyword -Name 'usb' -Value $Params.Usb + Protect-PodePermissionsPolicyKeyword -Name 'screen-wake-lock' -Value $Params.ScreenWakeLake + Protect-PodePermissionsPolicyKeyword -Name 'web-share' -Value $Params.WebShare + Protect-PodePermissionsPolicyKeyword -Name 'xr-spatial-tracking' -Value $Params.XrSpatialTracking + ) + + # Filter out $null values from the $values array using the array filter `-ne $null`. This approach + # is equivalent to using `$values | Where-Object { $_ -ne $null }` but is more efficient. The `-ne $null` + # operator is faster because it is a direct array operation that internally skips the overhead of + # piping through a cmdlet and processing each item individually. + $values = ($values -ne $null) + + # Filter out $null values from the $values array using the array filter `-ne $null`. This approach + # is equivalent to using `$values | Where-Object { $_ -ne $null }` but is more efficient. The `-ne $null` + # operator is faster because it is a direct array operation that internally skips the overhead of + # piping through a cmdlet and processing each item individually. + $value = ($values -join ', ') + + # Add the constructed Permissions Policy header to the response or relevant context. This cmdlet + # sets the HTTP header with the name 'Permissions-Policy' and the constructed value. + Add-PodeSecurityHeader -Name 'Permissions-Policy' -Value $value -Append $Append } \ No newline at end of file diff --git a/src/Private/SmtpServer.ps1 b/src/Private/SmtpServer.ps1 index 3a356515f..87f08b9c5 100644 --- a/src/Private/SmtpServer.ps1 +++ b/src/Private/SmtpServer.ps1 @@ -9,7 +9,7 @@ function Start-PodeSmtpServer { # work out which endpoints to listen on $endpoints = @() - @(Get-PodeEndpointInternal -Type Smtp) | ForEach-Object { + @(Get-PodeEndpointByProtocolType -Type Smtp) | ForEach-Object { # get the ip address $_ip = [string]($_.Address) $_ip = Get-PodeIPAddressesForHostname -Hostname $_ip -Type All | Select-Object -First 1 diff --git a/src/Private/Streams.ps1 b/src/Private/Streams.ps1 index 5946760c2..98bbf9d22 100644 --- a/src/Private/Streams.ps1 +++ b/src/Private/Streams.ps1 @@ -98,7 +98,7 @@ function Get-PodeByteLinesFromByteArray { Converts a stream to a byte array. .DESCRIPTION - The `ConvertFrom-PodeStreamToByte` function reads data from a stream and converts it to a byte array. + The `ConvertFrom-PodeValueToByteArray` function reads data from a stream and converts it to a byte array. It's useful for scenarios where you need to work with binary data from a stream. .PARAMETER Stream @@ -111,13 +111,13 @@ function Get-PodeByteLinesFromByteArray { # Example usage: # Read data from a file stream and convert it to a byte array $stream = [System.IO.File]::OpenRead("C:\path\to\file.bin") - $byteArray = ConvertFrom-PodeStreamToByte -Stream $stream + $byteArray = ConvertFrom-PodeValueToByteArray -Stream $stream $stream.Close() .NOTES This is an internal function and may change in future releases of Pode. #> -function ConvertFrom-PodeStreamToByte { +function ConvertFrom-PodeValueToByteArray { param( [Parameter(Mandatory = $true)] $Stream @@ -142,7 +142,7 @@ function ConvertFrom-PodeStreamToByte { Converts a string value to a byte array using the specified encoding. .DESCRIPTION - The `ConvertFrom-PodeValueToByte` function takes a string value and converts it to a byte array. + The `ConvertFrom-PodeValueToByteArray` function takes a string value and converts it to a byte array. You can specify the desired encoding (default is UTF-8). .PARAMETER Value @@ -158,26 +158,13 @@ function ConvertFrom-PodeStreamToByte { .EXAMPLE # Example usage: $inputString = "Hello, world!" - $byteArray = ConvertFrom-PodeValueToByte -Value $inputString + $byteArray = ConvertFrom-PodeValueToByteArray -Value $inputString # Now you can work with the byte array as needed. .NOTES This is an internal function and may change in future releases of Pode. #> -function ConvertFrom-PodeValueToByte { - param( - [Parameter()] - [string] - $Value, - - [Parameter()] - $Encoding = [System.Text.Encoding]::UTF8 - ) - - return $Encoding.GetBytes($Value) -} - -function ConvertFrom-PodeValueToByte { +function ConvertFrom-PodeValueToByteArray { param( [Parameter()] [string] diff --git a/src/Private/TcpServer.ps1 b/src/Private/TcpServer.ps1 index 9de07e93a..06797fcf0 100644 --- a/src/Private/TcpServer.ps1 +++ b/src/Private/TcpServer.ps1 @@ -4,7 +4,7 @@ function Start-PodeTcpServer { # work out which endpoints to listen on $endpoints = @() - @(Get-PodeEndpointInternal -Type Tcp) | ForEach-Object { + @(Get-PodeEndpointByProtocolType -Type Tcp) | ForEach-Object { # get the ip address $_ip = [string]($_.Address) $_ip = Get-PodeIPAddressesForHostname -Hostname $_ip -Type All | Select-Object -First 1 diff --git a/src/Private/UnusedHelper.ps1 b/src/Private/UnusedHelper.ps1 index 58f48964e..0540130ca 100644 --- a/src/Private/UnusedHelper.ps1 +++ b/src/Private/UnusedHelper.ps1 @@ -62,33 +62,6 @@ function Convert-PodePathSeparator { }) } - - -function Open-PodeRunspace { - param( - [Parameter(Mandatory = $true)] - [string] - $Type - ) - - try { - Import-PodeModulesInternal - Add-PodePSDrivesInternal - $PodeContext.RunspacePools[$Type].State = 'Ready' - } - catch { - if ($PodeContext.RunspacePools[$Type].State -ieq 'waiting') { - $PodeContext.RunspacePools[$Type].State = 'Error' - } - - $_ | Out-Default - $_.ScriptStackTrace | Out-Default - throw - } -} - - - <# .SYNOPSIS Tests if the Pode module is from the development branch. diff --git a/src/Public/Metrics.ps1 b/src/Public/Metrics.ps1 index fb6797d72..0d47243d4 100644 --- a/src/Public/Metrics.ps1 +++ b/src/Public/Metrics.ps1 @@ -71,7 +71,7 @@ $404Reqs = Get-PodeServerRequestMetric -StatusCode 404 #> function Get-PodeServerRequestMetric { [CmdletBinding(DefaultParameterSetName = 'StatusCode')] - [OutputType([int])] + [OutputType([long])] param( [Parameter(ParameterSetName = 'StatusCode')] [int] @@ -92,7 +92,7 @@ function Get-PodeServerRequestMetric { $strCode = "$($StatusCode)" if (!$PodeContext.Metrics.Requests.StatusCodes.ContainsKey($strCode)) { - return 0 + return 0L } return $PodeContext.Metrics.Requests.StatusCodes[$strCode] diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index 7e08f933e..69b470005 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -192,7 +192,7 @@ function Write-PodeTextResponse { else { # convert string to bytes if ($isStringValue) { - $Bytes = ConvertFrom-PodeValueToByte -Value $Value + $Bytes = ConvertFrom-PodeValueToByteArray -Value $Value } # check if we only need a range of the bytes diff --git a/src/Public/Security.ps1 b/src/Public/Security.ps1 index 3dae694b5..3728bce81 100644 --- a/src/Public/Security.ps1 +++ b/src/Public/Security.ps1 @@ -385,46 +385,7 @@ function Set-PodeSecurityContentSecurityPolicy { $XssBlock ) - # build the header's value - $values = @( - Protect-PodeContentSecurityKeyword -Name 'default-src' -Value $Default - Protect-PodeContentSecurityKeyword -Name 'child-src' -Value $Child - Protect-PodeContentSecurityKeyword -Name 'connect-src' -Value $Connect - Protect-PodeContentSecurityKeyword -Name 'font-src' -Value $Font - Protect-PodeContentSecurityKeyword -Name 'frame-src' -Value $Frame - Protect-PodeContentSecurityKeyword -Name 'img-src' -Value $Image - Protect-PodeContentSecurityKeyword -Name 'manifest-src' -Value $Manifest - Protect-PodeContentSecurityKeyword -Name 'media-src' -Value $Media - Protect-PodeContentSecurityKeyword -Name 'object-src' -Value $Object - Protect-PodeContentSecurityKeyword -Name 'script-src' -Value $Scripts - Protect-PodeContentSecurityKeyword -Name 'style-src' -Value $Style - Protect-PodeContentSecurityKeyword -Name 'base-uri' -Value $BaseUri - Protect-PodeContentSecurityKeyword -Name 'form-action' -Value $FormAction - Protect-PodeContentSecurityKeyword -Name 'frame-ancestors' -Value $FrameAncestor - ) - - if ($Sandbox -ine 'None') { - $values += "sandbox $($Sandbox.ToLowerInvariant())".Trim() - } - - if ($UpgradeInsecureRequests) { - $values += 'upgrade-insecure-requests' - } - - $values = ($null -ne $values) - $value = ($values -join '; ') - - # add the header - Add-PodeSecurityHeader -Name 'Content-Security-Policy' -Value $value - - # this is done to explicitly disable XSS auditors in modern browsers - # as having it enabled has now been found to cause more vulnerabilities - if ($XssBlock) { - Add-PodeSecurityHeader -Name 'X-XSS-Protection' -Value '1; mode=block' - } - else { - Add-PodeSecurityHeader -Name 'X-XSS-Protection' -Value '0' - } + Set-PodeSecurityContentSecurityPolicyInternal -Params $PSBoundParameters } <# @@ -486,6 +447,7 @@ If supplied, the header will have the upgrade-insecure-requests value added. Add-PodeSecurityContentSecurityPolicy -Default '*.twitter.com' -Image 'data' #> function Add-PodeSecurityContentSecurityPolicy { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSPossibleIncorrectComparisonWithNull', '')] [CmdletBinding()] param( [Parameter()] @@ -555,37 +517,7 @@ function Add-PodeSecurityContentSecurityPolicy { $UpgradeInsecureRequests ) - # build the header's value - $values = @( - Protect-PodeContentSecurityKeyword -Name 'default-src' -Value $Default -Append - Protect-PodeContentSecurityKeyword -Name 'child-src' -Value $Child -Append - Protect-PodeContentSecurityKeyword -Name 'connect-src' -Value $Connect -Append - Protect-PodeContentSecurityKeyword -Name 'font-src' -Value $Font -Append - Protect-PodeContentSecurityKeyword -Name 'frame-src' -Value $Frame -Append - Protect-PodeContentSecurityKeyword -Name 'img-src' -Value $Image -Append - Protect-PodeContentSecurityKeyword -Name 'manifest-src' -Value $Manifest -Append - Protect-PodeContentSecurityKeyword -Name 'media-src' -Value $Media -Append - Protect-PodeContentSecurityKeyword -Name 'object-src' -Value $Object -Append - Protect-PodeContentSecurityKeyword -Name 'script-src' -Value $Scripts -Append - Protect-PodeContentSecurityKeyword -Name 'style-src' -Value $Style -Append - Protect-PodeContentSecurityKeyword -Name 'base-uri' -Value $BaseUri -Append - Protect-PodeContentSecurityKeyword -Name 'form-action' -Value $FormAction -Append - Protect-PodeContentSecurityKeyword -Name 'frame-ancestors' -Value $FrameAncestor -Append - ) - - if ($Sandbox -ine 'None') { - $values += "sandbox $($Sandbox.ToLowerInvariant())".Trim() - } - - if ($UpgradeInsecureRequests) { - $values += 'upgrade-insecure-requests' - } - - $values = ($null -ne $values) - $value = ($values -join '; ') - - # add the header - Add-PodeSecurityHeader -Name 'Content-Security-Policy' -Value $value + Set-PodeSecurityContentSecurityPolicyInternal -Params $PSBoundParameters -Append } <# @@ -703,10 +635,9 @@ The values to use for the WebShare portion of the header. .PARAMETER XrSpatialTracking The values to use for the XrSpatialTracking portion of the header. -.EXAMPLE -Set-PodeSecurityPermissionsPolicy -LayoutAnimations 'none' -UnoptimisedImages 'none' -OversizedImages 'none' -SyncXhr 'none' -UnsizedMedia 'none' #> function Set-PodeSecurityPermissionsPolicy { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSPossibleIncorrectComparisonWithNull', '')] [CmdletBinding()] param( [Parameter()] @@ -830,45 +761,7 @@ function Set-PodeSecurityPermissionsPolicy { $XrSpatialTracking ) - # build the header's value - $values = @( - Protect-PodePermissionsPolicyKeyword -Name 'accelerometer' -Value $Accelerometer - Protect-PodePermissionsPolicyKeyword -Name 'ambient-light-sensor' -Value $AmbientLightSensor - Protect-PodePermissionsPolicyKeyword -Name 'autoplay' -Value $Autoplay - Protect-PodePermissionsPolicyKeyword -Name 'battery' -Value $Battery - Protect-PodePermissionsPolicyKeyword -Name 'camera' -Value $Camera - Protect-PodePermissionsPolicyKeyword -Name 'display-capture' -Value $DisplayCapture - Protect-PodePermissionsPolicyKeyword -Name 'document-domain' -Value $DocumentDomain - Protect-PodePermissionsPolicyKeyword -Name 'encrypted-media' -Value $EncryptedMedia - Protect-PodePermissionsPolicyKeyword -Name 'fullscreen' -Value $Fullscreen - Protect-PodePermissionsPolicyKeyword -Name 'gamepad' -Value $Gamepad - Protect-PodePermissionsPolicyKeyword -Name 'geolocation' -Value $Geolocation - Protect-PodePermissionsPolicyKeyword -Name 'gyroscope' -Value $Gyroscope - Protect-PodePermissionsPolicyKeyword -Name 'interest-cohort' -Value $InterestCohort - Protect-PodePermissionsPolicyKeyword -Name 'layout-animations' -Value $LayoutAnimations - Protect-PodePermissionsPolicyKeyword -Name 'legacy-image-formats' -Value $LegacyImageFormats - Protect-PodePermissionsPolicyKeyword -Name 'magnetometer' -Value $Magnetometer - Protect-PodePermissionsPolicyKeyword -Name 'microphone' -Value $Microphone - Protect-PodePermissionsPolicyKeyword -Name 'midi' -Value $Midi - Protect-PodePermissionsPolicyKeyword -Name 'oversized-images' -Value $OversizedImages - Protect-PodePermissionsPolicyKeyword -Name 'payment' -Value $Payment - Protect-PodePermissionsPolicyKeyword -Name 'picture-in-picture' -Value $PictureInPicture - Protect-PodePermissionsPolicyKeyword -Name 'publickey-credentials-get' -Value $PublicKeyCredentials - Protect-PodePermissionsPolicyKeyword -Name 'speaker-selection' -Value $Speakers - Protect-PodePermissionsPolicyKeyword -Name 'sync-xhr' -Value $SyncXhr - Protect-PodePermissionsPolicyKeyword -Name 'unoptimized-images' -Value $UnoptimisedImages - Protect-PodePermissionsPolicyKeyword -Name 'unsized-media' -Value $UnsizedMedia - Protect-PodePermissionsPolicyKeyword -Name 'usb' -Value $Usb - Protect-PodePermissionsPolicyKeyword -Name 'screen-wake-lock' -Value $ScreenWakeLake - Protect-PodePermissionsPolicyKeyword -Name 'web-share' -Value $WebShare - Protect-PodePermissionsPolicyKeyword -Name 'xr-spatial-tracking' -Value $XrSpatialTracking - ) - - $values = ($null -ne $values) - $value = ($values -join ', ') - - # add the header - Add-PodeSecurityHeader -Name 'Permissions-Policy' -Value $value + Set-PodeSecurityPermissionsPolicy -Params $PSBoundParameters } <# @@ -1095,45 +988,7 @@ function Add-PodeSecurityPermissionsPolicy { $XrSpatialTracking ) - # build the header's value - $values = @( - Protect-PodePermissionsPolicyKeyword -Name 'accelerometer' -Value $Accelerometer -Append - Protect-PodePermissionsPolicyKeyword -Name 'ambient-light-sensor' -Value $AmbientLightSensor -Append - Protect-PodePermissionsPolicyKeyword -Name 'autoplay' -Value $Autoplay -Append - Protect-PodePermissionsPolicyKeyword -Name 'battery' -Value $Battery -Append - Protect-PodePermissionsPolicyKeyword -Name 'camera' -Value $Camera -Append - Protect-PodePermissionsPolicyKeyword -Name 'display-capture' -Value $DisplayCapture -Append - Protect-PodePermissionsPolicyKeyword -Name 'document-domain' -Value $DocumentDomain -Append - Protect-PodePermissionsPolicyKeyword -Name 'encrypted-media' -Value $EncryptedMedia -Append - Protect-PodePermissionsPolicyKeyword -Name 'fullscreen' -Value $Fullscreen -Append - Protect-PodePermissionsPolicyKeyword -Name 'gamepad' -Value $Gamepad -Append - Protect-PodePermissionsPolicyKeyword -Name 'geolocation' -Value $Geolocation -Append - Protect-PodePermissionsPolicyKeyword -Name 'gyroscope' -Value $Gyroscope -Append - Protect-PodePermissionsPolicyKeyword -Name 'interest-cohort' -Value $InterestCohort -Append - Protect-PodePermissionsPolicyKeyword -Name 'layout-animations' -Value $LayoutAnimations -Append - Protect-PodePermissionsPolicyKeyword -Name 'legacy-image-formats' -Value $LegacyImageFormats -Append - Protect-PodePermissionsPolicyKeyword -Name 'magnetometer' -Value $Magnetometer -Append - Protect-PodePermissionsPolicyKeyword -Name 'microphone' -Value $Microphone -Append - Protect-PodePermissionsPolicyKeyword -Name 'midi' -Value $Midi -Append - Protect-PodePermissionsPolicyKeyword -Name 'oversized-images' -Value $OversizedImages -Append - Protect-PodePermissionsPolicyKeyword -Name 'payment' -Value $Payment -Append - Protect-PodePermissionsPolicyKeyword -Name 'picture-in-picture' -Value $PictureInPicture -Append - Protect-PodePermissionsPolicyKeyword -Name 'publickey-credentials-get' -Value $PublicKeyCredentials -Append - Protect-PodePermissionsPolicyKeyword -Name 'speaker-selection' -Value $Speakers -Append - Protect-PodePermissionsPolicyKeyword -Name 'sync-xhr' -Value $SyncXhr -Append - Protect-PodePermissionsPolicyKeyword -Name 'unoptimized-images' -Value $UnoptimisedImages -Append - Protect-PodePermissionsPolicyKeyword -Name 'unsized-media' -Value $UnsizedMedia -Append - Protect-PodePermissionsPolicyKeyword -Name 'usb' -Value $Usb -Append - Protect-PodePermissionsPolicyKeyword -Name 'screen-wake-lock' -Value $ScreenWakeLake -Append - Protect-PodePermissionsPolicyKeyword -Name 'web-share' -Value $WebShare -Append - Protect-PodePermissionsPolicyKeyword -Name 'xr-spatial-tracking' -Value $XrSpatialTracking -Append - ) - - $values = ($null -ne $values) - $value = ($values -join ', ') - - # add the header - Add-PodeSecurityHeader -Name 'Permissions-Policy' -Value $value + Set-PodeSecurityPermissionsPolicy -Params $PSBoundParameters -Append } <# From 972c0c913813e0cb4c78fd3b09728981a8d7c8f4 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 24 May 2024 13:29:14 -0700 Subject: [PATCH 003/177] modified: examples/timers.ps1 modified: src/Private/Middleware.ps1 modified: src/Private/Security.ps1 modified: src/Private/Serverless.ps1 modified: src/Private/Timers.ps1 --- examples/timers.ps1 | 5 +- src/Private/Middleware.ps1 | 25 +++++++- src/Private/Security.ps1 | 126 +++++++++++++++++++++---------------- src/Private/Serverless.ps1 | 6 +- src/Private/Timers.ps1 | 4 +- 5 files changed, 106 insertions(+), 60 deletions(-) diff --git a/examples/timers.ps1 b/examples/timers.ps1 index 091b98d56..257b7d851 100644 --- a/examples/timers.ps1 +++ b/examples/timers.ps1 @@ -7,7 +7,7 @@ Import-Module "$($path)/src/Pode.psm1" -Force -ErrorAction Stop # create a basic server Start-PodeServer { - Add-PodeEndpoint -Address * -Port 8081 -Protocol Http + Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http # runs forever, looping every 5secs $message = 'Hello, world' @@ -30,12 +30,14 @@ Start-PodeServer { # runs forever, but skips the first 3 "loops" - is paused for 15secs then loops every 5secs Add-PodeTimer -Name 'pause-first-3' -Interval 5 -ScriptBlock { 'Skip 3 then run' | Out-PodeHost + Write-PodeHost $TimerEvent -Explode -ShowType } -Skip 3 # runs every 5secs, but only runs for 3 "loops" (ie, 15secs) Add-PodeTimer -Name 'run-3-times' -Interval 5 -ScriptBlock { 'Only run 3 times' | Out-PodeHost Get-PodeTimer -Name 'run-3-times' | Out-Default + Write-PodeHost $TimerEvent -Explode -ShowType } -Limit 3 # skip the first 2 loops, then run for 15 loops @@ -46,6 +48,7 @@ Start-PodeServer { # run once after 2mins Add-PodeTimer -Name 'run-once' -Interval 20 -ScriptBlock { 'Ran once' | Out-PodeHost + Write-PodeHost $TimerEvent -Explode -ShowType } -Skip 1 -Limit 1 # create a new timer via a route diff --git a/src/Private/Middleware.ps1 b/src/Private/Middleware.ps1 index f633d7e4c..9de0a68a2 100644 --- a/src/Private/Middleware.ps1 +++ b/src/Private/Middleware.ps1 @@ -147,7 +147,27 @@ function Get-PodeAccessMiddleware { }) } +<# +.SYNOPSIS +Retrieves the rate limit middleware for Pode. + +.DESCRIPTION +This function returns the inbuilt rate limit middleware for Pode. It checks if the request IP address, route, and endpoint have hit their respective rate limits. If any of these checks fail, a 429 status code is set, and the request is denied. + +.EXAMPLE +Get-PodeLimitMiddleware +Retrieves the rate limit middleware and adds it to the middleware pipeline. + +.RETURNS +[ScriptBlock] - Returns a script block that represents the rate limit middleware. + +.NOTES +This is an internal function and may change in future releases of Pode. +#> function Get-PodeLimitMiddleware { + [CmdletBinding()] + [OutputType([ScriptBlock])] + param() return (Get-PodeInbuiltMiddleware -Name '__pode_mw_rate_limit__' -ScriptBlock { # are there any rules? if ($PodeContext.Server.Limits.Rules.Count -eq 0) { @@ -167,7 +187,7 @@ function Get-PodeLimitMiddleware { } # check the endpoint - if (!(Test-PodeEndpointByProtocolTypeLimit -EndpointName $WebEvent.Endpoint.Name)) { + if (!(Test-PodeEndpointLimit -EndpointName $WebEvent.Endpoint.Name)) { Set-PodeResponseStatus -Code 429 return $false } @@ -192,6 +212,9 @@ function Get-PodeLimitMiddleware { Retrieves middleware for serving public static content. #> function Get-PodePublicMiddleware { + [CmdletBinding()] + [OutputType([bool])] + param() return (Get-PodeInbuiltMiddleware -Name '__pode_mw_static_content__' -ScriptBlock { # only find public static content here $path = Find-PodePublicRoute -Path $WebEvent.Path diff --git a/src/Private/Security.ps1 b/src/Private/Security.ps1 index 4cebcbbe6..067686ac0 100644 --- a/src/Private/Security.ps1 +++ b/src/Private/Security.ps1 @@ -180,7 +180,31 @@ function Test-PodeRouteLimit { } } -function Test-PodeEndpointByProtocolTypeLimit { +<# +.SYNOPSIS +Checks if a given endpoint has exceeded its limit according to the defined rate limiting rules in Pode. + +.DESCRIPTION +This function evaluates the rate limiting rules for a specified endpoint and determines if the endpoint is allowed to proceed based on the defined limits and the current usage rate. If the endpoint is not active or not defined in the rules, it is either allowed by default or added to the active list with its respective rule. + +.PARAMETER EndpointName +The name of the endpoint to check against the rate limiting rules. + +.EXAMPLE +Test-PodeEndpointLimit -EndpointName "MyEndpoint" +Checks if "MyEndpoint" is allowed to proceed based on the current rate limiting rules. + +.EXAMPLE +$result = Test-PodeEndpointLimit -EndpointName $null +Checks if an unnamed endpoint (e.g., $null) is allowed, which always returns $true. + +.RETURNS +[boolean] - Returns $true if the endpoint is allowed, otherwise $false. + +.NOTES +This is an internal function and may change in future releases of Pode. +#> +function Test-PodeEndpointLimit { param( [Parameter()] [string] @@ -1146,20 +1170,20 @@ function Set-PodeSecurityContentSecurityPolicyInternal { # build the header's value $values = @( - Protect-PodeContentSecurityKeyword -Name 'default-src' -Value $Params.Default - Protect-PodeContentSecurityKeyword -Name 'child-src' -Value $Params.Child - Protect-PodeContentSecurityKeyword -Name 'connect-src' -Value $Params.Connect - Protect-PodeContentSecurityKeyword -Name 'font-src' -Value $Params.Font - Protect-PodeContentSecurityKeyword -Name 'frame-src' -Value $Params.Frame - Protect-PodeContentSecurityKeyword -Name 'img-src' -Value $Params.Image - Protect-PodeContentSecurityKeyword -Name 'manifest-src' -Value $Params.Manifest - Protect-PodeContentSecurityKeyword -Name 'media-src' -Value $Params.Media - Protect-PodeContentSecurityKeyword -Name 'object-src' -Value $Params.Object - Protect-PodeContentSecurityKeyword -Name 'script-src' -Value $Params.Scripts - Protect-PodeContentSecurityKeyword -Name 'style-src' -Value $Params.Style - Protect-PodeContentSecurityKeyword -Name 'base-uri' -Value $Params.BaseUri - Protect-PodeContentSecurityKeyword -Name 'form-action' -Value $Params.FormAction - Protect-PodeContentSecurityKeyword -Name 'frame-ancestors' -Value $Params.FrameAncestor + Protect-PodeContentSecurityKeyword -Name 'default-src' -Value $Params.Default -Append:$Append + Protect-PodeContentSecurityKeyword -Name 'child-src' -Value $Params.Child -Append:$Append + Protect-PodeContentSecurityKeyword -Name 'connect-src' -Value $Params.Connect -Append:$Append + Protect-PodeContentSecurityKeyword -Name 'font-src' -Value $Params.Font -Append:$Append + Protect-PodeContentSecurityKeyword -Name 'frame-src' -Value $Params.Frame -Append:$Append + Protect-PodeContentSecurityKeyword -Name 'img-src' -Value $Params.Image -Append:$Append + Protect-PodeContentSecurityKeyword -Name 'manifest-src' -Value $Params.Manifest -Append:$Append + Protect-PodeContentSecurityKeyword -Name 'media-src' -Value $Params.Media -Append:$Append + Protect-PodeContentSecurityKeyword -Name 'object-src' -Value $Params.Object -Append:$Append + Protect-PodeContentSecurityKeyword -Name 'script-src' -Value $Params.Scripts -Append:$Append + Protect-PodeContentSecurityKeyword -Name 'style-src' -Value $Params.Style -Append:$Append + Protect-PodeContentSecurityKeyword -Name 'base-uri' -Value $Params.BaseUri -Append:$Append + Protect-PodeContentSecurityKeyword -Name 'form-action' -Value $Params.FormAction -Append:$Append + Protect-PodeContentSecurityKeyword -Name 'frame-ancestors' -Value $Params.FrameAncestor -Append:$Append ) if ($Params.Sandbox -ine 'None') { @@ -1175,16 +1199,12 @@ function Set-PodeSecurityContentSecurityPolicyInternal { # operator is faster because it is a direct array operation that internally skips the overhead of # piping through a cmdlet and processing each item individually. $values = ($values -ne $null) - # Filter out $null values from the $values array using the array filter `-ne $null`. This approach - # is equivalent to using `$values | Where-Object { $_ -ne $null }` but is more efficient. The `-ne $null` - # operator is faster because it is a direct array operation that internally skips the overhead of - # piping through a cmdlet and processing each item individually. $value = ($values -join '; ') # Add the Content Security Policy header to the response or relevant context. This cmdlet # sets the HTTP header with the name 'Content-Security-Policy' and the constructed value. - Add-PodeSecurityHeader -Name 'Content-Security-Policy' -Value $value -Append $Append + Add-PodeSecurityHeader -Name 'Content-Security-Policy' -Value $value # this is done to explicitly disable XSS auditors in modern browsers # as having it enabled has now been found to cause more vulnerabilities @@ -1244,36 +1264,36 @@ function Set-PodeSecurityPermissionsPolicy { # build the header's value $values = @( - Protect-PodePermissionsPolicyKeyword -Name 'accelerometer' -Value $Params.Accelerometer - Protect-PodePermissionsPolicyKeyword -Name 'ambient-light-sensor' -Value $Params.AmbientLightSensor - Protect-PodePermissionsPolicyKeyword -Name 'autoplay' -Value $Params.Autoplay - Protect-PodePermissionsPolicyKeyword -Name 'battery' -Value $Params.Battery - Protect-PodePermissionsPolicyKeyword -Name 'camera' -Value $Params.Camera - Protect-PodePermissionsPolicyKeyword -Name 'display-capture' -Value $Params.DisplayCapture - Protect-PodePermissionsPolicyKeyword -Name 'document-domain' -Value $Params.DocumentDomain - Protect-PodePermissionsPolicyKeyword -Name 'encrypted-media' -Value $Params.EncryptedMedia - Protect-PodePermissionsPolicyKeyword -Name 'fullscreen' -Value $Params.Fullscreen - Protect-PodePermissionsPolicyKeyword -Name 'gamepad' -Value $Params.Gamepad - Protect-PodePermissionsPolicyKeyword -Name 'geolocation' -Value $Params.Geolocation - Protect-PodePermissionsPolicyKeyword -Name 'gyroscope' -Value $Params.Gyroscope - Protect-PodePermissionsPolicyKeyword -Name 'interest-cohort' -Value $Params.InterestCohort - Protect-PodePermissionsPolicyKeyword -Name 'layout-animations' -Value $Params.LayoutAnimations - Protect-PodePermissionsPolicyKeyword -Name 'legacy-image-formats' -Value $Params.LegacyImageFormats - Protect-PodePermissionsPolicyKeyword -Name 'magnetometer' -Value $Params.Magnetometer - Protect-PodePermissionsPolicyKeyword -Name 'microphone' -Value $Params.Microphone - Protect-PodePermissionsPolicyKeyword -Name 'midi' -Value $Params.Midi - Protect-PodePermissionsPolicyKeyword -Name 'oversized-images' -Value $Params.OversizedImages - Protect-PodePermissionsPolicyKeyword -Name 'payment' -Value $Params.Payment - Protect-PodePermissionsPolicyKeyword -Name 'picture-in-picture' -Value $Params.PictureInPicture - Protect-PodePermissionsPolicyKeyword -Name 'publickey-credentials-get' -Value $Params.PublicKeyCredentials - Protect-PodePermissionsPolicyKeyword -Name 'speaker-selection' -Value $Params.Speakers - Protect-PodePermissionsPolicyKeyword -Name 'sync-xhr' -Value $Params.SyncXhr - Protect-PodePermissionsPolicyKeyword -Name 'unoptimized-images' -Value $Params.UnoptimisedImages - Protect-PodePermissionsPolicyKeyword -Name 'unsized-media' -Value $Params.UnsizedMedia - Protect-PodePermissionsPolicyKeyword -Name 'usb' -Value $Params.Usb - Protect-PodePermissionsPolicyKeyword -Name 'screen-wake-lock' -Value $Params.ScreenWakeLake - Protect-PodePermissionsPolicyKeyword -Name 'web-share' -Value $Params.WebShare - Protect-PodePermissionsPolicyKeyword -Name 'xr-spatial-tracking' -Value $Params.XrSpatialTracking + Protect-PodePermissionsPolicyKeyword -Name 'accelerometer' -Value $Params.Accelerometer -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'ambient-light-sensor' -Value $Params.AmbientLightSensor -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'autoplay' -Value $Params.Autoplay -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'battery' -Value $Params.Battery -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'camera' -Value $Params.Camera -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'display-capture' -Value $Params.DisplayCapture -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'document-domain' -Value $Params.DocumentDomain -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'encrypted-media' -Value $Params.EncryptedMedia -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'fullscreen' -Value $Params.Fullscreen -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'gamepad' -Value $Params.Gamepad -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'geolocation' -Value $Params.Geolocation -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'gyroscope' -Value $Params.Gyroscope -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'interest-cohort' -Value $Params.InterestCohort -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'layout-animations' -Value $Params.LayoutAnimations -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'legacy-image-formats' -Value $Params.LegacyImageFormats -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'magnetometer' -Value $Params.Magnetometer -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'microphone' -Value $Params.Microphone -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'midi' -Value $Params.Midi -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'oversized-images' -Value $Params.OversizedImages -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'payment' -Value $Params.Payment -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'picture-in-picture' -Value $Params.PictureInPicture -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'publickey-credentials-get' -Value $Params.PublicKeyCredentials -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'speaker-selection' -Value $Params.Speakers -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'sync-xhr' -Value $Params.SyncXhr -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'unoptimized-images' -Value $Params.UnoptimisedImages -Append $Append + Protect-PodePermissionsPolicyKeyword -Name 'unsized-media' -Value $Params.UnsizedMedia -Append $Append + Protect-PodePermissionsPolicyKeyword -Name 'usb' -Value $Params.Usb -Append $Append + Protect-PodePermissionsPolicyKeyword -Name 'screen-wake-lock' -Value $Params.ScreenWakeLake -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'web-share' -Value $Params.WebShare -Append:$Append + Protect-PodePermissionsPolicyKeyword -Name 'xr-spatial-tracking' -Value $Params.XrSpatialTracking -Append:$Append ) # Filter out $null values from the $values array using the array filter `-ne $null`. This approach @@ -1282,13 +1302,9 @@ function Set-PodeSecurityPermissionsPolicy { # piping through a cmdlet and processing each item individually. $values = ($values -ne $null) - # Filter out $null values from the $values array using the array filter `-ne $null`. This approach - # is equivalent to using `$values | Where-Object { $_ -ne $null }` but is more efficient. The `-ne $null` - # operator is faster because it is a direct array operation that internally skips the overhead of - # piping through a cmdlet and processing each item individually. $value = ($values -join ', ') # Add the constructed Permissions Policy header to the response or relevant context. This cmdlet # sets the HTTP header with the name 'Permissions-Policy' and the constructed value. - Add-PodeSecurityHeader -Name 'Permissions-Policy' -Value $value -Append $Append + Add-PodeSecurityHeader -Name 'Permissions-Policy' -Value $value } \ No newline at end of file diff --git a/src/Private/Serverless.ps1 b/src/Private/Serverless.ps1 index ec67329a0..98a178718 100644 --- a/src/Private/Serverless.ps1 +++ b/src/Private/Serverless.ps1 @@ -1,4 +1,5 @@ function Start-PodeAzFuncServer { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')] param( [Parameter(Mandatory = $true)] $Data @@ -26,7 +27,7 @@ function Start-PodeAzFuncServer { $response.Headers = @{} # reset event data - $WebEvent = @{ + $global:WebEvent = @{ OnEnd = @() Auth = @{} Response = $response @@ -125,6 +126,7 @@ function Start-PodeAzFuncServer { } function Start-PodeAwsLambdaServer { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')] param( [Parameter(Mandatory = $true)] $Data @@ -154,7 +156,7 @@ function Start-PodeAwsLambdaServer { } # reset event data - $WebEvent = @{ + $global:WebEvent = @{ OnEnd = @() Auth = @{} Response = $response diff --git a/src/Private/Timers.ps1 b/src/Private/Timers.ps1 index 1fddbef8c..3dc1a9db3 100644 --- a/src/Private/Timers.ps1 +++ b/src/Private/Timers.ps1 @@ -62,6 +62,8 @@ function Start-PodeTimerRunspace { } function Invoke-PodeInternalTimer { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] param( [Parameter(Mandatory = $true)] $Timer, @@ -72,7 +74,7 @@ function Invoke-PodeInternalTimer { ) try { - $script:TimerEvent = @{ + $global:TimerEvent = @{ Lockable = $PodeContext.Threading.Lockables.Global Sender = $Timer Metadata = @{} From 29f30d658c488ef75936925fbb1fe21d64b402fd Mon Sep 17 00:00:00 2001 From: mdaneri Date: Wed, 29 May 2024 16:09:55 -0700 Subject: [PATCH 004/177] First drop Modified - Write-PodeCsvResponse - Write-PodeHtmlResponse - Write-PodeJsonResponse - Write-PodeXmlResponse - Write-PodeYamlResponse to support piping arrays --- examples/Write-Response.ps1 | 133 ++++++++++++++++++++ src/Public/Responses.ps1 | 238 ++++++++++++++++++++++-------------- 2 files changed, 282 insertions(+), 89 deletions(-) create mode 100644 examples/Write-Response.ps1 diff --git a/examples/Write-Response.ps1 b/examples/Write-Response.ps1 new file mode 100644 index 000000000..7823766a1 --- /dev/null +++ b/examples/Write-Response.ps1 @@ -0,0 +1,133 @@ +$podePath = Split-Path -Parent -Path (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) +if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { + Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop +} +else { + Import-Module -Name 'Pode' +} + +Start-PodeServer { + Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http + # nopipe + Add-PodeRoute -Path '/html/processes' -Method Get -ScriptBlock { + $myProcess = Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | + Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | + Sort-Object WS -Descending + Write-PodeHtmlResponse -Value $myProcess -StatusCode 200 + } + # pipe + Add-PodeRoute -Path '/html/processesPiped' -Method Get -ScriptBlock { + Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | + Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | + Sort-Object WS -Descending | Write-PodeHtmlResponse -StatusCode 200 + } + + # nopipe + Add-PodeRoute -Path '/text/processes' -Method Get -ScriptBlock { + $myProcess = Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | + Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | + Sort-Object WS -Descending | Out-String + Write-PodeTextResponse -Value $myProcess -StatusCode 200 + } + # pipe + Add-PodeRoute -Path '/text/processesPiped' -Method Get -ScriptBlock { + Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | + Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | + Sort-Object WS -Descending | Out-String | Write-PodeTextResponse -StatusCode 200 + } + + # nopipe + Add-PodeRoute -Path '/csv/processes' -Method Get -ScriptBlock { + $myProcess = Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | + Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | + Sort-Object WS -Descending + Write-PodeCsvResponse -Value $myProcess -StatusCode 200 + } + + # pipe + Add-PodeRoute -Path '/csv/processesPiped' -Method Get -ScriptBlock { + Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | + Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | + Sort-Object WS -Descending | Write-PodeCsvResponse -StatusCode 200 + } + + Add-PodeRoute -Path '/csv/string' -Method Get -ScriptBlock { + Write-PodeCsvResponse -Value "Name`nRick`nDon" + } + + Add-PodeRoute -Path '/csv/hash' -Method Get -ScriptBlock { + Write-PodeCsvResponse -Value @(@{ Name = 'Rick' }, @{ Name = 'Don' }) + } + + # nopipe + Add-PodeRoute -Path '/json/processes' -Method Get -ScriptBlock { + $myProcess = Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | + Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | + Sort-Object WS -Descending + Write-PodeJsonResponse -Value $myProcess -StatusCode 200 + } + + # pipe + Add-PodeRoute -Path '/json/processesPiped' -Method Get -ScriptBlock { + Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | + Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | + Sort-Object WS -Descending | Write-PodeJsonResponse -StatusCode 200 + } + + # nopipe + Add-PodeRoute -Path '/xml/processes' -Method Get -ScriptBlock { + $myProcess = Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | + Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | + Sort-Object WS -Descending + Write-PodeXmlResponse -Value $myProcess -StatusCode 200 + } + + # pipe + Add-PodeRoute -Path '/xml/processesPiped' -Method Get -ScriptBlock { + Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | + Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | + Sort-Object WS -Descending | Write-PodeXmlResponse -StatusCode 200 + } + + Add-PodeRoute -Path '/xml/string' -Method Get -ScriptBlock { + Write-PodeXmlResponse -Value "Name`nRick`nDon" + } + + Add-PodeRoute -Path '/xml/hash' -Method Get -ScriptBlock { + Write-PodeXmlResponse -Value @(@{ Name = 'Rick' }, @{ Name = 'Don' }) + } + + # nopipe + Add-PodeRoute -Path '/yaml/processes' -Method Get -ScriptBlock { + $myProcess = Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | + Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | + Sort-Object WS -Descending + Write-PodeYamlResponse -Value $myProcess -StatusCode 200 -ContentType 'text/yaml' + } + + # pipe + Add-PodeRoute -Path '/yaml/processesPiped' -Method Get -ScriptBlock { + Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | + Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | + Sort-Object WS -Descending | Write-PodeYamlResponse -StatusCode 200 -ContentType 'text/yaml' + } + Start-Job -ScriptBlock { + Start-Sleep -Seconds 5 + Start-Process http://localhost:8081/html/processesPiped + Start-Process http://localhost:8081/html/processes + Start-Process http://localhost:8081/text/processesPiped + Start-Process http://localhost:8081/text/processes + Start-Process http://localhost:8081/csv/processesPiped + Start-Process http://localhost:8081/csv/processes + Start-Process http://localhost:8081/csv/string + Start-Process http://localhost:8081/csv/hash + Start-Process http://localhost:8081/json/processesPiped + Start-Process http://localhost:8081/json/processes + Start-Process http://localhost:8081/xml/processesPiped + Start-Process http://localhost:8081/xml/processes + Start-Process http://localhost:8081/xml/string + Start-Process http://localhost:8081/xml/hash + Start-Process http://localhost:8081/yaml/processesPiped + Start-Process http://localhost:8081/yaml/processes + } +} \ No newline at end of file diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index e64eb7e55..471556124 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -454,40 +454,46 @@ function Write-PodeCsvResponse { [int] $StatusCode = 200 ) - - switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { - 'file' { - if (Test-PodePath $Path) { - $Value = Get-PodeFileContent -Path $Path - } + begin { + $pipelineValue = @() + } + process { + if ($PSCmdlet.ParameterSetName -eq 'Value') { + $pipelineValue += $_ } - - 'value' { - if ($Value -isnot [string]) { - $Value = @(foreach ($v in $Value) { - New-Object psobject -Property $v - }) - - if (Test-PodeIsPSCore) { - $Value = ($Value | ConvertTo-Csv -Delimiter ',' -IncludeTypeInformation:$false) + } end { + switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { + 'file' { + if (Test-PodePath $Path) { + $Value = Get-PodeFileContent -Path $Path } - else { - $Value = ($Value | ConvertTo-Csv -Delimiter ',' -NoTypeInformation) + } + + 'value' { + if ($pipelineValue) { + $Value = $pipelineValue } + if ($Value -isnot [string]) { + if (Test-PodeIsPSCore) { + $Value = ($Value | ConvertTo-Csv -Delimiter ',' -IncludeTypeInformation:$false) + } + else { + $Value = ($Value | ConvertTo-Csv -Delimiter ',' -NoTypeInformation) + } - $Value = ($Value -join ([environment]::NewLine)) + $Value = ($Value -join ([environment]::NewLine)) + } } } - } - if ([string]::IsNullOrWhiteSpace($Value)) { - $Value = [string]::Empty - } + if ([string]::IsNullOrWhiteSpace($Value)) { + $Value = [string]::Empty + } - Write-PodeTextResponse -Value $Value -ContentType 'text/csv' -StatusCode $StatusCode + Write-PodeTextResponse -Value $Value -ContentType 'text/csv' -StatusCode $StatusCode + } } - <# .SYNOPSIS Writes HTML data to the Response. @@ -528,26 +534,41 @@ function Write-PodeHtmlResponse { $StatusCode = 200 ) - switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { - 'file' { - if (Test-PodePath $Path) { - $Value = Get-PodeFileContent -Path $Path - } + begin { + $pipelineValue = @() + } + + process { + if ($PSCmdlet.ParameterSetName -eq 'Value') { + $pipelineValue += $_ } + } - 'value' { - if ($Value -isnot [string]) { - $Value = ($Value | ConvertTo-Html) - $Value = ($Value -join ([environment]::NewLine)) + end { + switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { + 'file' { + if (Test-PodePath $Path) { + $Value = Get-PodeFileContent -Path $Path + } + } + + 'value' { + if ($pipelineValue) { + $Value = $pipelineValue + } + if ($Value -isnot [string]) { + $Value = ($Value | ConvertTo-Html) + $Value = ($Value -join ([environment]::NewLine)) + } } } - } - if ([string]::IsNullOrWhiteSpace($Value)) { - $Value = [string]::Empty - } + if ([string]::IsNullOrWhiteSpace($Value)) { + $Value = [string]::Empty + } - Write-PodeTextResponse -Value $Value -ContentType 'text/html' -StatusCode $StatusCode + Write-PodeTextResponse -Value $Value -ContentType 'text/html' -StatusCode $StatusCode + } } @@ -674,34 +695,43 @@ function Write-PodeJsonResponse { $NoCompress ) + begin { + $pipelineValue = @() + } - switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { - 'file' { - if (Test-PodePath $Path) { - $Value = Get-PodeFileContent -Path $Path - } - if ([string]::IsNullOrWhiteSpace($Value)) { - $Value = '{}' - } + process { + if ($PSCmdlet.ParameterSetName -eq 'Value') { + $pipelineValue += $_ } + } + + end { + switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { + 'file' { + if (Test-PodePath $Path) { + $Value = Get-PodeFileContent -Path $Path + } + if ([string]::IsNullOrWhiteSpace($Value)) { + $Value = '{}' + } + } - 'value' { - if ($Value -isnot [string]) { - if ($Depth -le 0) { - $Value = (ConvertTo-Json -InputObject $Value -Compress:(!$NoCompress)) + 'value' { + if ($pipelineValue) { + $Value = $pipelineValue } - else { + if ($Value -isnot [string]) { $Value = (ConvertTo-Json -InputObject $Value -Depth $Depth -Compress:(!$NoCompress)) } } } - } - if ([string]::IsNullOrWhiteSpace($Value)) { - $Value = '{}' - } + if ([string]::IsNullOrWhiteSpace($Value)) { + $Value = '{}' + } - Write-PodeTextResponse -Value $Value -ContentType 'application/json' -StatusCode $StatusCode + Write-PodeTextResponse -Value $Value -ContentType 'application/json' -StatusCode $StatusCode + } } @@ -718,6 +748,9 @@ A String, PSObject, or HashTable value. .PARAMETER Path The path to an XML file. +.PARAMETER Depth +The Depth to generate the XML document - the larger this value the worse performance gets. + .PARAMETER StatusCode The status code to set against the response. @@ -741,34 +774,50 @@ function Write-PodeXmlResponse { [string] $Path, + [Parameter(ParameterSetName = 'Value')] + [ValidateRange(0, 100)] + [int] + $Depth = 10, + [Parameter()] [int] $StatusCode = 200 ) + begin { + $pipelineValue = @() + } - switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { - 'file' { - if (Test-PodePath $Path) { - $Value = Get-PodeFileContent -Path $Path - } + process { + if ($PSCmdlet.ParameterSetName -eq 'Value') { + $pipelineValue += $_ } + } - 'value' { - if ($Value -isnot [string]) { - $Value = @(foreach ($v in $Value) { - New-Object psobject -Property $v - }) + end { - $Value = ($Value | ConvertTo-Xml -Depth 10 -As String -NoTypeInformation) + switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { + 'file' { + if (Test-PodePath $Path) { + $Value = Get-PodeFileContent -Path $Path + } + } + + 'value' { + if ($pipelineValue) { + $Value = $pipelineValue + } + if ($Value -isnot [string]) { + $Value = ($Value | ConvertTo-Xml -Depth $Depth -As String -NoTypeInformation) + } } } - } - if ([string]::IsNullOrWhiteSpace($Value)) { - $Value = [string]::Empty - } + if ([string]::IsNullOrWhiteSpace($Value)) { + $Value = [string]::Empty + } - Write-PodeTextResponse -Value $Value -ContentType 'text/xml' -StatusCode $StatusCode + Write-PodeTextResponse -Value $Value -ContentType 'text/xml' -StatusCode $StatusCode + } } <# @@ -830,30 +879,41 @@ function Write-PodeYamlResponse { $StatusCode = 200 ) - switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { - 'file' { - if (Test-PodePath $Path) { - $Value = Get-PodeFileContent -Path $Path - } + begin { + $pipelineValue = @() + } + + process { + if ($PSCmdlet.ParameterSetName -eq 'Value') { + $pipelineValue += $_ } + } - 'value' { - if ($Value -isnot [string]) { - if ( $Depth -gt 0) { - $Value = ConvertTo-PodeYaml -InputObject $Value -Depth $Depth + end { + + switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { + 'file' { + if (Test-PodePath $Path) { + $Value = Get-PodeFileContent -Path $Path } - else { - $Value = ConvertTo-PodeYaml -InputObject $Value + } + + 'value' { + if ($pipelineValue) { + $Value = $pipelineValue + } + if ($Value -isnot [string]) { + $Value = ConvertTo-PodeYaml -InputObject $Value -Depth $Depth + } } } - } - if ([string]::IsNullOrWhiteSpace($Value)) { - $Value = '[]' - } - - Write-PodeTextResponse -Value $Value -ContentType $ContentType -StatusCode $StatusCode + if ([string]::IsNullOrWhiteSpace($Value)) { + $Value = '[]' + } + Write-PodeTextResponse -Value $Value -ContentType $ContentType -StatusCode $StatusCode + } } From a774e4296c73da43adcf6be1dd49e1e4ce3dce00 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Wed, 29 May 2024 17:43:05 -0700 Subject: [PATCH 005/177] second drop fix an issue with write xml and csv when an array of hashtable is passed --- examples/Write-Response.ps1 | 10 +++------- src/Private/Helpers.ps1 | 28 ++++++++++++++++++++++++++ src/Public/Responses.ps1 | 36 ++++++++++++++++++++++++++++++---- tests/unit/Responses.Tests.ps1 | 26 +++++++++++++++++++++++- 4 files changed, 88 insertions(+), 12 deletions(-) diff --git a/examples/Write-Response.ps1 b/examples/Write-Response.ps1 index 7823766a1..55ea34fac 100644 --- a/examples/Write-Response.ps1 +++ b/examples/Write-Response.ps1 @@ -89,12 +89,9 @@ Start-PodeServer { Sort-Object WS -Descending | Write-PodeXmlResponse -StatusCode 200 } - Add-PodeRoute -Path '/xml/string' -Method Get -ScriptBlock { - Write-PodeXmlResponse -Value "Name`nRick`nDon" - } Add-PodeRoute -Path '/xml/hash' -Method Get -ScriptBlock { - Write-PodeXmlResponse -Value @(@{ Name = 'Rick' }, @{ Name = 'Don' }) + Write-PodeXmlResponse -Value @(@{ Name = 'Rick' }, @{ Name = 'Don' }) -UsePropertyName } # nopipe @@ -113,7 +110,7 @@ Start-PodeServer { } Start-Job -ScriptBlock { Start-Sleep -Seconds 5 - Start-Process http://localhost:8081/html/processesPiped + <# Start-Process http://localhost:8081/html/processesPiped Start-Process http://localhost:8081/html/processes Start-Process http://localhost:8081/text/processesPiped Start-Process http://localhost:8081/text/processes @@ -123,9 +120,8 @@ Start-PodeServer { Start-Process http://localhost:8081/csv/hash Start-Process http://localhost:8081/json/processesPiped Start-Process http://localhost:8081/json/processes - Start-Process http://localhost:8081/xml/processesPiped + #> Start-Process http://localhost:8081/xml/processesPiped Start-Process http://localhost:8081/xml/processes - Start-Process http://localhost:8081/xml/string Start-Process http://localhost:8081/xml/hash Start-Process http://localhost:8081/yaml/processesPiped Start-Process http://localhost:8081/yaml/processes diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index d16ea4f92..cefaaf492 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -3316,4 +3316,32 @@ function ConvertTo-PodeYamlInternal { throw "Error'$($_)' in script $($_.InvocationInfo.ScriptName) $($_.InvocationInfo.Line.Trim()) (line $($_.InvocationInfo.ScriptLineNumber)) char $($_.InvocationInfo.OffsetInLine) executing $($_.InvocationInfo.MyCommand) on $type object '$($InputObject)' Class: $($InputObject.GetType().Name) BaseClass: $($InputObject.GetType().BaseType.Name) " } } +} + + + +function Resolve-PodeObjectArray { + param ( + [AllowNull()] + $Property + ) + if ($Property -is [hashtable]) { + if ($Property.Count -eq 1) { + return New-Object psobject -Property $Property + } + else { + return @(foreach ($v in $Property) { + Resolve-PodeObjectArray -Property $v + }) + } + } + elseif ($Property -is [object[]]) { + return @(foreach ($v in $Property) { + Resolve-PodeObjectArray -Property $v + + }) + } + else { + return New-Object psobject -Property $Property + } } \ No newline at end of file diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index 471556124..1f91c17d7 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -431,6 +431,9 @@ The path to a CSV file. .PARAMETER StatusCode The status code to set against the response. +.PARAMETER UsePropertyName +The elements name is equal to the key value + .EXAMPLE Write-PodeCsvResponse -Value "Name`nRick" @@ -452,7 +455,10 @@ function Write-PodeCsvResponse { [Parameter()] [int] - $StatusCode = 200 + $StatusCode = 200, + + [switch] + $UsePropertyName ) begin { $pipelineValue = @() @@ -473,7 +479,12 @@ function Write-PodeCsvResponse { if ($pipelineValue) { $Value = $pipelineValue } + if ($Value -isnot [string]) { + if ($UsePropertyName.IsPresent) { + $Value = Resolve-PodeObjectArray -Property $Value + } + if (Test-PodeIsPSCore) { $Value = ($Value | ConvertTo-Csv -Delimiter ',' -IncludeTypeInformation:$false) } @@ -754,11 +765,14 @@ The Depth to generate the XML document - the larger this value the worse perform .PARAMETER StatusCode The status code to set against the response. +.PARAMETER UsePropertyName +The elements name is equal to the key value + .EXAMPLE Write-PodeXmlResponse -Value 'Rick' .EXAMPLE -Write-PodeXmlResponse -Value @{ Name = 'Rick' } -StatusCode 201 +Write-PodeXmlResponse -Value @{ Name = 'Rick' } -StatusCode 201 -UsePropertyName .EXAMPLE Write-PodeXmlResponse -Path 'E:/Files/Names.xml' @@ -781,14 +795,17 @@ function Write-PodeXmlResponse { [Parameter()] [int] - $StatusCode = 200 + $StatusCode = 200, + + [switch] + $UsePropertyName ) begin { $pipelineValue = @() } process { - if ($PSCmdlet.ParameterSetName -eq 'Value') { + if ($PSCmdlet.ParameterSetName -eq 'Value' -and $_) { $pipelineValue += $_ } } @@ -806,7 +823,11 @@ function Write-PodeXmlResponse { if ($pipelineValue) { $Value = $pipelineValue } + if ($Value -isnot [string]) { + if ($UsePropertyName.IsPresent) { + $Value = Resolve-PodeObjectArray -Property $Value + } $Value = ($Value | ConvertTo-Xml -Depth $Depth -As String -NoTypeInformation) } } @@ -902,6 +923,13 @@ function Write-PodeYamlResponse { if ($pipelineValue) { $Value = $pipelineValue } + + if ($Value -is [hashtable]) { + $Value = @(foreach ($v in $Value) { + New-Object psobject -Property $v + }) + } + if ($Value -isnot [string]) { $Value = ConvertTo-PodeYaml -InputObject $Value -Depth $Depth diff --git a/tests/unit/Responses.Tests.ps1 b/tests/unit/Responses.Tests.ps1 index 00e02dea4..c97b1538d 100644 --- a/tests/unit/Responses.Tests.ps1 +++ b/tests/unit/Responses.Tests.ps1 @@ -274,11 +274,35 @@ Describe 'Write-PodeXmlResponse' { } It 'Converts and returns a value from a hashtable' { - $r = Write-PodeXmlResponse -Value @{ 'name' = 'john' } + $r = Write-PodeXmlResponse -Value @{ 'name' = 'john' } -UsePropertyName ($r.Value -ireplace '[\r\n ]', '') | Should -Be 'john' $r.ContentType | Should -Be $_ContentType } + It 'Converts and returns a value from a array of hashtable by pipe' { + $r = @(@{ Name = 'Rick' }, @{ Name = 'Don' }) | Write-PodeXmlResponse -UsePropertyName + ($r.Value -ireplace '[\r\n ]', '') | Should -Be 'RickDon' + $r.ContentType | Should -Be $_ContentType + } + + It 'Converts and returns a value from a array of hashtable' { + $r = Write-PodeXmlResponse -Value @(@{ Name = 'Rick' }, @{ Name = 'Don' }) -UsePropertyName + ($r.Value -ireplace '[\r\n ]', '') | Should -Be 'RickDon' + $r.ContentType | Should -Be $_ContentType + } + It 'Converts and returns a value from a array of process' { + $myProcess = Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | + Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | + Sort-Object WS -Descending + Write-PodeXmlResponse -StatusCode 200 -Value $myProcess +} + +It 'Converts and returns a value from a array of process pipe' { + $myProcess = Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | + Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | + Sort-Object WS -Descending| + Write-PodeXmlResponse -StatusCode 200 +} It 'Does nothing for an invalid file path' { Mock Test-PodePath { return $false } Write-PodeXmlResponse -Path 'fake-file' | Out-Null From 5d30182d16c34827b91718c9b6d017024803843d Mon Sep 17 00:00:00 2001 From: mdaneri Date: Wed, 29 May 2024 21:43:26 -0700 Subject: [PATCH 006/177] Remove -UsePropetyName because redundant Remove -UsePropetyName because redundant added additional tests --- examples/Write-Response.ps1 | 6 +- src/Private/Helpers.ps1 | 117 ++++++++++++++++++++++----------- src/Public/Responses.ps1 | 54 ++++++++------- tests/unit/Responses.Tests.ps1 | 77 +++++++++++++++++----- 4 files changed, 174 insertions(+), 80 deletions(-) diff --git a/examples/Write-Response.ps1 b/examples/Write-Response.ps1 index 55ea34fac..61fa4ee06 100644 --- a/examples/Write-Response.ps1 +++ b/examples/Write-Response.ps1 @@ -91,7 +91,7 @@ Start-PodeServer { Add-PodeRoute -Path '/xml/hash' -Method Get -ScriptBlock { - Write-PodeXmlResponse -Value @(@{ Name = 'Rick' }, @{ Name = 'Don' }) -UsePropertyName + Write-PodeXmlResponse -Value @(@{ Name = 'Rick' }, @{ Name = 'Don' }) } # nopipe @@ -110,7 +110,7 @@ Start-PodeServer { } Start-Job -ScriptBlock { Start-Sleep -Seconds 5 - <# Start-Process http://localhost:8081/html/processesPiped + Start-Process http://localhost:8081/html/processesPiped Start-Process http://localhost:8081/html/processes Start-Process http://localhost:8081/text/processesPiped Start-Process http://localhost:8081/text/processes @@ -120,7 +120,7 @@ Start-PodeServer { Start-Process http://localhost:8081/csv/hash Start-Process http://localhost:8081/json/processesPiped Start-Process http://localhost:8081/json/processes - #> Start-Process http://localhost:8081/xml/processesPiped + Start-Process http://localhost:8081/xml/processesPiped Start-Process http://localhost:8081/xml/processes Start-Process http://localhost:8081/xml/hash Start-Process http://localhost:8081/yaml/processesPiped diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index cefaaf492..c9b1dedf2 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -3018,31 +3018,31 @@ function Test-PodeVersionDev { <# .SYNOPSIS -Tests the running PowerShell version for compatibility with Pode, identifying end-of-life (EOL) and untested versions. + Tests the running PowerShell version for compatibility with Pode, identifying end-of-life (EOL) and untested versions. .DESCRIPTION -The `Test-PodeVersionPwshEOL` function checks the current PowerShell version against a list of versions that were either supported or EOL at the time of the Pode release. It uses the module manifest to determine which PowerShell versions are considered EOL and which are officially supported. If the current version is EOL or was not tested with the current release of Pode, the function generates a warning. This function aids in maintaining best practices for using supported PowerShell versions with Pode. + The `Test-PodeVersionPwshEOL` function checks the current PowerShell version against a list of versions that were either supported or EOL at the time of the Pode release. It uses the module manifest to determine which PowerShell versions are considered EOL and which are officially supported. If the current version is EOL or was not tested with the current release of Pode, the function generates a warning. This function aids in maintaining best practices for using supported PowerShell versions with Pode. .PARAMETER ReportUntested -If specified, the function will report if the current PowerShell version was not available and thus untested at the time of the Pode release. This is useful for identifying potential compatibility issues with newer versions of PowerShell. + If specified, the function will report if the current PowerShell version was not available and thus untested at the time of the Pode release. This is useful for identifying potential compatibility issues with newer versions of PowerShell. .OUTPUTS -A hashtable containing two keys: -- `eol`: A boolean indicating if the current PowerShell version was EOL at the time of the Pode release. -- `supported`: A boolean indicating if the current PowerShell version was officially supported by Pode at the time of the release. + A hashtable containing two keys: + - `eol`: A boolean indicating if the current PowerShell version was EOL at the time of the Pode release. + - `supported`: A boolean indicating if the current PowerShell version was officially supported by Pode at the time of the release. .EXAMPLE -Test-PodeVersionPwshEOL + Test-PodeVersionPwshEOL -Checks the current PowerShell version against Pode's supported and EOL versions list. Outputs a warning if the version is EOL or untested, and returns a hashtable indicating the compatibility status. + Checks the current PowerShell version against Pode's supported and EOL versions list. Outputs a warning if the version is EOL or untested, and returns a hashtable indicating the compatibility status. .EXAMPLE -Test-PodeVersionPwshEOL -ReportUntested + Test-PodeVersionPwshEOL -ReportUntested -Similar to the basic usage, but also reports if the current PowerShell version was untested because it was not available at the time of the Pode release. + Similar to the basic usage, but also reports if the current PowerShell version was untested because it was not available at the time of the Pode release. .NOTES -This function is part of the Pode module's utilities to ensure compatibility and encourage the use of supported PowerShell versions. + This function is part of the Pode module's utilities to ensure compatibility and encourage the use of supported PowerShell versions. #> function Test-PodeVersionPwshEOL { @@ -3081,15 +3081,19 @@ function Test-PodeVersionPwshEOL { <# .SYNOPSIS -creates a YAML description of the data in the object - based on https://github.com/Phil-Factor/PSYaml + creates a YAML description of the data in the object - based on https://github.com/Phil-Factor/PSYaml + .DESCRIPTION -This produces YAML from any object you pass to it. It isn't suitable for the huge objects produced by some of the cmdlets such as Get-Process, but fine for simple objects -.PARAMETER Object -the object that you want scripted out + This produces YAML from any object you pass to it. It isn't suitable for the huge objects produced by some of the cmdlets such as Get-Process, but fine for simple objects + + .PARAMETER Object + The object that you want scripted out + .PARAMETER Depth -The depth that you want your object scripted to + The depth that you want your object scripted to + .EXAMPLE -Get-PodeOpenApiDefinition|ConvertTo-PodeYaml + Get-PodeOpenApiDefinition|ConvertTo-PodeYaml #> function ConvertTo-PodeYaml { [CmdletBinding()] @@ -3118,36 +3122,36 @@ function ConvertTo-PodeYaml { <# .SYNOPSIS - Converts PowerShell objects into a YAML-formatted string. + Converts PowerShell objects into a YAML-formatted string. .DESCRIPTION - This function takes PowerShell objects and converts them to a YAML string representation. - It supports various data types including arrays, hashtables, strings, and more. - The depth of conversion can be controlled, allowing for nested objects to be accurately represented. + This function takes PowerShell objects and converts them to a YAML string representation. + It supports various data types including arrays, hashtables, strings, and more. + The depth of conversion can be controlled, allowing for nested objects to be accurately represented. .PARAMETER InputObject - The PowerShell object to convert to YAML. This parameter accepts input via the pipeline. + The PowerShell object to convert to YAML. This parameter accepts input via the pipeline. .PARAMETER Depth - Specifies the maximum depth of object nesting to convert. Default is 10 levels deep. + Specifies the maximum depth of object nesting to convert. Default is 10 levels deep. .PARAMETER NestingLevel - Used internally to track the current depth of recursion. Generally not specified by the user. + Used internally to track the current depth of recursion. Generally not specified by the user. .PARAMETER NoNewLine - If specified, suppresses the newline characters in the output to create a single-line string. + If specified, suppresses the newline characters in the output to create a single-line string. .OUTPUTS - System.String. Returns a string in YAML format. + System.String. Returns a string in YAML format. .EXAMPLE - $object | ConvertTo-PodeYamlInternal + $object | ConvertTo-PodeYamlInternal - Converts the object piped to it into a YAML string. + Converts the object piped to it into a YAML string. .NOTES - This is an internal function and may change in future releases of Pode. - It converts only basic PowerShell types, such as strings, integers, booleans, arrays, hashtables, and ordered dictionaries into a YAML format. + This is an internal function and may change in future releases of Pode. + It converts only basic PowerShell types, such as strings, integers, booleans, arrays, hashtables, and ordered dictionaries into a YAML format. #> @@ -3319,29 +3323,64 @@ function ConvertTo-PodeYamlInternal { } +<# +.SYNOPSIS + Resolves various types of object arrays into PowerShell objects. + +.DESCRIPTION + This function takes an input property and determines its type. + It then resolves the property into a PowerShell object or an array of objects, + depending on whether the property is a hashtable, array, or single object. + +.PARAMETER Property + The property to be resolved. It can be a hashtable, an object array, or a single object. + +.RETURNS + Returns a PowerShell object or an array of PowerShell objects, depending on the input property type. + +.EXAMPLE + $result = Resolve-PodeObjectArray -Property $myProperty + This example resolves the $myProperty into a PowerShell object or an array of objects. +.NOTES + This is an internal function and may change in future releases of Pode. +#> function Resolve-PodeObjectArray { + [CmdletBinding()] + [OutputType([object[]])] + [OutputType([psobject])] param ( [AllowNull()] + [object] $Property ) + + # Check if the property is a hashtable if ($Property -is [hashtable]) { + # If the hashtable has only one item, convert it to a PowerShell object if ($Property.Count -eq 1) { - return New-Object psobject -Property $Property + return New-Object psobject -Property $Property } else { - return @(foreach ($v in $Property) { - Resolve-PodeObjectArray -Property $v - }) + # If the hashtable has more than one item, recursively resolve each item + return @(foreach ($p in $Property) { + Resolve-PodeObjectArray -Property $p + }) } } + # Check if the property is an array of objects elseif ($Property -is [object[]]) { - return @(foreach ($v in $Property) { - Resolve-PodeObjectArray -Property $v - - }) + # Recursively resolve each item in the array + return @(foreach ($p in $Property) { + Resolve-PodeObjectArray -Property $p + }) + } + # Check if the property is already a PowerShell object + elseif ($Property -is [psobject]) { + return $Property } else { - return New-Object psobject -Property $Property + # For any other type, convert it to a PowerShell object + return New-Object psobject -Property $Property } } \ No newline at end of file diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index 1f91c17d7..a1d142157 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -431,9 +431,6 @@ The path to a CSV file. .PARAMETER StatusCode The status code to set against the response. -.PARAMETER UsePropertyName -The elements name is equal to the key value - .EXAMPLE Write-PodeCsvResponse -Value "Name`nRick" @@ -455,19 +452,20 @@ function Write-PodeCsvResponse { [Parameter()] [int] - $StatusCode = 200, - - [switch] - $UsePropertyName + $StatusCode = 200 ) + begin { $pipelineValue = @() } + process { if ($PSCmdlet.ParameterSetName -eq 'Value') { $pipelineValue += $_ } - } end { + } + + end { switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 'file' { if (Test-PodePath $Path) { @@ -481,9 +479,7 @@ function Write-PodeCsvResponse { } if ($Value -isnot [string]) { - if ($UsePropertyName.IsPresent) { - $Value = Resolve-PodeObjectArray -Property $Value - } + $Value = Resolve-PodeObjectArray -Property $Value if (Test-PodeIsPSCore) { $Value = ($Value | ConvertTo-Csv -Delimiter ',' -IncludeTypeInformation:$false) @@ -765,17 +761,35 @@ The Depth to generate the XML document - the larger this value the worse perform .PARAMETER StatusCode The status code to set against the response. -.PARAMETER UsePropertyName -The elements name is equal to the key value - .EXAMPLE Write-PodeXmlResponse -Value 'Rick' .EXAMPLE -Write-PodeXmlResponse -Value @{ Name = 'Rick' } -StatusCode 201 -UsePropertyName +Write-PodeXmlResponse -Value @{ Name = 'Rick' } -StatusCode 201 + +.EXAMPLE +@(@{ Name = 'Rick' }, @{ Name = 'Don' }) | Write-PodeXmlResponse + +.EXAMPLE +$users = @([PSCustomObject]@{ + Name = 'Rick' + }, [PSCustomObject]@{ + Name = 'Don' + } + ) +Write-PodeXmlResponse -Value $users + +.EXAMPLE +@([PSCustomObject]@{ + Name = 'Rick' + }, [PSCustomObject]@{ + Name = 'Don' + } +) | Write-PodeXmlResponse .EXAMPLE Write-PodeXmlResponse -Path 'E:/Files/Names.xml' + #> function Write-PodeXmlResponse { [CmdletBinding(DefaultParameterSetName = 'Value')] @@ -795,10 +809,7 @@ function Write-PodeXmlResponse { [Parameter()] [int] - $StatusCode = 200, - - [switch] - $UsePropertyName + $StatusCode = 200 ) begin { $pipelineValue = @() @@ -825,10 +836,7 @@ function Write-PodeXmlResponse { } if ($Value -isnot [string]) { - if ($UsePropertyName.IsPresent) { - $Value = Resolve-PodeObjectArray -Property $Value - } - $Value = ($Value | ConvertTo-Xml -Depth $Depth -As String -NoTypeInformation) + $Value = Resolve-PodeObjectArray -Property $Value | ConvertTo-Xml -Depth $Depth -As String -NoTypeInformation } } } diff --git a/tests/unit/Responses.Tests.ps1 b/tests/unit/Responses.Tests.ps1 index c97b1538d..b3ecd887e 100644 --- a/tests/unit/Responses.Tests.ps1 +++ b/tests/unit/Responses.Tests.ps1 @@ -239,6 +239,41 @@ Describe 'Write-PodeCsvResponse' { $r.ContentType | Should -Be $_ContentType } + It 'Converts and returns a value from a array of hashtable' { + $r = Write-PodeCsvResponse -Value @(@{ Name = 'Rick' }, @{ Name = 'Don' }) + $r.Value | Should -Be "`"Name`"$([environment]::NewLine)`"Rick`"$([environment]::NewLine)`"Don`"" + $r.ContentType | Should -Be $_ContentType + } + + It 'Converts and returns a value from a array of hashtable by Pipe' { + $r = @(@{ Name = 'Rick' }, @{ Name = 'Don' }) | Write-PodeCsvResponse + $r.Value | Should -Be "`"Name`"$([environment]::NewLine)`"Rick`"$([environment]::NewLine)`"Don`"" + $r.ContentType | Should -Be $_ContentType + } + + It 'Converts and returns a value from a array of PSCustomObject' { + $users = @([PSCustomObject]@{ + Name = 'Rick' + }, [PSCustomObject]@{ + Name = 'Don' + } + ) + $r = Write-PodeCsvResponse -Value $users + $r.Value | Should -Be "`"Name`"$([environment]::NewLine)`"Rick`"$([environment]::NewLine)`"Don`"" + $r.ContentType | Should -Be $_ContentType + } + + It 'Converts and returns a value from a array of PSCustomObject by Pipe' { + $r = @([PSCustomObject]@{ + Name = 'Rick' + }, [PSCustomObject]@{ + Name = 'Don' + } + ) | Write-PodeCsvResponse + $r.Value | Should -Be "`"Name`"$([environment]::NewLine)`"Rick`"$([environment]::NewLine)`"Don`"" + $r.ContentType | Should -Be $_ContentType + } + It 'Does nothing for an invalid file path' { Mock Test-PodePath { return $false } Write-PodeCsvResponse -Path 'fake-file' | Out-Null @@ -274,35 +309,47 @@ Describe 'Write-PodeXmlResponse' { } It 'Converts and returns a value from a hashtable' { - $r = Write-PodeXmlResponse -Value @{ 'name' = 'john' } -UsePropertyName + $r = Write-PodeXmlResponse -Value @{ 'name' = 'john' } ($r.Value -ireplace '[\r\n ]', '') | Should -Be 'john' $r.ContentType | Should -Be $_ContentType } It 'Converts and returns a value from a array of hashtable by pipe' { - $r = @(@{ Name = 'Rick' }, @{ Name = 'Don' }) | Write-PodeXmlResponse -UsePropertyName + $r = @(@{ Name = 'Rick' }, @{ Name = 'Don' }) | Write-PodeXmlResponse ($r.Value -ireplace '[\r\n ]', '') | Should -Be 'RickDon' $r.ContentType | Should -Be $_ContentType } It 'Converts and returns a value from a array of hashtable' { - $r = Write-PodeXmlResponse -Value @(@{ Name = 'Rick' }, @{ Name = 'Don' }) -UsePropertyName + $r = Write-PodeXmlResponse -Value @(@{ Name = 'Rick' }, @{ Name = 'Don' }) ($r.Value -ireplace '[\r\n ]', '') | Should -Be 'RickDon' $r.ContentType | Should -Be $_ContentType } - It 'Converts and returns a value from a array of process' { - $myProcess = Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | - Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | - Sort-Object WS -Descending - Write-PodeXmlResponse -StatusCode 200 -Value $myProcess -} -It 'Converts and returns a value from a array of process pipe' { - $myProcess = Get-Process | .{ process { if ($_.WS -gt 100mb) { $_ } } } | - Select-Object Name, @{e = { [int]($_.WS / 1mb) }; n = 'WS' } | - Sort-Object WS -Descending| - Write-PodeXmlResponse -StatusCode 200 -} + It 'Converts and returns a value from a array of PSCustomObject' { + $users = @([PSCustomObject]@{ + Name = 'Rick' + }, [PSCustomObject]@{ + Name = 'Don' + } + ) + $r = Write-PodeXmlResponse -Value $users + ($r.Value -ireplace '[\r\n ]', '') | Should -Be 'RickDon' + $r.ContentType | Should -Be $_ContentType + } + + It 'Converts and returns a value from a array of PSCustomObject passed by pipe' { + $r = @([PSCustomObject]@{ + Name = 'Rick' + }, [PSCustomObject]@{ + Name = 'Don' + } + ) | Write-PodeXmlResponse + ($r.Value -ireplace '[\r\n ]', '') | Should -Be 'RickDon' + $r.ContentType | Should -Be $_ContentType + } + + It 'Does nothing for an invalid file path' { Mock Test-PodePath { return $false } Write-PodeXmlResponse -Path 'fake-file' | Out-Null From 6cfebc757d86108e5693b6c44d2b748b57e214d1 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Wed, 29 May 2024 23:15:41 -0700 Subject: [PATCH 007/177] first drop --- src/Locales/ar/Pode.psd1 | 24 ++++++++++++++++++++++++ src/Locales/de/Pode.psd1 | 24 ++++++++++++++++++++++++ src/Locales/en/Pode.psd1 | 24 ++++++++++++++++++++++++ src/Locales/es/Pode.psd1 | 24 ++++++++++++++++++++++++ src/Locales/fr/Pode.psd1 | 24 ++++++++++++++++++++++++ src/Locales/it/Pode.psd1 | 24 ++++++++++++++++++++++++ src/Locales/ja/Pode.psd1 | 24 ++++++++++++++++++++++++ src/Locales/zn/Pode.psd1 | 24 ++++++++++++++++++++++++ src/Pode.psm1 | 6 +++++- src/Private/Authentication.ps1 | 4 ++-- src/Private/AutoImport.ps1 | 4 ++-- src/Private/Context.ps1 | 4 ++-- src/Private/CronParser.ps1 | 20 ++++++++++---------- src/Private/Endpoints.ps1 | 4 ++-- src/Private/Gui.ps1 | 2 +- src/Private/Helpers.ps1 | 8 ++++---- 16 files changed, 220 insertions(+), 24 deletions(-) create mode 100644 src/Locales/ar/Pode.psd1 create mode 100644 src/Locales/de/Pode.psd1 create mode 100644 src/Locales/en/Pode.psd1 create mode 100644 src/Locales/es/Pode.psd1 create mode 100644 src/Locales/fr/Pode.psd1 create mode 100644 src/Locales/it/Pode.psd1 create mode 100644 src/Locales/ja/Pode.psd1 create mode 100644 src/Locales/zn/Pode.psd1 diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 new file mode 100644 index 000000000..323254bb1 --- /dev/null +++ b/src/Locales/ar/Pode.psd1 @@ -0,0 +1,24 @@ +ConvertFrom-StringData -StringData @' +adModuleWindowsOnlyMessage = وحدة Active Directory متاحة فقط على نظام Windows +adModuleNotInstalledMessage = وحدة Active Directory غير مثبتة +secretManagementModuleNotInstalledMessage = وحدة Microsoft.PowerShell.SecretManagement غير مثبتة +secretVaultAlreadyRegisteredMessage = تم تسجيل خزنة سرية بالاسم '{0}' بالفعل أثناء الاستيراد التلقائي للخزن السرية +failedToOpenRunspacePoolMessage = فشل في فتح RunspacePool: {0} +cronExpressionInvalidMessage = يجب أن تتكون تعبير Cron فقط من 5 أجزاء: {0} +invalidAliasFoundMessage = تم العثور على اسم مستعار غير صالح {0}: {1} +invalidAtomCharacterMessage = حرف ذري غير صالح: {0} +minValueGreaterThanMaxMessage = يجب ألا تكون القيمة الدنيا لـ {0} أكبر من القيمة القصوى +minValueInvalidMessage = القيمة الدنيا '{0}' لـ {1} غير صالحة، يجب أن تكون أكبر من أو تساوي {2} +maxValueInvalidMessage = القيمة القصوى '{0}' لـ {1} غير صالحة، يجب أن تكون أقل من أو تساوي {2} +valueOutOfRangeMessage = القيمة '{0}' لـ {1} غير صالحة، يجب أن تكون بين {2} و {3} +daysInMonthExceededMessage = {0} يحتوي فقط على {1} أيام، ولكن تم توفير {2} +nextTriggerCalculationErrorMessage = يبدو أن هناك خطأ ما عند محاولة حساب تاريخ ووقت التشغيل التالي: {0} +incompatiblePodeDllMessage = تم تحميل إصدار غير متوافق موجود من Pode.DLL {0}. الإصدار {1} مطلوب. افتح جلسة Powershell/pwsh جديدة وحاول مرة أخرى. +endpointNotExistMessage = لا يوجد نقطة نهاية بالبروتوكول '{0}' والعنوان '{1}' أو العنوان المحلي '{2}' +endpointNameNotExistMessage = لا يوجد نقطة نهاية بالاسم '{0}' +failedToConnectToUrlMessage = فشل الاتصال بعنوان URL: {0} +failedToParseAddressMessage = فشل في تحليل '{0}' كعنوان IP/Host:Port صالح +invalidIpAddressMessage = عنوان IP المقدم غير صالح: {0} +invalidPortMessage = لا يمكن أن يكون المنفذ سالبًا: {0} +pathNotExistMessage = المسار غير موجود: {0} +'@ \ No newline at end of file diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 new file mode 100644 index 000000000..0e38fb2a5 --- /dev/null +++ b/src/Locales/de/Pode.psd1 @@ -0,0 +1,24 @@ +ConvertFrom-StringData -StringData @' +adModuleWindowsOnlyMessage = Das Active Directory-Modul ist nur unter Windows verfügbar +adModuleNotInstalledMessage = Das Active Directory-Modul ist nicht installiert +secretManagementModuleNotInstalledMessage = Das Microsoft.PowerShell.SecretManagement-Modul ist nicht installiert +secretVaultAlreadyRegisteredMessage = Ein Secret Vault mit dem Namen '{0}' wurde bereits beim automatischen Importieren von Secret Vaults registriert +failedToOpenRunspacePoolMessage = Fehler beim Öffnen des RunspacePool: {0} +cronExpressionInvalidMessage = Cron-Ausdruck sollte nur aus 5 Teilen bestehen: {0} +invalidAliasFoundMessage = Ungültiger {0} Alias gefunden: {1} +invalidAtomCharacterMessage = Ungültiges Atomzeichen: {0} +minValueGreaterThanMaxMessage = Der Mindestwert für {0} sollte nicht größer als der Höchstwert sein +minValueInvalidMessage = Der Mindestwert '{0}' für {1} ist ungültig, sollte größer oder gleich {2} sein +maxValueInvalidMessage = Der Höchstwert '{0}' für {1} ist ungültig, sollte kleiner oder gleich {2} sein +valueOutOfRangeMessage = Der Wert '{0}' für {1} ist ungültig, sollte zwischen {2} und {3} liegen +daysInMonthExceededMessage = {0} hat nur {1} Tage, aber {2} wurde angegeben +nextTriggerCalculationErrorMessage = Es scheint, dass beim Versuch, das nächste Trigger-Datum und die nächste Uhrzeit zu berechnen, etwas schiefgelaufen ist: {0} +incompatiblePodeDllMessage = Eine vorhandene inkompatible Version von Pode.DLL {0} ist geladen. Version {1} wird benötigt. Öffnen Sie eine neue Powershell/pwsh-Sitzung und versuchen Sie es erneut. +endpointNotExistMessage = Ein Endpunkt mit dem Protokoll '{0}' und der Adresse '{1}' oder der lokalen Adresse '{2}' existiert nicht +endpointNameNotExistMessage = Ein Endpunkt mit dem Namen '{0}' existiert nicht +failedToConnectToUrlMessage = Fehler beim Verbinden mit der URL: {0} +failedToParseAddressMessage = Fehler beim Parsen von '{0}' als gültige IP/Host:Port-Adresse +invalidIpAddressMessage = Die angegebene IP-Adresse ist ungültig: {0} +invalidPortMessage = Der Port kann nicht negativ sein: {0} +pathNotExistMessage = Pfad existiert nicht: {0} +'@ \ No newline at end of file diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 new file mode 100644 index 000000000..25956ad06 --- /dev/null +++ b/src/Locales/en/Pode.psd1 @@ -0,0 +1,24 @@ +ConvertFrom-StringData -StringData @' +adModuleWindowsOnlyMessage = Active Directory module only available on Windows +adModuleNotInstalledMessage = Active Directory module is not installed +secretManagementModuleNotInstalledMessage = Microsoft.PowerShell.SecretManagement module not installed +secretVaultAlreadyRegisteredMessage = A Secret Vault with the name '{0}' has already been registered while auto-importing Secret Vaults +failedToOpenRunspacePoolMessage = Failed to open RunspacePool: {0} +cronExpressionInvalidMessage = Cron expression should only consist of 5 parts: {0} +invalidAliasFoundMessage = Invalid {0} alias found: {1} +invalidAtomCharacterMessage = Invalid atom character: {0} +minValueGreaterThanMaxMessage = Min value for {0} should not be greater than the max value +minValueInvalidMessage = Min value '{0}' for {1} is invalid, should be greater than/equal to {2} +maxValueInvalidMessage = Max value '{0}' for {1} is invalid, should be less than/equal to {2} +valueOutOfRangeMessage = Value '{0}' for {1} is invalid, should be between {2} and {3} +daysInMonthExceededMessage = {0} only has {1} days, but {2} was supplied +nextTriggerCalculationErrorMessage = Looks like something went wrong trying to calculate the next trigger datetime: {0} +incompatiblePodeDllMessage = An existing incompatible Pode.DLL version {0} is loaded. Version {1} is required. Open a new Powershell/pwsh session and retry. +endpointNotExistMessage = Endpoint with protocol '{0}' and address '{1}' or local address '{2}' does not exist +endpointNameNotExistMessage = Endpoint with name '{0}' does not exist +failedToConnectToUrlMessage = Failed to connect to URL: {0} +failedToParseAddressMessage = Failed to parse '{0}' as a valid IP/Host:Port address +invalidIpAddressMessage = The IP address supplied is invalid: {0} +invalidPortMessage = The port cannot be negative: {0} +pathNotExistMessage = Path does not exist: {0} +'@ \ No newline at end of file diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 new file mode 100644 index 000000000..67ac8cc3e --- /dev/null +++ b/src/Locales/es/Pode.psd1 @@ -0,0 +1,24 @@ +ConvertFrom-StringData -StringData @' +adModuleWindowsOnlyMessage = El módulo de Active Directory solo está disponible en Windows +adModuleNotInstalledMessage = El módulo de Active Directory no está instalado +secretManagementModuleNotInstalledMessage = El módulo Microsoft.PowerShell.SecretManagement no está instalado +secretVaultAlreadyRegisteredMessage = Ya se ha registrado un Bóveda Secreta con el nombre '{0}' al importar automáticamente Bóvedas Secretas +failedToOpenRunspacePoolMessage = Error al abrir RunspacePool: {0} +cronExpressionInvalidMessage = La expresión Cron solo debe consistir en 5 partes: {0} +invalidAliasFoundMessage = Se encontró un alias {0} no válido: {1} +invalidAtomCharacterMessage = Carácter atómico no válido: {0} +minValueGreaterThanMaxMessage = El valor mínimo para {0} no debe ser mayor que el valor máximo +minValueInvalidMessage = El valor mínimo '{0}' para {1} no es válido, debe ser mayor o igual a {2} +maxValueInvalidMessage = El valor máximo '{0}' para {1} no es válido, debe ser menor o igual a {2} +valueOutOfRangeMessage = El valor '{0}' para {1} no es válido, debe estar entre {2} y {3} +daysInMonthExceededMessage = {0} solo tiene {1} días, pero se suministró {2} +nextTriggerCalculationErrorMessage = Parece que algo salió mal al intentar calcular la siguiente fecha y hora del disparador: {0} +incompatiblePodeDllMessage = Se ha cargado una versión incompatible existente de Pode.DLL {0}. Se requiere la versión {1}. Abra una nueva sesión de Powershell/pwsh e intente de nuevo. +endpointNotExistMessage = No existe un punto de conexión con el protocolo '{0}' y la dirección '{1}' o la dirección local '{2}' +endpointNameNotExistMessage = No existe un punto de conexión con el nombre '{0}' +failedToConnectToUrlMessage = Error al conectar con la URL: {0} +failedToParseAddressMessage = Error al analizar '{0}' como una dirección IP/Host:Puerto válida +invalidIpAddressMessage = La dirección IP suministrada no es válida: {0} +invalidPortMessage = El puerto no puede ser negativo: {0} +pathNotExistMessage = La ruta no existe: {0} +'@ \ No newline at end of file diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 new file mode 100644 index 000000000..f7c33aa37 --- /dev/null +++ b/src/Locales/fr/Pode.psd1 @@ -0,0 +1,24 @@ +ConvertFrom-StringData -StringData @' +adModuleWindowsOnlyMessage = Le module Active Directory est uniquement disponible sur Windows +adModuleNotInstalledMessage = Le module Active Directory n'est pas installé +secretManagementModuleNotInstalledMessage = Le module Microsoft.PowerShell.SecretManagement n'est pas installé +secretVaultAlreadyRegisteredMessage = Un coffre-fort secret avec le nom '{0}' a déjà été enregistré lors de l'importation automatique des coffres-forts secrets +failedToOpenRunspacePoolMessage = Échec de l'ouverture de RunspacePool : {0} +cronExpressionInvalidMessage = L'expression Cron doit uniquement comporter 5 parties : {0} +invalidAliasFoundMessage = Alias {0} non valide trouvé : {1} +invalidAtomCharacterMessage = Caractère atomique non valide : {0} +minValueGreaterThanMaxMessage = La valeur minimale pour {0} ne doit pas être supérieure à la valeur maximale +minValueInvalidMessage = La valeur minimale '{0}' pour {1} n'est pas valide, elle doit être supérieure ou égale à {2} +maxValueInvalidMessage = La valeur maximale '{0}' pour {1} n'est pas valide, elle doit être inférieure ou égale à {2} +valueOutOfRangeMessage = La valeur '{0}' pour {1} n'est pas valide, elle doit être comprise entre {2} et {3} +daysInMonthExceededMessage = {0} n'a que {1} jours, mais {2} a été fourni +nextTriggerCalculationErrorMessage = Il semble que quelque chose ait mal tourné lors de la tentative de calcul de la prochaine date et heure de déclenchement : {0} +incompatiblePodeDllMessage = Une version incompatible existante de Pode.DLL {0} est chargée. La version {1} est requise. Ouvrez une nouvelle session Powershell/pwsh et réessayez. +endpointNotExistMessage = Un point de terminaison avec le protocole '{0}' et l'adresse '{1}' ou l'adresse locale '{2}' n'existe pas +endpointNameNotExistMessage = Un point de terminaison avec le nom '{0}' n'existe pas +failedToConnectToUrlMessage = Échec de la connexion à l'URL : {0} +failedToParseAddressMessage = Échec de l'analyse de '{0}' en tant qu'adresse IP/Hôte:Port valide +invalidIpAddressMessage = L'adresse IP fournie n'est pas valide : {0} +invalidPortMessage = Le port ne peut pas être négatif : {0} +pathNotExistMessage = Le chemin n'existe pas : {0} +'@ \ No newline at end of file diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 new file mode 100644 index 000000000..b542ea731 --- /dev/null +++ b/src/Locales/it/Pode.psd1 @@ -0,0 +1,24 @@ +ConvertFrom-StringData -StringData @' +adModuleWindowsOnlyMessage = Il modulo di Active Directory è disponibile solo su Windows +adModuleNotInstalledMessage = Il modulo di Active Directory non è installato +secretManagementModuleNotInstalledMessage = Il modulo Microsoft.PowerShell.SecretManagement non è installato +secretVaultAlreadyRegisteredMessage = Una Secret Vault con il nome '{0}' è già stata registrata durante l'importazione automatica delle Secret Vaults +failedToOpenRunspacePoolMessage = Errore nell'apertura di RunspacePool: {0} +cronExpressionInvalidMessage = L'espressione Cron deve consistere solo di 5 parti: {0} +invalidAliasFoundMessage = Alias {0} non valido trovato: {1} +invalidAtomCharacterMessage = Carattere atomico non valido: {0} +minValueGreaterThanMaxMessage = Il valore minimo per {0} non deve essere maggiore del valore massimo +minValueInvalidMessage = Il valore minimo '{0}' per {1} non è valido, deve essere maggiore o uguale a {2} +maxValueInvalidMessage = Il valore massimo '{0}' per {1} non è valido, deve essere minore o uguale a {2} +valueOutOfRangeMessage = Il valore '{0}' per {1} non è valido, deve essere compreso tra {2} e {3} +daysInMonthExceededMessage = {0} ha solo {1} giorni, ma è stato fornito {2} +nextTriggerCalculationErrorMessage = Sembra che qualcosa sia andato storto nel tentativo di calcolare la prossima data e ora del trigger: {0} +incompatiblePodeDllMessage = È stata caricata una versione incompatibile esistente di Pode.DLL {0}. È richiesta la versione {1}. Aprire una nuova sessione di Powershell/pwsh e riprovare. +endpointNotExistMessage = Non esiste un endpoint con il protocollo '{0}' e l'indirizzo '{1}' o l'indirizzo locale '{2}' +endpointNameNotExistMessage = Non esiste un endpoint con il nome '{0}' +failedToConnectToUrlMessage = Errore nella connessione all'URL: {0} +failedToParseAddressMessage = Errore nell'analisi di '{0}' come indirizzo IP/Host:Porto valido +invalidIpAddressMessage = L'indirizzo IP fornito non è valido: {0} +invalidPortMessage = La porta non può essere negativa: {0} +pathNotExistMessage = Il percorso non esiste: {0} +'@ \ No newline at end of file diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 new file mode 100644 index 000000000..18b377c3b --- /dev/null +++ b/src/Locales/ja/Pode.psd1 @@ -0,0 +1,24 @@ +ConvertFrom-StringData -StringData @' +adModuleWindowsOnlyMessage = Active DirectoryモジュールはWindowsでのみ利用可能です +adModuleNotInstalledMessage = Active Directoryモジュールがインストールされていません +secretManagementModuleNotInstalledMessage = Microsoft.PowerShell.SecretManagementモジュールがインストールされていません +secretVaultAlreadyRegisteredMessage = シークレットボールト'{0}'は既に登録されています(シークレットボールトの自動インポート中) +failedToOpenRunspacePoolMessage = RunspacePoolのオープンに失敗しました: {0} +cronExpressionInvalidMessage = Cron式は5つの部分で構成される必要があります: {0} +invalidAliasFoundMessage = 無効な{0}エイリアスが見つかりました: {1} +invalidAtomCharacterMessage = 無効なアトム文字: {0} +minValueGreaterThanMaxMessage = {0}の最小値は最大値を超えることはできません +minValueInvalidMessage = {1}の最小値'{0}'は無効です。{2}以上でなければなりません +maxValueInvalidMessage = {1}の最大値'{0}'は無効です。{2}以下でなければなりません +valueOutOfRangeMessage = {1}の値'{0}'は無効です。{2}から{3}の間でなければなりません +daysInMonthExceededMessage = {0}は{1}日しかありませんが、{2}が指定されました +nextTriggerCalculationErrorMessage = 次のトリガー日時の計算中に問題が発生したようです: {0} +incompatiblePodeDllMessage = 既存の互換性のないPode.DLLバージョン{0}がロードされています。バージョン{1}が必要です。新しいPowershell/pwshセッションを開いて再試行してください。 +endpointNotExistMessage = プロトコル'{0}'とアドレス'{1}'またはローカルアドレス'{2}'のエンドポイントが存在しません +endpointNameNotExistMessage = 名前'{0}'のエンドポイントが存在しません +failedToConnectToUrlMessage = URLへの接続に失敗しました: {0} +failedToParseAddressMessage = '{0}'を有効なIP/ホスト:ポートアドレスとして解析できませんでした +invalidIpAddressMessage = 提供されたIPアドレスは無効です: {0} +invalidPortMessage = ポートは負であってはなりません: {0} +pathNotExistMessage = パスが存在しません: {0} +'@ \ No newline at end of file diff --git a/src/Locales/zn/Pode.psd1 b/src/Locales/zn/Pode.psd1 new file mode 100644 index 000000000..0e0c8729b --- /dev/null +++ b/src/Locales/zn/Pode.psd1 @@ -0,0 +1,24 @@ +ConvertFrom-StringData -StringData @' +adModuleWindowsOnlyMessage = Active Directory模块仅在Windows上可用 +adModuleNotInstalledMessage = Active Directory模块未安装 +secretManagementModuleNotInstalledMessage = Microsoft.PowerShell.SecretManagement模块未安装 +secretVaultAlreadyRegisteredMessage = 在自动导入秘密库时,名为'{0}'的秘密库已注册 +failedToOpenRunspacePoolMessage = 无法打开RunspacePool: {0} +cronExpressionInvalidMessage = Cron表达式应仅由5部分组成: {0} +invalidAliasFoundMessage = 找到无效的{0}别名:{1} +invalidAtomCharacterMessage = 无效的原子字符:{0} +minValueGreaterThanMaxMessage = {0}的最小值不应大于最大值 +minValueInvalidMessage = {1}的最小值'{0}'无效,应大于或等于{2} +maxValueInvalidMessage = {1}的最大值'{0}'无效,应小于或等于{2} +valueOutOfRangeMessage = {1}的值'{0}'无效,应介于{2}和{3}之间 +daysInMonthExceededMessage = {0}只有{1}天,但提供了{2} +nextTriggerCalculationErrorMessage = 计算下一个触发日期时间时似乎出了问题:{0} +incompatiblePodeDllMessage = 已加载现有的不兼容Pode.DLL版本{0}。需要版本{1}。请打开一个新的Powershell/pwsh会话并重试。 +endpointNotExistMessage = 协议为'{0}'且地址为'{1}'或本地地址为'{2}'的端点不存在 +endpointNameNotExistMessage = 名称为'{0}'的端点不存在 +failedToConnectToUrlMessage = 无法连接到URL: {0} +failedToParseAddressMessage = 无法将'{0}'解析为有效的IP/主机:端口地址 +invalidIpAddressMessage = 提供的IP地址无效:{0} +invalidPortMessage = 端口不能为负:{0} +pathNotExistMessage = 路径不存在:{0} +'@ \ No newline at end of file diff --git a/src/Pode.psm1 b/src/Pode.psm1 index 00a5be399..32d555b03 100644 --- a/src/Pode.psm1 +++ b/src/Pode.psm1 @@ -1,6 +1,9 @@ # root path $root = Split-Path -Parent -Path $MyInvocation.MyCommand.Path +# Import localized messages +Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $root -ChildPath 'Locales') + # load assemblies Add-Type -AssemblyName System.Web Add-Type -AssemblyName System.Net.Http @@ -17,7 +20,7 @@ if ($podeDll) { if ( $moduleManifest.ModuleVersion -ne '$version$') { $moduleVersion = ([version]::new($moduleManifest.ModuleVersion + '.0')) if ($podeDll.GetName().Version -ne $moduleVersion) { - throw "An existing incompatible Pode.DLL version $($podeDll.GetName().Version) is loaded. Version $moduleVersion is required. Open a new Powershell/pwsh session and retry." + throw ($msgTable.incompatiblePodeDllMessage -f $podeDll.GetName().Version, $moduleVersion) #"An existing incompatible Pode.DLL version $($podeDll.GetName().Version) is loaded. Version $moduleVersion is required. Open a new Powershell/pwsh session and retry." } } } @@ -33,6 +36,7 @@ else { } } + # load private functions Get-ChildItem "$($root)/Private/*.ps1" | ForEach-Object { . ([System.IO.Path]::GetFullPath($_)) } diff --git a/src/Private/Authentication.ps1 b/src/Private/Authentication.ps1 index 0656f4bf4..7bf7a6cdd 100644 --- a/src/Private/Authentication.ps1 +++ b/src/Private/Authentication.ps1 @@ -2194,11 +2194,11 @@ function Expand-PodeAuthMerge { function Import-PodeAuthADModule { if (!(Test-PodeIsWindows)) { - throw 'Active Directory module only available on Windows' + throw $msgTable.adModuleWindowsOnlyMessage #'Active Directory module only available on Windows' } if (!(Test-PodeModuleInstalled -Name ActiveDirectory)) { - throw 'Active Directory module is not installed' + throw $msgTable.adModuleNotInstalledMessage #'Active Directory module is not installed' } Import-Module -Name ActiveDirectory -Force -ErrorAction Stop diff --git a/src/Private/AutoImport.ps1 b/src/Private/AutoImport.ps1 index 6af105ab7..f196d577b 100644 --- a/src/Private/AutoImport.ps1 +++ b/src/Private/AutoImport.ps1 @@ -177,7 +177,7 @@ function Import-PodeSecretManagementVaultsIntoRegistry { # error if SecretManagement module not installed if (!(Test-PodeModuleInstalled -Name Microsoft.PowerShell.SecretManagement)) { - throw 'Microsoft.PowerShell.SecretManagement module not installed' + throw $msgTable.secretManagementModuleNotInstalledMessage #'Microsoft.PowerShell.SecretManagement module not installed' } # import the module @@ -195,7 +195,7 @@ function Import-PodeSecretManagementVaultsIntoRegistry { # is a vault with this name already registered? if (Test-PodeSecretVault -Name $vault.Name) { - throw "A Secret Vault with the name '$($vault.Name)' has already been registered while auto-importing Secret Vaults" + throw ($msgTable.secretVaultAlreadyRegisteredMessage -f $vault.Name) #"A Secret Vault with the name '$($vault.Name)' has already been registered while auto-importing Secret Vaults" } # register the vault diff --git a/src/Private/Context.ps1 b/src/Private/Context.ps1 index 457352788..0472e3eed 100644 --- a/src/Private/Context.ps1 +++ b/src/Private/Context.ps1 @@ -666,7 +666,7 @@ function Open-PodeRunspacePools { if ($item.Pool.RunspacePoolStateInfo.State -ieq 'broken') { $item.Pool.EndOpen($item.Result) | Out-Default - throw "Failed to open RunspacePool: $($key)" + throw ($msgTable.failedToOpenRunspacePoolMessage -f $key) #"Failed to open RunspacePool: $($key)" } } @@ -722,7 +722,7 @@ function Close-PodeRunspacePools { if ($item.Pool.RunspacePoolStateInfo.State -ieq 'broken') { $item.Pool.EndClose($item.Result) | Out-Default - throw "Failed to close RunspacePool: $($key)" + throw ($msgTable.failedToOpenRunspacePoolMessage -f $key) #"Failed to open RunspacePool: $($key)" } } diff --git a/src/Private/CronParser.ps1 b/src/Private/CronParser.ps1 index 55336397d..da231d4c5 100644 --- a/src/Private/CronParser.ps1 +++ b/src/Private/CronParser.ps1 @@ -109,7 +109,7 @@ function ConvertFrom-PodeCronExpression { # split and check atoms length $atoms = @($Expression -isplit '\s+') if ($atoms.Length -ne 5) { - throw "Cron expression should only consist of 5 parts: $($Expression)" + throw ($msgTable.cronExpressionInvalidMessage -f $Expression) #"Cron expression should only consist of 5 parts: $($Expression)" } # basic variables @@ -140,7 +140,7 @@ function ConvertFrom-PodeCronExpression { while ($_atom -imatch $aliasRgx) { $_alias = $_aliases[$Matches['tag']] if ($null -eq $_alias) { - throw "Invalid $($_field) alias found: $($Matches['tag'])" + throw ($msgTable.invalidAliasFoundMessage -f $_field, $Matches['tag']) #"Invalid $($_field) alias found: $($Matches['tag'])" } $_atom = $_atom -ireplace $Matches['tag'], $_alias @@ -150,7 +150,7 @@ function ConvertFrom-PodeCronExpression { # ensure atom is a valid value if (!($_atom -imatch '^[\d|/|*|\-|,r]+$')) { - throw "Invalid atom character: $($_atom)" + throw ($msgTable.invalidAtomCharacterMessage -f $_atom)#"Invalid atom character: $($_atom)" } # replace * with min/max constraint @@ -214,28 +214,28 @@ function ConvertFrom-PodeCronExpression { # error else { - throw "Invalid cron atom format found: $($_atom)" + throw ($msgTable.invalidAtomCharacterMessage -f $_atom)#"Invalid cron atom format found: $($_atom)" } # ensure cron expression values are valid if ($null -ne $_cronExp.Range) { if ($_cronExp.Range.Min -gt $_cronExp.Range.Max) { - throw "Min value for $($_field) should not be greater than the max value" + throw ($msgTable.minValueGreaterThanMaxMessage -f $_field) #"Min value for $($_field) should not be greater than the max value" } if ($_cronExp.Range.Min -lt $_constraint[0]) { - throw "Min value '$($_cronExp.Range.Min)' for $($_field) is invalid, should be greater than/equal to $($_constraint[0])" + throw ($msgTable.minValueInvalidMessage -f $_cronExp.Range.Min, $_field, $_constraint[0]) #"Min value '$($_cronExp.Range.Min)' for $($_field) is invalid, should be greater than/equal to $($_constraint[0])" } if ($_cronExp.Range.Max -gt $_constraint[1]) { - throw "Max value '$($_cronExp.Range.Max)' for $($_field) is invalid, should be less than/equal to $($_constraint[1])" + throw ($msgTable.maxValueInvalidMessage -f $_cronExp.Range.Max, $_field, $_constraint[1]) #"Max value '$($_cronExp.Range.Max)' for $($_field) is invalid, should be less than/equal to $($_constraint[1])" } } if ($null -ne $_cronExp.Values) { $_cronExp.Values | ForEach-Object { if ($_ -lt $_constraint[0] -or $_ -gt $_constraint[1]) { - throw "Value '$($_)' for $($_field) is invalid, should be between $($_constraint[0]) and $($_constraint[1])" + throw ($msgTable.valueOutOfRangeMessage -f $value, $_field, $_constraint[0], $_constraint[1]) #"Value '$($_)' for $($_field) is invalid, should be between $($_constraint[0]) and $($_constraint[1])" } } } @@ -250,7 +250,7 @@ function ConvertFrom-PodeCronExpression { foreach ($mon in $cron['Month'].Values) { foreach ($day in $cron['DayOfMonth'].Values) { if ($day -gt $constraints.DaysInMonths[$mon - 1]) { - throw "$($constraints.Months[$mon - 1]) only has $($constraints.DaysInMonths[$mon - 1]) days, but $($day) was supplied" + throw ($msgTable.daysInMonthExceededMessage -f $constraints.Months[$mon - 1], $constraints.DaysInMonths[$mon - 1], $day) #"$($constraints.Months[$mon - 1]) only has $($constraints.DaysInMonths[$mon - 1]) days, but $($day) was supplied" } } } @@ -518,7 +518,7 @@ function Get-PodeCronNextTrigger { # before we return, make sure the time is valid if (!(Test-PodeCronExpression -Expression $Expression -DateTime $NextTime)) { - throw "Looks like something went wrong trying to calculate the next trigger datetime: $($NextTime)" + throw ($msgTable.nextTriggerCalculationErrorMessage -f $NextTime) #"Looks like something went wrong trying to calculate the next trigger datetime: $($NextTime)" } # if before the start or after end then return null diff --git a/src/Private/Endpoints.ps1 b/src/Private/Endpoints.ps1 index 0e0f6c3c7..1cb70a5cc 100644 --- a/src/Private/Endpoints.ps1 +++ b/src/Private/Endpoints.ps1 @@ -282,7 +282,7 @@ function Find-PodeEndpointName { # error? if ($ThrowError) { - throw "Endpoint with protocol '$($Protocol)' and address '$($Address)' or local address '$($_localAddress)' does not exist" + throw ($msgTable.endpointNotExistMessage -f $Protocol, $Address, $_localAddress) #"Endpoint with protocol '$($Protocol)' and address '$($Address)' or local address '$($_localAddress)' does not exist" } return $null @@ -310,7 +310,7 @@ function Get-PodeEndpointByName { # error? if ($ThrowError) { - throw "Endpoint with name '$($Name)' does not exist" + throw ($msgTable.endpointNameNotExistMessage -f $Name) #"Endpoint with name '$($Name)' does not exist" } return $null diff --git a/src/Private/Gui.ps1 b/src/Private/Gui.ps1 index ec5592abf..10a32a695 100644 --- a/src/Private/Gui.ps1 +++ b/src/Private/Gui.ps1 @@ -41,7 +41,7 @@ function Start-PodeGuiRunspace { Start-Sleep -Milliseconds 200 } else { - throw "Failed to connect to URL: $($uri)" + throw ($msgTable.failedToConnectToUrlMessage -f $uri) #"Failed to connect to URL: $($uri)" } } } diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index d16ea4f92..71066827e 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -190,7 +190,7 @@ function Get-PodeEndpointInfo { # validate that we have a valid ip/host:port address if (!(($Address -imatch "^$($cmbdRgx)$") -or ($Address -imatch "^$($hostRgx)[\:]{0,1}") -or ($Address -imatch "[\:]{0,1}$($portRgx)$"))) { - throw "Failed to parse '$($Address)' as a valid IP/Host:Port address" + throw ($msgTable.failedToParseAddressMessage -f $Address)#"Failed to parse '$($Address)' as a valid IP/Host:Port address" } # grab the ip address/hostname @@ -201,7 +201,7 @@ function Get-PodeEndpointInfo { # ensure we have a valid ip address/hostname if (!(Test-PodeIPAddress -IP $_host)) { - throw "The IP address supplied is invalid: $($_host)" + throw ($msgTable.invalidIpAddressMessage -f $_host) #"The IP address supplied is invalid: $($_host)" } # grab the port @@ -212,7 +212,7 @@ function Get-PodeEndpointInfo { # ensure the port is valid if ($_port -lt 0) { - throw "The port cannot be negative: $($_port)" + throw ($msgTable.invalidPortMessage -f $_port)#"The port cannot be negative: $($_port)" } # return the info @@ -873,7 +873,7 @@ function New-PodePSDrive { # if the path supplied doesn't exist, error if (!(Test-Path $Path)) { - throw "Path does not exist: $($Path)" + throw ($msgTable.pathNotExistMessage -f $Path)#"Path does not exist: $($Path)" } # resolve the path From 8a0af281837edc25f58e78a5e91ba32910a8482c Mon Sep 17 00:00:00 2001 From: mdaneri Date: Wed, 29 May 2024 23:35:14 -0700 Subject: [PATCH 008/177] Pester tests fix --- tests/integration/Authentication.Tests.ps1 | 2 + tests/unit/Authentication.Tests.ps1 | 15 ++-- tests/unit/Context.Tests.ps1 | 1 + tests/unit/Cookies.Tests.ps1 | 1 + tests/unit/CronParser.Tests.ps1 | 1 + tests/unit/Cryptography.Tests.ps1 | 1 + tests/unit/Endware.Tests.ps1 | 1 + tests/unit/Flash.Tests.ps1 | 1 + tests/unit/Handlers.Tests.ps1 | 1 + tests/unit/Headers.Tests.ps1 | 1 + tests/unit/Helpers.Tests.ps1 | 5 +- tests/unit/Logging.Tests.ps1 | 1 + tests/unit/Mappers.Tests.ps1 | 5 +- tests/unit/Metrics.Tests.ps1 | 1 + tests/unit/Middleware.Tests.ps1 | 1 + tests/unit/NameGenerator.Tests.ps1 | 1 + tests/unit/OpenApi.Tests.ps1 | 1 + tests/unit/PrivateOpenApi.Tests.ps1 | 89 +++++++++++----------- tests/unit/Responses.Tests.ps1 | 1 + tests/unit/Routes.Tests.ps1 | 1 + tests/unit/Schedules.Tests.ps1 | 1 + tests/unit/Security.Tests.ps1 | 1 + tests/unit/Server.Tests.ps1 | 1 + tests/unit/Serverless.Tests.ps1 | 1 + tests/unit/Sessions.Tests.ps1 | 1 + tests/unit/State.Tests.ps1 | 1 + tests/unit/Timers.Tests.ps1 | 1 + 27 files changed, 83 insertions(+), 55 deletions(-) diff --git a/tests/integration/Authentication.Tests.ps1 b/tests/integration/Authentication.Tests.ps1 index 67344ad67..9ffc4cb4e 100644 --- a/tests/integration/Authentication.Tests.ps1 +++ b/tests/integration/Authentication.Tests.ps1 @@ -6,6 +6,8 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]integration', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + } Describe 'Authentication Requests' { diff --git a/tests/unit/Authentication.Tests.ps1 b/tests/unit/Authentication.Tests.ps1 index d5f529726..5af266048 100644 --- a/tests/unit/Authentication.Tests.ps1 +++ b/tests/unit/Authentication.Tests.ps1 @@ -4,6 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } $now = [datetime]::UtcNow @@ -148,15 +149,15 @@ Describe 'Test-PodeJwt' { } -Describe "Expand-PodeAuthMerge Tests" { +Describe 'Expand-PodeAuthMerge Tests' { BeforeAll { # Mock the $PodeContext variable $PodeContext = @{ Server = @{ Authentications = @{ Methods = @{ - BasicAuth = @{ Name = 'BasicAuth'; merged = $false } - ApiKeyAuth = @{ Name = 'ApiKeyAuth'; merged = $false } + BasicAuth = @{ Name = 'BasicAuth'; merged = $false } + ApiKeyAuth = @{ Name = 'ApiKeyAuth'; merged = $false } CustomMergedAuth = @{ Name = 'CustomMergedAuth'; merged = $true; Authentications = @('BasicAuth', 'ApiKeyAuth') } } } @@ -164,27 +165,27 @@ Describe "Expand-PodeAuthMerge Tests" { } } - It "Expands discrete authentication methods correctly" { + It 'Expands discrete authentication methods correctly' { $expandedAuthNames = Expand-PodeAuthMerge -Names @('BasicAuth', 'ApiKeyAuth') $expandedAuthNames | Should -Contain 'BasicAuth' $expandedAuthNames | Should -Contain 'ApiKeyAuth' $expandedAuthNames.Count | Should -Be 2 } - It "Expands merged authentication methods into individual components" { + It 'Expands merged authentication methods into individual components' { $expandedAuthNames = Expand-PodeAuthMerge -Names @('CustomMergedAuth') $expandedAuthNames | Should -Contain 'BasicAuth' $expandedAuthNames | Should -Contain 'ApiKeyAuth' $expandedAuthNames.Count | Should -Be 2 } - It "Handles anonymous access special case" { + It 'Handles anonymous access special case' { $expandedAuthNames = Expand-PodeAuthMerge -Names @('%_allowanon_%') $expandedAuthNames | Should -Contain '%_allowanon_%' $expandedAuthNames.Count | Should -Be 1 } - It "Handles empty and invalid inputs" { + It 'Handles empty and invalid inputs' { { Expand-PodeAuthMerge -Names @() } | Should -Throw { Expand-PodeAuthMerge -Names @('NonExistentAuth') } | Should -Throw } diff --git a/tests/unit/Context.Tests.ps1 b/tests/unit/Context.Tests.ps1 index dc89568b1..94cf871b0 100644 --- a/tests/unit/Context.Tests.ps1 +++ b/tests/unit/Context.Tests.ps1 @@ -4,6 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ 'Server' = $null; } } diff --git a/tests/unit/Cookies.Tests.ps1 b/tests/unit/Cookies.Tests.ps1 index f9a992fd2..876aea138 100644 --- a/tests/unit/Cookies.Tests.ps1 +++ b/tests/unit/Cookies.Tests.ps1 @@ -4,6 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Test-PodeCookie' { It 'Returns true' { diff --git a/tests/unit/CronParser.Tests.ps1 b/tests/unit/CronParser.Tests.ps1 index b5d7454e4..7bb1c7920 100644 --- a/tests/unit/CronParser.Tests.ps1 +++ b/tests/unit/CronParser.Tests.ps1 @@ -4,6 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Get-PodeCronFields' { diff --git a/tests/unit/Cryptography.Tests.ps1 b/tests/unit/Cryptography.Tests.ps1 index 1345986c5..60d0a87ab 100644 --- a/tests/unit/Cryptography.Tests.ps1 +++ b/tests/unit/Cryptography.Tests.ps1 @@ -2,6 +2,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Invoke-PodeHMACSHA256Hash' { diff --git a/tests/unit/Endware.Tests.ps1 b/tests/unit/Endware.Tests.ps1 index ba7458420..4a41c1581 100644 --- a/tests/unit/Endware.Tests.ps1 +++ b/tests/unit/Endware.Tests.ps1 @@ -2,6 +2,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Invoke-PodeEndware' { diff --git a/tests/unit/Flash.Tests.ps1 b/tests/unit/Flash.Tests.ps1 index 98b613611..e75d741cc 100644 --- a/tests/unit/Flash.Tests.ps1 +++ b/tests/unit/Flash.Tests.ps1 @@ -5,6 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Add-PodeFlashMessage' { diff --git a/tests/unit/Handlers.Tests.ps1 b/tests/unit/Handlers.Tests.ps1 index 02d4d4bc7..1895ee15f 100644 --- a/tests/unit/Handlers.Tests.ps1 +++ b/tests/unit/Handlers.Tests.ps1 @@ -5,6 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ 'Server' = $null; } } diff --git a/tests/unit/Headers.Tests.ps1 b/tests/unit/Headers.Tests.ps1 index 003671688..eccd1d30e 100644 --- a/tests/unit/Headers.Tests.ps1 +++ b/tests/unit/Headers.Tests.ps1 @@ -4,6 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Test-PodeHeader' { Context 'WebServer' { diff --git a/tests/unit/Helpers.Tests.ps1 b/tests/unit/Helpers.Tests.ps1 index d80e5c543..dd59ea60e 100644 --- a/tests/unit/Helpers.Tests.ps1 +++ b/tests/unit/Helpers.Tests.ps1 @@ -4,6 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Get-PodeType' { @@ -1725,13 +1726,13 @@ Describe 'ConvertTo-PodeYamlInternal Tests' { } It 'Converts arrays correctly' { - $result = ConvertTo-PodeYamlInternal -InputObject @('one', 'two', 'three') -NoNewLine + $result = ConvertTo-PodeYamlInternal -InputObject @('one', 'two', 'three') -NoNewLine $expected = (@' - one - two - three '@) - $result | Should -Be ($expected.Trim() -Replace "`r`n","`n") + $result | Should -Be ($expected.Trim() -Replace "`r`n", "`n") } It 'Converts hashtables correctly' { diff --git a/tests/unit/Logging.Tests.ps1 b/tests/unit/Logging.Tests.ps1 index 3d54a6a2a..74a28cec0 100644 --- a/tests/unit/Logging.Tests.ps1 +++ b/tests/unit/Logging.Tests.ps1 @@ -4,6 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Get-PodeLogger' { It 'Returns null as the logger does not exist' { diff --git a/tests/unit/Mappers.Tests.ps1 b/tests/unit/Mappers.Tests.ps1 index a8557fa3f..abb8dc845 100644 --- a/tests/unit/Mappers.Tests.ps1 +++ b/tests/unit/Mappers.Tests.ps1 @@ -4,6 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Get-PodeContentType' { Context 'No extension supplied' { @@ -1287,7 +1288,7 @@ Describe 'Get-PodeContentType' { '.z' = 'application/x-compress' '.zip' = 'application/zip' } } - It "Returns correct content type for <_>" -ForEach ($types.Keys) { + It 'Returns correct content type for <_>' -ForEach ($types.Keys) { Get-PodeContentType -Extension $_ | Should -Be $types[$_] } @@ -1456,7 +1457,7 @@ Describe 'Get-PodeStatusDescription' { '511' = 'Network Authentication Required' '526' = 'Invalid SSL Certificate' } } - It "Returns description for the <_> StatusCode" -ForEach ($codes.Keys) { + It 'Returns description for the <_> StatusCode' -ForEach ($codes.Keys) { Get-PodeStatusDescription -StatusCode $_ | Should -Be $codes[$_] } diff --git a/tests/unit/Metrics.Tests.ps1 b/tests/unit/Metrics.Tests.ps1 index 3430ac158..6ce9bd00c 100644 --- a/tests/unit/Metrics.Tests.ps1 +++ b/tests/unit/Metrics.Tests.ps1 @@ -4,6 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ Metrics = @{ diff --git a/tests/unit/Middleware.Tests.ps1 b/tests/unit/Middleware.Tests.ps1 index f4b7034d9..c3ddd6b58 100644 --- a/tests/unit/Middleware.Tests.ps1 +++ b/tests/unit/Middleware.Tests.ps1 @@ -5,6 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Get-PodeInbuiltMiddleware' { diff --git a/tests/unit/NameGenerator.Tests.ps1 b/tests/unit/NameGenerator.Tests.ps1 index 140bf974c..a3863037f 100644 --- a/tests/unit/NameGenerator.Tests.ps1 +++ b/tests/unit/NameGenerator.Tests.ps1 @@ -2,6 +2,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Get-PodeRandomName' { diff --git a/tests/unit/OpenApi.Tests.ps1 b/tests/unit/OpenApi.Tests.ps1 index a9ceced07..b39f2008a 100644 --- a/tests/unit/OpenApi.Tests.ps1 +++ b/tests/unit/OpenApi.Tests.ps1 @@ -5,6 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } +Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture "en-us" -FileName "Pode" } Describe 'OpenApi' { diff --git a/tests/unit/PrivateOpenApi.Tests.ps1 b/tests/unit/PrivateOpenApi.Tests.ps1 index c9b1c4a89..e0f8e1bee 100644 --- a/tests/unit/PrivateOpenApi.Tests.ps1 +++ b/tests/unit/PrivateOpenApi.Tests.ps1 @@ -5,6 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'PrivateOpenApi' { @@ -13,11 +14,11 @@ Describe 'PrivateOpenApi' { function GetPodeContext { return @{ Server = @{ - Security = @{ + Security = @{ autoheaders = $false } - Authentications=@{} - OpenAPI = @{ + Authentications = @{} + OpenAPI = @{ SelectedDefinitionTag = 'default' Definitions = @{ default = Get-PodeOABaseObject @@ -287,32 +288,32 @@ Describe 'PrivateOpenApi' { } - Describe "Set-PodeOAAuth Tests" { + Describe 'Set-PodeOAAuth Tests' { BeforeAll { # Mock Test-PodeAuthExists to simulate authentication method existence Mock Test-PodeAuthExists { return $true } } - It "Applies multiple authentication methods to a route" { + It 'Applies multiple authentication methods to a route' { $route = @{ OpenApi = @{} } { Set-PodeOAAuth -Route @($route) -Name @('BasicAuth', 'ApiKeyAuth') } | Should -Not -Throw $route.OpenApi.Authentication.Count | Should -Be 2 } - It "Throws an exception for non-existent authentication method" { + It 'Throws an exception for non-existent authentication method' { Mock Test-PodeAuthExists { return $false } $route = @{ OpenApi = @{} } { Set-PodeOAAuth -Route @($route) -Name 'InvalidAuth' } | Should -Throw } - It "Allows anonymous access" { + It 'Allows anonymous access' { $route = @{ OpenApi = @{ Authentication = @{} } } { Set-PodeOAAuth -Route @($route) -Name 'BasicAuth' -AllowAnon } | Should -Not -Throw $route.OpenApi.Authentication.keys -contains '%_allowanon_%' | Should -Be $true $route.OpenApi.Authentication['%_allowanon_%'] | Should -BeNullOrEmpty } - It "Applies both authenticated and anonymous access to a route" { + It 'Applies both authenticated and anonymous access to a route' { $route = @{ OpenApi = @{} } { Set-PodeOAAuth -Route @($route) -Name @('BasicAuth') -AllowAnon } | Should -Not -Throw $route.OpenApi.Authentication.Count | Should -Be 2 @@ -321,8 +322,8 @@ Describe 'PrivateOpenApi' { } } - Describe "Get-PodeOABaseObject Tests" { - It "Returns the correct base OpenAPI object structure" { + Describe 'Get-PodeOABaseObject Tests' { + It 'Returns the correct base OpenAPI object structure' { $baseObject = Get-PodeOABaseObject $baseObject | Should -BeOfType [hashtable] @@ -335,20 +336,20 @@ Describe 'PrivateOpenApi' { } } - Describe "Initialize-PodeOpenApiTable Tests" { - It "Initializes OpenAPI table with default settings" { + Describe 'Initialize-PodeOpenApiTable Tests' { + It 'Initializes OpenAPI table with default settings' { $openApiTable = Initialize-PodeOpenApiTable $openApiTable | Should -BeOfType [hashtable] - $openApiTable.DefinitionTagSelectionStack -is [System.Collections.Generic.Stack[System.Object]] | Should -BeTrue - $openApiTable.DefaultDefinitionTag | Should -Be "default" - $openApiTable.SelectedDefinitionTag | Should -Be "default" + $openApiTable.DefinitionTagSelectionStack -is [System.Collections.Generic.Stack[System.Object]] | Should -BeTrue + $openApiTable.DefaultDefinitionTag | Should -Be 'default' + $openApiTable.SelectedDefinitionTag | Should -Be 'default' $openApiTable.Definitions | Should -BeOfType [hashtable] - $openApiTable.Definitions["default"] | Should -BeOfType [hashtable] + $openApiTable.Definitions['default'] | Should -BeOfType [hashtable] } - It "Initializes OpenAPI table with custom definition tag" { - $customTag = "api-v1" + It 'Initializes OpenAPI table with custom definition tag' { + $customTag = 'api-v1' $openApiTable = Initialize-PodeOpenApiTable -DefaultDefinitionTag $customTag $openApiTable.DefaultDefinitionTag | Should -Be $customTag @@ -358,7 +359,7 @@ Describe 'PrivateOpenApi' { } } - Describe "ConvertTo-PodeOASchemaObjectProperty Tests" { + Describe 'ConvertTo-PodeOASchemaObjectProperty Tests' { BeforeAll { # Mock ConvertTo-PodeOASchemaProperty to simulate its behavior Mock ConvertTo-PodeOASchemaProperty { return @{ type = $_.type; processed = $true } } @@ -366,57 +367,57 @@ Describe 'PrivateOpenApi' { It "Converts a list of properties excluding 'allOf', 'oneOf', 'anyOf'" { $properties = @( - @{ name = "prop1"; type = "string" }, - @{ name = "prop2"; type = "integer" }, - @{ name = "prop3"; type = "allOf" } + @{ name = 'prop1'; type = 'string' }, + @{ name = 'prop2'; type = 'integer' }, + @{ name = 'prop3'; type = 'allOf' } ) - $result = ConvertTo-PodeOASchemaObjectProperty -Properties $properties -DefinitionTag "myTag" + $result = ConvertTo-PodeOASchemaObjectProperty -Properties $properties -DefinitionTag 'myTag' $result.Count | Should -Be 2 - $result["prop1"].processed | Should -Be $true - $result["prop2"].processed | Should -Be $true - $result.ContainsKey("prop3") | Should -Be $false + $result['prop1'].processed | Should -Be $true + $result['prop2'].processed | Should -Be $true + $result.ContainsKey('prop3') | Should -Be $false } - It "Forms valid schema object for non-excluded properties" { + It 'Forms valid schema object for non-excluded properties' { $properties = @( - @{ name = "prop1"; type = "string" } + @{ name = 'prop1'; type = 'string' } ) - $result = ConvertTo-PodeOASchemaObjectProperty -Properties $properties -DefinitionTag "myTag" + $result = ConvertTo-PodeOASchemaObjectProperty -Properties $properties -DefinitionTag 'myTag' $result.Count | Should -Be 1 - $result["prop1"].type | Should -Be "string" - $result["prop1"].processed | Should -Be $true + $result['prop1'].type | Should -Be 'string' + $result['prop1'].processed | Should -Be $true } } - Describe "ConvertTo-PodeOAObjectSchema Tests" { + Describe 'ConvertTo-PodeOAObjectSchema Tests' { Mock ConvertTo-PodeOASchemaProperty { return @{ mockedResult = $true } } Mock Test-PodeOAComponentInternal { return $true } Mock Test-PodeOAVersion { param($Version) $Version -le 3.0 } - It "Converts valid content to schema object" { + It 'Converts valid content to schema object' { $content = @{ - "application/json" = @{ type = "String" } + 'application/json' = @{ type = 'String' } } - $result = ConvertTo-PodeOAObjectSchema -Content $content -DefinitionTag "myTag" + $result = ConvertTo-PodeOAObjectSchema -Content $content -DefinitionTag 'myTag' - $result.ContainsKey("application/json") | Should -Be $true - $result["application/json"].schema.type | Should -Be 'string' + $result.ContainsKey('application/json') | Should -Be $true + $result['application/json'].schema.type | Should -Be 'string' } - It "Handles array structures correctly" { + It 'Handles array structures correctly' { $content = @{ - "application/json" = @{ - __array = $true - __content = @{ type = "String" } + 'application/json' = @{ + __array = $true + __content = @{ type = 'String' } } } - $result = ConvertTo-PodeOAObjectSchema -Content $content -DefinitionTag "myTag" + $result = ConvertTo-PodeOAObjectSchema -Content $content -DefinitionTag 'myTag' - $result["application/json"].schema.type | Should -Be "array" - $result["application/json"].schema.Items.type | Should -Be 'string' + $result['application/json'].schema.type | Should -Be 'array' + $result['application/json'].schema.Items.type | Should -Be 'string' } } diff --git a/tests/unit/Responses.Tests.ps1 b/tests/unit/Responses.Tests.ps1 index 00e02dea4..9bd533b69 100644 --- a/tests/unit/Responses.Tests.ps1 +++ b/tests/unit/Responses.Tests.ps1 @@ -5,6 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture "en-us" -FileName "Pode" } diff --git a/tests/unit/Routes.Tests.ps1 b/tests/unit/Routes.Tests.ps1 index 88025a2f7..004f8d72a 100644 --- a/tests/unit/Routes.Tests.ps1 +++ b/tests/unit/Routes.Tests.ps1 @@ -5,6 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ 'Server' = $null; } } diff --git a/tests/unit/Schedules.Tests.ps1 b/tests/unit/Schedules.Tests.ps1 index 05e688db1..e1705db87 100644 --- a/tests/unit/Schedules.Tests.ps1 +++ b/tests/unit/Schedules.Tests.ps1 @@ -5,6 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Find-PodeSchedule' { Context 'Invalid parameters supplied' { diff --git a/tests/unit/Security.Tests.ps1 b/tests/unit/Security.Tests.ps1 index 9862b9510..778c20e0f 100644 --- a/tests/unit/Security.Tests.ps1 +++ b/tests/unit/Security.Tests.ps1 @@ -5,6 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ 'Server' = $null; } } diff --git a/tests/unit/Server.Tests.ps1 b/tests/unit/Server.Tests.ps1 index ff9bd1327..052330a2d 100644 --- a/tests/unit/Server.Tests.ps1 +++ b/tests/unit/Server.Tests.ps1 @@ -5,6 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ diff --git a/tests/unit/Serverless.Tests.ps1 b/tests/unit/Serverless.Tests.ps1 index 6366d7895..a0f35b6fa 100644 --- a/tests/unit/Serverless.Tests.ps1 +++ b/tests/unit/Serverless.Tests.ps1 @@ -5,6 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Start-PodeAzFuncServer' { BeforeAll { diff --git a/tests/unit/Sessions.Tests.ps1 b/tests/unit/Sessions.Tests.ps1 index 5b5deb390..6a6a81c01 100644 --- a/tests/unit/Sessions.Tests.ps1 +++ b/tests/unit/Sessions.Tests.ps1 @@ -5,6 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $now = [datetime]::UtcNow } diff --git a/tests/unit/State.Tests.ps1 b/tests/unit/State.Tests.ps1 index b7feec3b5..ee9143505 100644 --- a/tests/unit/State.Tests.ps1 +++ b/tests/unit/State.Tests.ps1 @@ -5,6 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ 'Server' = $null; } } diff --git a/tests/unit/Timers.Tests.ps1 b/tests/unit/Timers.Tests.ps1 index c8b6e6076..3938dda18 100644 --- a/tests/unit/Timers.Tests.ps1 +++ b/tests/unit/Timers.Tests.ps1 @@ -5,6 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } + Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ 'Server' = $null; } } From 1d95dde358b12c8f5a9399b8c962541c637bcb9b Mon Sep 17 00:00:00 2001 From: mdaneri Date: Thu, 30 May 2024 14:31:17 -0700 Subject: [PATCH 009/177] 3rd drop fix build process add language test --- pode.build.ps1 | 4 +- src/Locales/ar/Pode.psd1 | 110 +++++++++++++++++++++++------- src/Locales/de/Pode.psd1 | 108 +++++++++++++++++++++++------ src/Locales/en/Pode.psd1 | 108 +++++++++++++++++++++++------ src/Locales/es/Pode.psd1 | 108 +++++++++++++++++++++++------ src/Locales/fr/Pode.psd1 | 108 +++++++++++++++++++++++------ src/Locales/it/Pode.psd1 | 110 +++++++++++++++++++++++------- src/Locales/ja/Pode.psd1 | 108 +++++++++++++++++++++++------ src/Locales/pl/Pode.psd1 | 88 ++++++++++++++++++++++++ src/Locales/pt/Pode.psd1 | 88 ++++++++++++++++++++++++ src/Locales/zn/Pode.psd1 | 108 +++++++++++++++++++++++------ src/Pode.Internal.psd1 | 1 + src/Pode.psm1 | 7 +- src/Private/Authentication.ps1 | 4 +- src/Private/AutoImport.ps1 | 4 +- src/Private/Context.ps1 | 4 +- src/Private/CronParser.ps1 | 20 +++--- src/Private/Cryptography.ps1 | 16 ++--- src/Private/Endpoints.ps1 | 4 +- src/Private/Gui.ps1 | 2 +- src/Private/Helpers.ps1 | 45 ++++++------ src/Private/Middleware.ps1 | 4 +- src/Private/OpenApi.ps1 | 34 ++++----- src/Private/Routes.ps1 | 10 +-- src/Private/ScopedVariables.ps1 | 4 +- src/Private/Secrets.ps1 | 12 ++-- src/Private/Security.ps1 | 20 +++--- src/Private/Server.ps1 | 2 +- src/Private/ServiceServer.ps1 | 2 +- src/Private/Sessions.ps1 | 4 +- src/Private/Setup.ps1 | 2 +- src/Private/SmtpServer.ps1 | 2 +- src/Private/Tasks.ps1 | 2 +- src/Private/Verbs.ps1 | 4 +- src/Public/Access.ps1 | 12 ++-- tests/unit/Helpers.Tests.ps1 | 2 +- tests/unit/Localization.Tests.ps1 | 37 ++++++++++ tests/unit/Mappers.Tests.ps1 | 2 +- tests/unit/Routes.Tests.ps1 | 2 +- 39 files changed, 1021 insertions(+), 291 deletions(-) create mode 100644 src/Locales/pl/Pode.psd1 create mode 100644 src/Locales/pt/Pode.psd1 create mode 100644 tests/unit/Localization.Tests.ps1 diff --git a/pode.build.ps1 b/pode.build.ps1 index 6fa324e7b..887192cef 100644 --- a/pode.build.ps1 +++ b/pode.build.ps1 @@ -427,7 +427,7 @@ Task Pack Build, { New-Item -Path $path -ItemType Directory -Force | Out-Null # which source folders do we need? create them and copy their contents - $folders = @('Private', 'Public', 'Misc', 'Libs') + $folders = @('Private', 'Public', 'Misc', 'Libs','Locales') $folders | ForEach-Object { New-Item -ItemType Directory -Path (Join-Path $path $_) -Force | Out-Null Copy-Item -Path "./src/$($_)/*" -Destination (Join-Path $path $_) -Force -Recurse | Out-Null @@ -652,7 +652,7 @@ Task Install-Module -If ($Version) Pack, { $path = './pkg' # copy over folders - $folders = @('Private', 'Public', 'Misc', 'Libs', 'licenses') + $folders = @('Private', 'Public', 'Misc', 'Libs', 'licenses','Locales') $folders | ForEach-Object { Copy-Item -Path (Join-Path -Path $path -ChildPath $_) -Destination $dest -Force -Recurse | Out-Null } diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 323254bb1..ad6ea3766 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -1,24 +1,88 @@ ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyMessage = وحدة Active Directory متاحة فقط على نظام Windows -adModuleNotInstalledMessage = وحدة Active Directory غير مثبتة -secretManagementModuleNotInstalledMessage = وحدة Microsoft.PowerShell.SecretManagement غير مثبتة -secretVaultAlreadyRegisteredMessage = تم تسجيل خزنة سرية بالاسم '{0}' بالفعل أثناء الاستيراد التلقائي للخزن السرية -failedToOpenRunspacePoolMessage = فشل في فتح RunspacePool: {0} -cronExpressionInvalidMessage = يجب أن تتكون تعبير Cron فقط من 5 أجزاء: {0} -invalidAliasFoundMessage = تم العثور على اسم مستعار غير صالح {0}: {1} -invalidAtomCharacterMessage = حرف ذري غير صالح: {0} -minValueGreaterThanMaxMessage = يجب ألا تكون القيمة الدنيا لـ {0} أكبر من القيمة القصوى -minValueInvalidMessage = القيمة الدنيا '{0}' لـ {1} غير صالحة، يجب أن تكون أكبر من أو تساوي {2} -maxValueInvalidMessage = القيمة القصوى '{0}' لـ {1} غير صالحة، يجب أن تكون أقل من أو تساوي {2} -valueOutOfRangeMessage = القيمة '{0}' لـ {1} غير صالحة، يجب أن تكون بين {2} و {3} -daysInMonthExceededMessage = {0} يحتوي فقط على {1} أيام، ولكن تم توفير {2} -nextTriggerCalculationErrorMessage = يبدو أن هناك خطأ ما عند محاولة حساب تاريخ ووقت التشغيل التالي: {0} -incompatiblePodeDllMessage = تم تحميل إصدار غير متوافق موجود من Pode.DLL {0}. الإصدار {1} مطلوب. افتح جلسة Powershell/pwsh جديدة وحاول مرة أخرى. -endpointNotExistMessage = لا يوجد نقطة نهاية بالبروتوكول '{0}' والعنوان '{1}' أو العنوان المحلي '{2}' -endpointNameNotExistMessage = لا يوجد نقطة نهاية بالاسم '{0}' -failedToConnectToUrlMessage = فشل الاتصال بعنوان URL: {0} -failedToParseAddressMessage = فشل في تحليل '{0}' كعنوان IP/Host:Port صالح -invalidIpAddressMessage = عنوان IP المقدم غير صالح: {0} -invalidPortMessage = لا يمكن أن يكون المنفذ سالبًا: {0} -pathNotExistMessage = المسار غير موجود: {0} -'@ \ No newline at end of file +adModuleWindowsOnlyExceptionMessage = وحدة Active Directory متاحة فقط على نظام Windows. +adModuleNotInstalledExceptionMessage = وحدة Active Directory غير مثبتة. +secretManagementModuleNotInstalledExceptionMessage = وحدة Microsoft.PowerShell.SecretManagement غير مثبتة. +secretVaultAlreadyRegisteredExceptionMessage = تم تسجيل خزنة سرية باسم '{0}' بالفعل أثناء استيراد الخزن السرية تلقائيًا. +failedToOpenRunspacePoolExceptionMessage = فشل في فتح RunspacePool: {0} +cronExpressionInvalidExceptionMessage = يجب أن تتكون تعبير Cron من 5 أجزاء فقط: {0} +invalidAliasFoundExceptionMessage = تم العثور على اسم مستعار غير صالح {0}: {1} +invalidAtomCharacterExceptionMessage = حرف الذرة غير صالح: {0} +minValueGreaterThanMaxExceptionMessage = يجب ألا تكون القيمة الدنيا {0} أكبر من القيمة القصوى. +minValueInvalidExceptionMessage = القيمة الدنيا '{0}' لـ {1} غير صالحة، يجب أن تكون أكبر من/أو تساوي {2} +maxValueInvalidExceptionMessage = القيمة القصوى '{0}' لـ {1} غير صالحة، يجب أن تكون أقل من/أو تساوي {2} +valueOutOfRangeExceptionMessage = القيمة '{0}' لـ {1} غير صالحة، يجب أن تكون بين {2} و {3} +daysInMonthExceededExceptionMessage = يحتوي {0} على {1} أيام فقط، ولكن تم توفير {2}. +nextTriggerCalculationErrorExceptionMessage = يبدو أن هناك خطأ ما أثناء محاولة حساب تاريخ المشغل التالي: {0} +incompatiblePodeDllExceptionMessage = يتم تحميل إصدار غير متوافق من Pode.DLL {0}. الإصدار {1} مطلوب. افتح جلسة Powershell/pwsh جديدة وأعد المحاولة. +endpointNotExistExceptionMessage = نقطة النهاية مع البروتوكول '{0}' والعنوان '{1}' أو العنوان المحلي '{2}' غير موجودة. +endpointNameNotExistExceptionMessage = نقطة النهاية بالاسم '{0}' غير موجودة. +failedToConnectToUrlExceptionMessage = فشل الاتصال بعنوان URL: {0} +failedToParseAddressExceptionMessage = فشل في تحليل '{0}' كعنوان IP/مضيف:منفذ صالح +invalidIpAddressExceptionMessage = عنوان IP المقدم غير صالح: {0} +invalidPortExceptionMessage = لا يمكن أن يكون المنفذ سالبًا: {0} +pathNotExistExceptionMessage = المسار غير موجود: {0} +noSecretForHmac256ExceptionMessage = لم يتم تقديم أي سر لتجزئة HMAC256. +noSecretForHmac384ExceptionMessage = لم يتم تقديم أي سر لتجزئة HMAC384. +noSecretForHmac512ExceptionMessage = لم يتم تقديم أي سر لتجزئة HMAC512. +noSecretForJwtSignatureExceptionMessage = لم يتم تقديم أي سر لتوقيع JWT. +noSecretExpectedForNoSignatureExceptionMessage = لم يكن من المتوقع تقديم أي سر لعدم وجود توقيع. +unsupportedJwtAlgorithmExceptionMessage = خوارزمية JWT غير مدعومة حاليًا: {0} +invalidBase64JwtExceptionMessage = تم العثور على قيمة مشفرة بتنسيق Base64 غير صالحة في JWT +invalidJsonJwtExceptionMessage = تم العثور على قيمة JSON غير صالحة في JWT +unsupportedFunctionInServerlessContextExceptionMessage = الدالة {0} غير مدعومة في سياق بدون خادم. +invalidPathWildcardOrDirectoryExceptionMessage = لا يمكن أن يكون المسار المقدم عبارة عن حرف بدل أو دليل: {0} +invalidExceptionTypeExceptionMessage = الاستثناء من نوع غير صالح، يجب أن يكون إما WebException أو HttpRequestException، ولكن تم الحصول عليه: {0} +pathToLoadNotFoundExceptionMessage = لم يتم العثور على المسار لتحميل {0}: {1} +singleValueForIntervalExceptionMessage = يمكنك تقديم قيمة {0} واحدة فقط عند استخدام الفواصل الزمنية. +scriptErrorExceptionMessage = خطأ '{0}' في البرنامج النصي {1} {2} (السطر {3}) الحرف {4} أثناء تنفيذ {5} على الكائن {6} 'الصنف: {7} الصنف الأساسي: {8} +noScriptBlockSuppliedExceptionMessage = لم يتم تقديم أي ScriptBlock. +iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN مفقود. +invalidContentTypeForSchemaExceptionMessage = تم العثور على نوع محتوى غير صالح للمخطط: {0} +propertiesParameterWithoutNameExceptionMessage = لا يمكن استخدام معلمات الخصائص إذا لم يكن لدى الخاصية اسم. +multiTypePropertiesRequireOpenApi31ExceptionMessage = تتطلب خصائص الأنواع المتعددة إصدار OpenApi 3.1 أو أعلى. +openApiVersionPropertyMandatoryExceptionMessage = خاصية إصدار OpenApi إلزامية. +webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = ميزة Webhooks غير مدعومة في OpenAPI v3.0.x +authenticationMethodDoesNotExistExceptionMessage = طريقة المصادقة غير موجودة: {0} +unsupportedObjectExceptionMessage = الكائن غير مدعوم +validationOfAnyOfSchemaNotSupportedExceptionMessage = التحقق من مخطط يتضمن 'أي منها' غير مدعوم. +validationOfOneOfSchemaNotSupportedExceptionMessage = التحقق من مخطط يتضمن 'واحد منها' غير مدعوم. +cannotCreatePropertyWithoutTypeExceptionMessage = لا يمكن إنشاء الخاصية لأنه لم يتم تعريف نوع. +paramsNoAdditionalPropertiesExclusiveExceptionMessage = المعلمات -NoAdditionalProperties و -AdditionalProperties تتعارض مع بعضها البعض. +headerMustHaveNameInEncodingContextExceptionMessage = يجب أن يحتوي الرأس على اسم عند استخدامه في سياق الترميز. +descriptionRequiredExceptionMessage = الوصف مطلوب. +openApiDocumentNotCompliantExceptionMessage = مستند OpenAPI غير متوافق. +noComponentInDefinitionExceptionMessage = لا توجد مكون من نوع {0} باسم {1} متاح في تعريف {2}. +methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: تم التعريف بالفعل. +methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: تم التعريف بالفعل لـ {2} +invalidMiddlewareTypeExceptionMessage = أحد مكونات Middleware المقدمة من نوع غير صالح. كان المتوقع إما ScriptBlock أو Hashtable، ولكن تم الحصول عليه: {0} +hashtableMiddlewareNoLogicExceptionMessage = مكون Middleware من نوع Hashtable المقدم لا يحتوي على منطق معرف. +invalidLogicTypeInHashtableMiddlewareExceptionMessage = مكون Middleware من نوع Hashtable المقدم يحتوي على نوع منطق غير صالح. كان المتوقع ScriptBlock، ولكن تم الحصول عليه: {0} +scopedVariableAlreadyDefinedExceptionMessage = المتغير المحدد بالفعل معرف: {0} +valueForUsingVariableNotFoundExceptionMessage = لم يتم العثور على قيمة لـ `$using:{0}`. +unlockSecretRequiredExceptionMessage = خاصية 'UnlockSecret' مطلوبة عند استخدام Microsoft.PowerShell.SecretStore +unlockSecretButNoScriptBlockExceptionMessage = تم تقديم سر الفتح لنوع خزنة سرية مخصصة، ولكن لم يتم تقديم ScriptBlock الفتح. +noUnlockScriptBlockForVaultExceptionMessage = لم يتم تقديم ScriptBlock الفتح لفتح الخزنة '{0}' +noSetScriptBlockForVaultExceptionMessage = لم يتم تقديم ScriptBlock الإعداد لتحديث/إنشاء الأسرار في الخزنة '{0}' +noRemoveScriptBlockForVaultExceptionMessage = لم يتم تقديم ScriptBlock الإزالة لإزالة الأسرار من الخزنة '{0}' +invalidSecretValueTypeExceptionMessage = قيمة السر من نوع غير صالح. الأنواع المتوقعة: String، SecureString، HashTable، Byte[]، أو PSCredential. ولكن تم الحصول عليه: {0} +limitValueCannotBeZeroOrLessExceptionMessage = لا يمكن أن تكون القيمة الحدية 0 أو أقل لـ {0} +secondsValueCannotBeZeroOrLessExceptionMessage = لا يمكن أن تكون قيمة الثواني 0 أو أقل لـ {0} +failedToCreateOpenSslCertExceptionMessage = فشل في إنشاء شهادة openssl: {0} +certificateThumbprintsNameSupportedOnWindowsExceptionMessage = بصمات الإبهام/الاسم للشهادة مدعومة فقط على Windows. +noCertificateFoundExceptionMessage = لم يتم العثور على شهادة في {0}\{1} لـ '{2}' +runspacePoolFailedToLoadExceptionMessage = فشل تحميل RunspacePool لـ {0}. +noServiceHandlersDefinedExceptionMessage = لم يتم تعريف أي معالجات خدمة. +noSessionToSetOnResponseExceptionMessage = لا توجد جلسة متاحة لتعيينها على الاستجابة. +noSessionToCalculateDataHashExceptionMessage = لا توجد جلسة متاحة لحساب تجزئة البيانات. +moduleOrVersionNotFoundExceptionMessage = لم يتم العثور على الوحدة أو الإصدار على {0}: {1}@{2} +noSmtpHandlersDefinedExceptionMessage = لم يتم تعريف أي معالجات SMTP. +taskTimedOutExceptionMessage = انتهت المهلة الزمنية للمهمة بعد {0}ms. +verbAlreadyDefinedExceptionMessage = [الفعل] {0}: تم التعريف بالفعل +verbAlreadyDefinedForUrlExceptionMessage = [الفعل] {0}: تم التعريف بالفعل لـ {1} +pathOrScriptBlockRequiredExceptionMessage = مطلوب مسار أو ScriptBlock للحصول على قيم الوصول المخصصة. +accessMethodAlreadyDefinedExceptionMessage = طريقة الوصول معرفة بالفعل: {0} +accessMethodNotExistForMergingExceptionMessage = طريقة الوصول غير موجودة للدمج: {0} +routeAlreadyContainsCustomAccessExceptionMessage = المسار '[{0}] {1}' يحتوي بالفعل على وصول مخصص باسم '{2}' +accessMethodNotExistExceptionMessage = طريقة الوصول غير موجودة: {0} +pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = ميزة PathItems غير مدعومة في OpenAPI v3.0.x +'@ diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index 0e38fb2a5..5776e7c5b 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -1,24 +1,88 @@ ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyMessage = Das Active Directory-Modul ist nur unter Windows verfügbar -adModuleNotInstalledMessage = Das Active Directory-Modul ist nicht installiert -secretManagementModuleNotInstalledMessage = Das Microsoft.PowerShell.SecretManagement-Modul ist nicht installiert -secretVaultAlreadyRegisteredMessage = Ein Secret Vault mit dem Namen '{0}' wurde bereits beim automatischen Importieren von Secret Vaults registriert -failedToOpenRunspacePoolMessage = Fehler beim Öffnen des RunspacePool: {0} -cronExpressionInvalidMessage = Cron-Ausdruck sollte nur aus 5 Teilen bestehen: {0} -invalidAliasFoundMessage = Ungültiger {0} Alias gefunden: {1} -invalidAtomCharacterMessage = Ungültiges Atomzeichen: {0} -minValueGreaterThanMaxMessage = Der Mindestwert für {0} sollte nicht größer als der Höchstwert sein -minValueInvalidMessage = Der Mindestwert '{0}' für {1} ist ungültig, sollte größer oder gleich {2} sein -maxValueInvalidMessage = Der Höchstwert '{0}' für {1} ist ungültig, sollte kleiner oder gleich {2} sein -valueOutOfRangeMessage = Der Wert '{0}' für {1} ist ungültig, sollte zwischen {2} und {3} liegen -daysInMonthExceededMessage = {0} hat nur {1} Tage, aber {2} wurde angegeben -nextTriggerCalculationErrorMessage = Es scheint, dass beim Versuch, das nächste Trigger-Datum und die nächste Uhrzeit zu berechnen, etwas schiefgelaufen ist: {0} -incompatiblePodeDllMessage = Eine vorhandene inkompatible Version von Pode.DLL {0} ist geladen. Version {1} wird benötigt. Öffnen Sie eine neue Powershell/pwsh-Sitzung und versuchen Sie es erneut. -endpointNotExistMessage = Ein Endpunkt mit dem Protokoll '{0}' und der Adresse '{1}' oder der lokalen Adresse '{2}' existiert nicht -endpointNameNotExistMessage = Ein Endpunkt mit dem Namen '{0}' existiert nicht -failedToConnectToUrlMessage = Fehler beim Verbinden mit der URL: {0} -failedToParseAddressMessage = Fehler beim Parsen von '{0}' als gültige IP/Host:Port-Adresse -invalidIpAddressMessage = Die angegebene IP-Adresse ist ungültig: {0} -invalidPortMessage = Der Port kann nicht negativ sein: {0} -pathNotExistMessage = Pfad existiert nicht: {0} +adModuleWindowsOnlyExceptionMessage = Active Directory-Modul nur unter Windows verfügbar. +adModuleNotInstalledExceptionMessage = Das Active Directory-Modul ist nicht installiert. +secretManagementModuleNotInstalledExceptionMessage = Das Modul Microsoft.PowerShell.SecretManagement ist nicht installiert. +secretVaultAlreadyRegisteredExceptionMessage = Ein Geheimtresor mit dem Namen '{0}' wurde bereits beim automatischen Importieren von Geheimtresoren registriert. +failedToOpenRunspacePoolExceptionMessage = Fehler beim Öffnen des Runspace-Pools: {0} +cronExpressionInvalidExceptionMessage = Die Cron-Ausdruck sollte nur aus 5 Teilen bestehen: {0} +invalidAliasFoundExceptionMessage = Ungültiges {0}-Alias gefunden: {1} +invalidAtomCharacterExceptionMessage = Ungültiges Atomzeichen: {0} +minValueGreaterThanMaxExceptionMessage = Der Mindestwert für {0} darf nicht größer als der Maximalwert sein. +minValueInvalidExceptionMessage = Der Mindestwert '{0}' für {1} ist ungültig, sollte größer oder gleich {2} sein +maxValueInvalidExceptionMessage = Der Maximalwert '{0}' für {1} ist ungültig, sollte kleiner oder gleich {2} sein +valueOutOfRangeExceptionMessage = Wert '{0}' für {1} ist ungültig, sollte zwischen {2} und {3} liegen +daysInMonthExceededExceptionMessage = {0} hat nur {1} Tage, aber {2} wurden angegeben +nextTriggerCalculationErrorExceptionMessage = Es scheint, als ob beim Berechnen des nächsten Trigger-Datums und der nächsten Triggerzeit etwas schief gelaufen wäre: {0} +incompatiblePodeDllExceptionMessage = Eine vorhandene inkompatible Pode.DLL-Version {0} ist geladen. Version {1} wird benötigt. Öffnen Sie eine neue PowerShell/pwsh-Sitzung und versuchen Sie es erneut. +endpointNotExistExceptionMessage = Der Endpunkt mit dem Protokoll '{0}' und der Adresse '{1}' oder der lokalen Adresse '{2}' existiert nicht +endpointNameNotExistExceptionMessage = Der Endpunkt mit dem Namen '{0}' existiert nicht +failedToConnectToUrlExceptionMessage = Verbindung mit der URL fehlgeschlagen: {0} +failedToParseAddressExceptionMessage = Konnte '{0}' nicht als gültige IP/Host:Port-Adresse analysieren +invalidIpAddressExceptionMessage = Die angegebene IP-Adresse ist ungültig: {0} +invalidPortExceptionMessage = Der Port kann nicht negativ sein: {0} +pathNotExistExceptionMessage = Pfad existiert nicht: {0} +noSecretForHmac256ExceptionMessage = Es wurde kein Geheimnis für den HMAC256-Hash angegeben. +noSecretForHmac384ExceptionMessage = Es wurde kein Geheimnis für den HMAC384-Hash angegeben. +noSecretForHmac512ExceptionMessage = Es wurde kein Geheimnis für den HMAC512-Hash angegeben. +noSecretForJwtSignatureExceptionMessage = Es wurde kein Geheimnis für die JWT-Signatur angegeben. +noSecretExpectedForNoSignatureExceptionMessage = Es wurde erwartet, dass kein Geheimnis für keine Signatur angegeben wird. +unsupportedJwtAlgorithmExceptionMessage = Der JWT-Algorithmus wird derzeit nicht unterstützt: {0} +invalidBase64JwtExceptionMessage = Ungültiger Base64-codierter Wert in JWT gefunden +invalidJsonJwtExceptionMessage = Ungültiger JSON-Wert in JWT gefunden +unsupportedFunctionInServerlessContextExceptionMessage = Die Funktion {0} wird in einem serverlosen Kontext nicht unterstützt. +invalidPathWildcardOrDirectoryExceptionMessage = Der angegebene Pfad darf kein Platzhalter oder Verzeichnis sein: {0} +invalidExceptionTypeExceptionMessage = Die Ausnahme hat einen ungültigen Typ. Er sollte entweder WebException oder HttpRequestException sein, aber es wurde {0} erhalten +pathToLoadNotFoundExceptionMessage = Pfad zum Laden von {0} nicht gefunden: {1} +singleValueForIntervalExceptionMessage = Sie können nur einen einzelnen {0}-Wert angeben, wenn Sie Intervalle verwenden. +scriptErrorExceptionMessage = Fehler '{0}' im Skript {1} {2} (Zeile {3}) Zeichen {4} beim Ausführen von {5} auf {6} Objekt '{7}' Klasse: {8} Basisklasse: {9} +noScriptBlockSuppliedExceptionMessage = Kein Skriptblock angegeben. +iisAspnetcoreTokenMissingExceptionMessage = Das IIS-ASPNETCORE_TOKEN fehlt. +invalidContentTypeForSchemaExceptionMessage = Ungültiger Inhaltstyp für Schema gefunden: {0} +propertiesParameterWithoutNameExceptionMessage = Die Eigenschaftsparameter können nicht verwendet werden, wenn die Eigenschaft keinen Namen hat. +multiTypePropertiesRequireOpenApi31ExceptionMessage = Mehrfachtyp-Eigenschaften erfordern OpenApi-Version 3.1 oder höher. +openApiVersionPropertyMandatoryExceptionMessage = Die Eigenschaft OpenApi-Version ist obligatorisch. +webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = Das Webhooks-Feature wird in OpenAPI v3.0.x nicht unterstützt. +authenticationMethodDoesNotExistExceptionMessage = Authentifizierungsmethode existiert nicht: {0} +unsupportedObjectExceptionMessage = Nicht unterstütztes Objekt +validationOfAnyOfSchemaNotSupportedExceptionMessage = Die Validierung eines Schemas, das 'anyof' enthält, wird nicht unterstützt. +validationOfOneOfSchemaNotSupportedExceptionMessage = Die Validierung eines Schemas, das 'oneof' enthält, wird nicht unterstützt. +cannotCreatePropertyWithoutTypeExceptionMessage = Die Eigenschaft kann nicht erstellt werden, weil kein Typ definiert ist. +paramsNoAdditionalPropertiesExclusiveExceptionMessage = Die Parameter -NoAdditionalProperties und -AdditionalProperties schließen sich gegenseitig aus. +headerMustHaveNameInEncodingContextExceptionMessage = Ein Header muss einen Namen haben, wenn er im Codierungskontext verwendet wird. +descriptionRequiredExceptionMessage = Eine Beschreibung ist erforderlich. +openApiDocumentNotCompliantExceptionMessage = Das OpenAPI-Dokument ist nicht konform. +noComponentInDefinitionExceptionMessage = Es ist keine Komponente des Typs {0} mit dem Namen {1} in der Definition {2} verfügbar. +methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: Bereits definiert. +methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: Bereits für {2} definiert. +invalidMiddlewareTypeExceptionMessage = Eines der angegebenen Middleware-Objekte ist ein ungültiger Typ. Erwartet wurde entweder ein ScriptBlock oder ein Hashtable, aber erhalten wurde: {0}. +hashtableMiddlewareNoLogicExceptionMessage = Eine angegebene Hashtable-Middleware enthält keine definierte Logik. +invalidLogicTypeInHashtableMiddlewareExceptionMessage = Eine angegebene Hashtable-Middleware enthält einen ungültigen Logik-Typ. Erwartet wurde ein ScriptBlock, aber erhalten wurde: {0}. +scopedVariableAlreadyDefinedExceptionMessage = Die Bereichsvariable ist bereits definiert: {0}. +valueForUsingVariableNotFoundExceptionMessage = Der Wert für `$using:{0}` konnte nicht gefunden werden. +unlockSecretRequiredExceptionMessage = Eine 'UnlockSecret'-Eigenschaft ist erforderlich, wenn Microsoft.PowerShell.SecretStore verwendet wird. +unlockSecretButNoScriptBlockExceptionMessage = Unlock secret für benutzerdefinierten Secret Vault-Typ angegeben, aber kein Unlock ScriptBlock bereitgestellt. +noUnlockScriptBlockForVaultExceptionMessage = Kein Unlock ScriptBlock für das Entsperren des Tresors '{0}' bereitgestellt. +noSetScriptBlockForVaultExceptionMessage = Kein Set ScriptBlock für das Aktualisieren/Erstellen von Geheimnissen im Tresor '{0}' bereitgestellt. +noRemoveScriptBlockForVaultExceptionMessage = Kein Remove ScriptBlock für das Entfernen von Geheimnissen im Tresor '{0}' bereitgestellt. +invalidSecretValueTypeExceptionMessage = Der Geheimniswert hat einen ungültigen Typ. Erwartete Typen: String, SecureString, HashTable, Byte[] oder PSCredential. Aber erhalten wurde: {0}. +limitValueCannotBeZeroOrLessExceptionMessage = Der Grenzwert darf für {0} nicht 0 oder weniger sein. +secondsValueCannotBeZeroOrLessExceptionMessage = Der Sekundenwert darf für {0} nicht 0 oder weniger sein. +failedToCreateOpenSslCertExceptionMessage = Erstellung des OpenSSL-Zertifikats fehlgeschlagen: {0}. +certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Zertifikat-Thumbprints/Name werden nur unter Windows unterstützt. +noCertificateFoundExceptionMessage = Es wurde kein Zertifikat in {0}\{1} für '{2}' gefunden. +runspacePoolFailedToLoadExceptionMessage = {0} RunspacePool konnte nicht geladen werden. +noServiceHandlersDefinedExceptionMessage = Es wurden keine Service-Handler definiert. +noSessionToSetOnResponseExceptionMessage = Keine Sitzung verfügbar, die auf die Antwort gesetzt werden kann. +noSessionToCalculateDataHashExceptionMessage = Keine Sitzung verfügbar, um den Datenhash zu berechnen. +moduleOrVersionNotFoundExceptionMessage = Modul oder Version nicht gefunden auf {0}: {1}@{2} +noSmtpHandlersDefinedExceptionMessage = Es wurden keine SMTP-Handler definiert. +taskTimedOutExceptionMessage = Aufgabe ist nach {0}ms abgelaufen. +verbAlreadyDefinedExceptionMessage = [Verb] {0}: Bereits definiert. +verbAlreadyDefinedForUrlExceptionMessage = [Verb] {0}: Bereits für {1} definiert. +pathOrScriptBlockRequiredExceptionMessage = Ein Pfad oder ScriptBlock ist erforderlich, um die benutzerdefinierten Zugriffswerte zu beziehen. +accessMethodAlreadyDefinedExceptionMessage = Zugriffsmethode bereits definiert: {0}. +accessMethodNotExistForMergingExceptionMessage = Zugriffsmethode zum Zusammenführen nicht vorhanden: {0}. +routeAlreadyContainsCustomAccessExceptionMessage = Die Route '[{0}] {1}' enthält bereits einen benutzerdefinierten Zugriff mit dem Namen '{2}'. +accessMethodNotExistExceptionMessage = Zugriffsmethode nicht vorhanden: {0}. +pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = Das PathItems-Feature wird in OpenAPI v3.0.x nicht unterstützt. '@ \ No newline at end of file diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 25956ad06..8acaf4230 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -1,24 +1,88 @@ ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyMessage = Active Directory module only available on Windows -adModuleNotInstalledMessage = Active Directory module is not installed -secretManagementModuleNotInstalledMessage = Microsoft.PowerShell.SecretManagement module not installed -secretVaultAlreadyRegisteredMessage = A Secret Vault with the name '{0}' has already been registered while auto-importing Secret Vaults -failedToOpenRunspacePoolMessage = Failed to open RunspacePool: {0} -cronExpressionInvalidMessage = Cron expression should only consist of 5 parts: {0} -invalidAliasFoundMessage = Invalid {0} alias found: {1} -invalidAtomCharacterMessage = Invalid atom character: {0} -minValueGreaterThanMaxMessage = Min value for {0} should not be greater than the max value -minValueInvalidMessage = Min value '{0}' for {1} is invalid, should be greater than/equal to {2} -maxValueInvalidMessage = Max value '{0}' for {1} is invalid, should be less than/equal to {2} -valueOutOfRangeMessage = Value '{0}' for {1} is invalid, should be between {2} and {3} -daysInMonthExceededMessage = {0} only has {1} days, but {2} was supplied -nextTriggerCalculationErrorMessage = Looks like something went wrong trying to calculate the next trigger datetime: {0} -incompatiblePodeDllMessage = An existing incompatible Pode.DLL version {0} is loaded. Version {1} is required. Open a new Powershell/pwsh session and retry. -endpointNotExistMessage = Endpoint with protocol '{0}' and address '{1}' or local address '{2}' does not exist -endpointNameNotExistMessage = Endpoint with name '{0}' does not exist -failedToConnectToUrlMessage = Failed to connect to URL: {0} -failedToParseAddressMessage = Failed to parse '{0}' as a valid IP/Host:Port address -invalidIpAddressMessage = The IP address supplied is invalid: {0} -invalidPortMessage = The port cannot be negative: {0} -pathNotExistMessage = Path does not exist: {0} +adModuleWindowsOnlyExceptionMessage = Active Directory module only available on Windows. +adModuleNotInstalledExceptionMessage = Active Directory module is not installed. +secretManagementModuleNotInstalledExceptionMessage = Microsoft.PowerShell.SecretManagement module not installed. +secretVaultAlreadyRegisteredExceptionMessage = A Secret Vault with the name '{0}' has already been registered while auto-importing Secret Vaults. +failedToOpenRunspacePoolExceptionMessage = Failed to open RunspacePool: {0} +cronExpressionInvalidExceptionMessage = Cron expression should only consist of 5 parts: {0} +invalidAliasFoundExceptionMessage = Invalid {0} alias found: {1} +invalidAtomCharacterExceptionMessage = Invalid atom character: {0} +minValueGreaterThanMaxExceptionMessage = Min value for {0} should not be greater than the max value. +minValueInvalidExceptionMessage = Min value '{0}' for {1} is invalid, should be greater than/equal to {2} +maxValueInvalidExceptionMessage = Max value '{0}' for {1} is invalid, should be less than/equal to {2} +valueOutOfRangeExceptionMessage = Value '{0}' for {1} is invalid, should be between {2} and {3} +daysInMonthExceededExceptionMessage = {0} only has {1} days, but {2} was supplied. +nextTriggerCalculationErrorExceptionMessage = Looks like something went wrong trying to calculate the next trigger datetime: {0} +incompatiblePodeDllExceptionMessage = An existing incompatible Pode.DLL version {0} is loaded. Version {1} is required. Open a new Powershell/pwsh session and retry. +endpointNotExistExceptionMessage = Endpoint with protocol '{0}' and address '{1}' or local address '{2}' does not exist. +endpointNameNotExistExceptionMessage = Endpoint with name '{0}' does not exist. +failedToConnectToUrlExceptionMessage = Failed to connect to URL: {0} +failedToParseAddressExceptionMessage = Failed to parse '{0}' as a valid IP/Host:Port address +invalidIpAddressExceptionMessage = The IP address supplied is invalid: {0} +invalidPortExceptionMessage = The port cannot be negative: {0} +pathNotExistExceptionMessage = Path does not exist: {0} +noSecretForHmac256ExceptionMessage = No secret supplied for HMAC256 hash. +noSecretForHmac384ExceptionMessage = No secret supplied for HMAC384 hash. +noSecretForHmac512ExceptionMessage = No secret supplied for HMAC512 hash. +noSecretForJwtSignatureExceptionMessage = No secret supplied for JWT signature. +noSecretExpectedForNoSignatureExceptionMessage = Expected no secret to be supplied for no signature. +unsupportedJwtAlgorithmExceptionMessage = The JWT algorithm is not currently supported: {0} +invalidBase64JwtExceptionMessage = Invalid Base64 encoded value found in JWT +invalidJsonJwtExceptionMessage = Invalid JSON value found in JWT +unsupportedFunctionInServerlessContextExceptionMessage = The {0} function is not supported in a serverless context. +invalidPathWildcardOrDirectoryExceptionMessage = The Path supplied cannot be a wildcard or a directory: {0} +invalidExceptionTypeExceptionMessage = Exception is of an invalid type, should be either WebException or HttpRequestException, but got: {0} +pathToLoadNotFoundExceptionMessage = Path to load {0} not found: {1} +singleValueForIntervalExceptionMessage = You can only supply a single {0} value when using intervals. +scriptErrorExceptionMessage = Error '{0}' in script {1} {2} (line {3}) char {4} executing {5} on {6} object '{7}' Class: {8} BaseClass: {9} +noScriptBlockSuppliedExceptionMessage = No ScriptBlock supplied. +iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN is missing. +invalidContentTypeForSchemaExceptionMessage = Invalid content-type found for schema: {0} +propertiesParameterWithoutNameExceptionMessage = The Properties parameters cannot be used if the Property has no name. +multiTypePropertiesRequireOpenApi31ExceptionMessage = Multi-type properties require OpenApi Version 3.1 or above. +openApiVersionPropertyMandatoryExceptionMessage = OpenApi Version property is mandatory. +webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = The Webhooks feature is not supported in OpenAPI v3.0.x +authenticationMethodDoesNotExistExceptionMessage = Authentication method does not exist: {0} +unsupportedObjectExceptionMessage = Unsupported object +validationOfAnyOfSchemaNotSupportedExceptionMessage = Validation of a schema that includes 'anyof' is not supported. +validationOfOneOfSchemaNotSupportedExceptionMessage = Validation of a schema that includes 'oneof' is not supported. +cannotCreatePropertyWithoutTypeExceptionMessage = Cannot create the property because no type is defined. +paramsNoAdditionalPropertiesExclusiveExceptionMessage = Params -NoAdditionalProperties and -AdditionalProperties are mutually exclusive. +headerMustHaveNameInEncodingContextExceptionMessage = Header must have a name when used in an encoding context. +descriptionRequiredExceptionMessage = A Description is required. +openApiDocumentNotCompliantExceptionMessage = OpenAPI document is not compliant. +noComponentInDefinitionExceptionMessage = No component of type {0} named {1} is available in the {2} definition. +methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: Already defined. +methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: Already defined for {2} +invalidMiddlewareTypeExceptionMessage = One of the Middlewares supplied is an invalid type. Expected either a ScriptBlock or Hashtable, but got: {0} +hashtableMiddlewareNoLogicExceptionMessage = A Hashtable Middleware supplied has no Logic defined. +invalidLogicTypeInHashtableMiddlewareExceptionMessage = A Hashtable Middleware supplied has an invalid Logic type. Expected ScriptBlock, but got: {0} +scopedVariableAlreadyDefinedExceptionMessage = Scoped Variable already defined: {0} +valueForUsingVariableNotFoundExceptionMessage = Value for `$using:{0}` could not be found. +unlockSecretRequiredExceptionMessage = An 'UnlockSecret' property is required when using Microsoft.PowerShell.SecretStore +unlockSecretButNoScriptBlockExceptionMessage = Unlock secret supplied for custom Secret Vault type, but not Unlock ScriptBlock supplied. +noUnlockScriptBlockForVaultExceptionMessage = No Unlock ScriptBlock supplied for unlocking the vault '{0}' +noSetScriptBlockForVaultExceptionMessage = No Set ScriptBlock supplied for updating/creating secrets in the vault '{0}' +noRemoveScriptBlockForVaultExceptionMessage = No Remove ScriptBlock supplied for removing secrets from the vault '{0}' +invalidSecretValueTypeExceptionMessage = Secret value is of an invalid type. Expected types: String, SecureString, HashTable, Byte[], or PSCredential. But got: {0} +limitValueCannotBeZeroOrLessExceptionMessage = Limit value cannot be 0 or less for {0} +secondsValueCannotBeZeroOrLessExceptionMessage = Seconds value cannot be 0 or less for {0} +failedToCreateOpenSslCertExceptionMessage = Failed to create openssl cert: {0} +certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Certificate Thumbprints/Name are only supported on Windows. +noCertificateFoundExceptionMessage = No certificate could be found in {0}\{1} for '{2}' +runspacePoolFailedToLoadExceptionMessage = {0} RunspacePool failed to load. +noServiceHandlersDefinedExceptionMessage = No Service handlers have been defined. +noSessionToSetOnResponseExceptionMessage = There is no session available to set on the response. +noSessionToCalculateDataHashExceptionMessage = No session available to calculate data hash. +moduleOrVersionNotFoundExceptionMessage = Module or version not found on {0}: {1}@{2} +noSmtpHandlersDefinedExceptionMessage = No SMTP handlers have been defined. +taskTimedOutExceptionMessage = Task has timed out after {0}ms. +verbAlreadyDefinedExceptionMessage = [Verb] {0}: Already defined +verbAlreadyDefinedForUrlExceptionMessage = [Verb] {0}: Already defined for {1} +pathOrScriptBlockRequiredExceptionMessage = A Path or ScriptBlock is required for sourcing the Custom access values. +accessMethodAlreadyDefinedExceptionMessage = Access method already defined: {0} +accessMethodNotExistForMergingExceptionMessage = Access method does not exist for merging: {0} +routeAlreadyContainsCustomAccessExceptionMessage = Route '[{0}] {1}' already contains Custom Access with name '{2}' +accessMethodNotExistExceptionMessage = Access method does not exist: {0} +pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = The PathItems feature is not supported in OpenAPI v3.0.x '@ \ No newline at end of file diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 67ac8cc3e..c670efd3e 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -1,24 +1,88 @@ ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyMessage = El módulo de Active Directory solo está disponible en Windows -adModuleNotInstalledMessage = El módulo de Active Directory no está instalado -secretManagementModuleNotInstalledMessage = El módulo Microsoft.PowerShell.SecretManagement no está instalado -secretVaultAlreadyRegisteredMessage = Ya se ha registrado un Bóveda Secreta con el nombre '{0}' al importar automáticamente Bóvedas Secretas -failedToOpenRunspacePoolMessage = Error al abrir RunspacePool: {0} -cronExpressionInvalidMessage = La expresión Cron solo debe consistir en 5 partes: {0} -invalidAliasFoundMessage = Se encontró un alias {0} no válido: {1} -invalidAtomCharacterMessage = Carácter atómico no válido: {0} -minValueGreaterThanMaxMessage = El valor mínimo para {0} no debe ser mayor que el valor máximo -minValueInvalidMessage = El valor mínimo '{0}' para {1} no es válido, debe ser mayor o igual a {2} -maxValueInvalidMessage = El valor máximo '{0}' para {1} no es válido, debe ser menor o igual a {2} -valueOutOfRangeMessage = El valor '{0}' para {1} no es válido, debe estar entre {2} y {3} -daysInMonthExceededMessage = {0} solo tiene {1} días, pero se suministró {2} -nextTriggerCalculationErrorMessage = Parece que algo salió mal al intentar calcular la siguiente fecha y hora del disparador: {0} -incompatiblePodeDllMessage = Se ha cargado una versión incompatible existente de Pode.DLL {0}. Se requiere la versión {1}. Abra una nueva sesión de Powershell/pwsh e intente de nuevo. -endpointNotExistMessage = No existe un punto de conexión con el protocolo '{0}' y la dirección '{1}' o la dirección local '{2}' -endpointNameNotExistMessage = No existe un punto de conexión con el nombre '{0}' -failedToConnectToUrlMessage = Error al conectar con la URL: {0} -failedToParseAddressMessage = Error al analizar '{0}' como una dirección IP/Host:Puerto válida -invalidIpAddressMessage = La dirección IP suministrada no es válida: {0} -invalidPortMessage = El puerto no puede ser negativo: {0} -pathNotExistMessage = La ruta no existe: {0} +adModuleWindowsOnlyExceptionMessage = El módulo de Active Directory solo está disponible en Windows. +adModuleNotInstalledExceptionMessage = El módulo de Active Directory no está instalado. +secretManagementModuleNotInstalledExceptionMessage = El módulo Microsoft.PowerShell.SecretManagement no está instalado. +secretVaultAlreadyRegisteredExceptionMessage = Ya se ha registrado un Bóveda Secreta con el nombre '{0}' al importar automáticamente Bóvedas Secretas. +failedToOpenRunspacePoolExceptionMessage = Error al abrir RunspacePool: {0} +cronExpressionInvalidExceptionMessage = La expresión Cron solo debe consistir en 5 partes: {0} +invalidAliasFoundExceptionMessage = Se encontró un alias {0} no válido: {1} +invalidAtomCharacterExceptionMessage = Carácter atómico no válido: {0} +minValueGreaterThanMaxExceptionMessage = El valor mínimo para {0} no debe ser mayor que el valor máximo. +minValueInvalidExceptionMessage = El valor mínimo '{0}' para {1} no es válido, debe ser mayor o igual a {2} +maxValueInvalidExceptionMessage = El valor máximo '{0}' para {1} no es válido, debe ser menor o igual a {2} +valueOutOfRangeExceptionMessage = El valor '{0}' para {1} no es válido, debe estar entre {2} y {3} +daysInMonthExceededExceptionMessage = {0} solo tiene {1} días, pero se suministró {2}. +nextTriggerCalculationErrorExceptionMessage = Parece que algo salió mal al intentar calcular la siguiente fecha y hora del disparador: {0} +incompatiblePodeDllExceptionMessage = Se ha cargado una versión incompatible existente de Pode.DLL {0}. Se requiere la versión {1}. Abra una nueva sesión de Powershell/pwsh e intente de nuevo. +endpointNotExistExceptionMessage = No existe un punto de conexión con el protocolo '{0}' y la dirección '{1}' o la dirección local '{2}'. +endpointNameNotExistExceptionMessage = No existe un punto de conexión con el nombre '{0}'. +failedToConnectToUrlExceptionMessage = Error al conectar con la URL: {0} +failedToParseAddressExceptionMessage = Error al analizar '{0}' como una dirección IP/Host:Puerto válida +invalidIpAddressExceptionMessage = La dirección IP suministrada no es válida: {0} +invalidPortExceptionMessage = El puerto no puede ser negativo: {0} +pathNotExistExceptionMessage = La ruta no existe: {0} +noSecretForHmac256ExceptionMessage = No se suministró ningún secreto para el hash HMAC256. +noSecretForHmac384ExceptionMessage = No se suministró ningún secreto para el hash HMAC384. +noSecretForHmac512ExceptionMessage = No se suministró ningún secreto para el hash HMAC512. +noSecretForJwtSignatureExceptionMessage = No se suministró ningún secreto para la firma JWT. +noSecretExpectedForNoSignatureExceptionMessage = Se esperaba que no se suministrara ningún secreto para ninguna firma. +unsupportedJwtAlgorithmExceptionMessage = El algoritmo JWT actualmente no es compatible: {0} +invalidBase64JwtExceptionMessage = Valor Base64 no válido encontrado en JWT +invalidJsonJwtExceptionMessage = Valor JSON no válido encontrado en JWT +unsupportedFunctionInServerlessContextExceptionMessage = La función {0} no es compatible en un contexto sin servidor. +invalidPathWildcardOrDirectoryExceptionMessage = La ruta suministrada no puede ser un comodín o un directorio: {0} +invalidExceptionTypeExceptionMessage = La excepción es de un tipo no válido, debe ser WebException o HttpRequestException, pero se obtuvo: {0} +pathToLoadNotFoundExceptionMessage = No se encontró la ruta para cargar {0}: {1} +singleValueForIntervalExceptionMessage = Solo puede suministrar un único valor {0} cuando utiliza intervalos. +scriptErrorExceptionMessage = Error '{0}' en el script {1} {2} (línea {3}) carácter {4} al ejecutar {5} en el objeto {6} '{7}' Clase: {8} ClaseBase: {9} +noScriptBlockSuppliedExceptionMessage = No se suministró ningún ScriptBlock. +iisAspnetcoreTokenMissingExceptionMessage = Falta el token IIS ASPNETCORE_TOKEN. +invalidContentTypeForSchemaExceptionMessage = Tipo de contenido no válido encontrado para el esquema: {0} +propertiesParameterWithoutNameExceptionMessage = Los parámetros de propiedades no se pueden usar si la propiedad no tiene nombre. +multiTypePropertiesRequireOpenApi31ExceptionMessage = Las propiedades de tipo múltiple requieren OpenApi versión 3.1 o superior. +openApiVersionPropertyMandatoryExceptionMessage = La propiedad de versión OpenApi es obligatoria. +webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = La función de Webhooks no es compatible con OpenAPI v3.0.x +authenticationMethodDoesNotExistExceptionMessage = El método de autenticación no existe: {0} +unsupportedObjectExceptionMessage = Objeto no compatible +validationOfAnyOfSchemaNotSupportedExceptionMessage = La validación de un esquema que incluye 'anyof' no es compatible. +validationOfOneOfSchemaNotSupportedExceptionMessage = La validación de un esquema que incluye 'oneof' no es compatible. +cannotCreatePropertyWithoutTypeExceptionMessage = No se puede crear la propiedad porque no se ha definido ningún tipo. +paramsNoAdditionalPropertiesExclusiveExceptionMessage = Los parámetros -NoAdditionalProperties y -AdditionalProperties son mutuamente excluyentes. +headerMustHaveNameInEncodingContextExceptionMessage = El encabezado debe tener un nombre cuando se usa en un contexto de codificación. +descriptionRequiredExceptionMessage = Se requiere una descripción. +openApiDocumentNotCompliantExceptionMessage = El documento OpenAPI no cumple con las normas. +noComponentInDefinitionExceptionMessage = No hay componente del tipo {0} llamado {1} disponible en la definición de {2}. +methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: Ya está definido. +methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: Ya está definido para {2} +invalidMiddlewareTypeExceptionMessage = Uno de los Middlewares suministrados es de un tipo no válido. Se esperaba ScriptBlock o Hashtable, pero se obtuvo: {0} +hashtableMiddlewareNoLogicExceptionMessage = Un Middleware Hashtable suministrado no tiene lógica definida. +invalidLogicTypeInHashtableMiddlewareExceptionMessage = Un Middleware Hashtable suministrado tiene un tipo de lógica no válido. Se esperaba ScriptBlock, pero se obtuvo: {0} +scopedVariableAlreadyDefinedExceptionMessage = La variable con alcance ya está definida: {0} +valueForUsingVariableNotFoundExceptionMessage = No se pudo encontrar el valor para `$using:{0}`. +unlockSecretRequiredExceptionMessage = Se requiere una propiedad 'UnlockSecret' al usar Microsoft.PowerShell.SecretStore +unlockSecretButNoScriptBlockExceptionMessage = Se suministró un secreto de desbloqueo para el tipo de bóveda secreta personalizada, pero no se suministró ningún ScriptBlock de desbloqueo. +noUnlockScriptBlockForVaultExceptionMessage = No se suministró ningún ScriptBlock de desbloqueo para desbloquear la bóveda '{0}' +noSetScriptBlockForVaultExceptionMessage = No se suministró ningún ScriptBlock de configuración para actualizar/crear secretos en la bóveda '{0}' +noRemoveScriptBlockForVaultExceptionMessage = No se suministró ningún ScriptBlock de eliminación para eliminar secretos de la bóveda '{0}' +invalidSecretValueTypeExceptionMessage = El valor del secreto es de un tipo no válido. Tipos esperados: String, SecureString, HashTable, Byte[], o PSCredential. Pero se obtuvo: {0} +limitValueCannotBeZeroOrLessExceptionMessage = El valor del límite no puede ser 0 o menor para {0} +secondsValueCannotBeZeroOrLessExceptionMessage = El valor en segundos no puede ser 0 o menor para {0} +failedToCreateOpenSslCertExceptionMessage = Error al crear el certificado openssl: {0} +certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Las huellas digitales/nombres de certificados solo son compatibles con Windows. +noCertificateFoundExceptionMessage = No se encontró ningún certificado en {0}\{1} para '{2}' +runspacePoolFailedToLoadExceptionMessage = {0} RunspacePool no se pudo cargar. +noServiceHandlersDefinedExceptionMessage = No se han definido controladores de servicio. +noSessionToSetOnResponseExceptionMessage = No hay ninguna sesión disponible para configurar en la respuesta. +noSessionToCalculateDataHashExceptionMessage = No hay ninguna sesión disponible para calcular el hash de datos. +moduleOrVersionNotFoundExceptionMessage = No se encontró el módulo o la versión en {0}: {1}@{2} +noSmtpHandlersDefinedExceptionMessage = No se han definido controladores SMTP. +taskTimedOutExceptionMessage = La tarea ha agotado el tiempo después de {0}ms. +verbAlreadyDefinedExceptionMessage = [Verbo] {0}: Ya está definido +verbAlreadyDefinedForUrlExceptionMessage = [Verbo] {0}: Ya está definido para {1} +pathOrScriptBlockRequiredExceptionMessage = Se requiere una ruta o un ScriptBlock para obtener los valores de acceso personalizados. +accessMethodAlreadyDefinedExceptionMessage = Método de acceso ya definido: {0} +accessMethodNotExistForMergingExceptionMessage = El método de acceso no existe para fusionarse: {0} +routeAlreadyContainsCustomAccessExceptionMessage = La ruta '[{0}] {1}' ya contiene acceso personalizado con el nombre '{2}' +accessMethodNotExistExceptionMessage = El método de acceso no existe: {0} +pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = La función de elementos de ruta no es compatible con OpenAPI v3.0.x '@ \ No newline at end of file diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index f7c33aa37..bc41e11a4 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -1,24 +1,88 @@ ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyMessage = Le module Active Directory est uniquement disponible sur Windows -adModuleNotInstalledMessage = Le module Active Directory n'est pas installé -secretManagementModuleNotInstalledMessage = Le module Microsoft.PowerShell.SecretManagement n'est pas installé -secretVaultAlreadyRegisteredMessage = Un coffre-fort secret avec le nom '{0}' a déjà été enregistré lors de l'importation automatique des coffres-forts secrets -failedToOpenRunspacePoolMessage = Échec de l'ouverture de RunspacePool : {0} -cronExpressionInvalidMessage = L'expression Cron doit uniquement comporter 5 parties : {0} -invalidAliasFoundMessage = Alias {0} non valide trouvé : {1} -invalidAtomCharacterMessage = Caractère atomique non valide : {0} -minValueGreaterThanMaxMessage = La valeur minimale pour {0} ne doit pas être supérieure à la valeur maximale -minValueInvalidMessage = La valeur minimale '{0}' pour {1} n'est pas valide, elle doit être supérieure ou égale à {2} -maxValueInvalidMessage = La valeur maximale '{0}' pour {1} n'est pas valide, elle doit être inférieure ou égale à {2} -valueOutOfRangeMessage = La valeur '{0}' pour {1} n'est pas valide, elle doit être comprise entre {2} et {3} -daysInMonthExceededMessage = {0} n'a que {1} jours, mais {2} a été fourni -nextTriggerCalculationErrorMessage = Il semble que quelque chose ait mal tourné lors de la tentative de calcul de la prochaine date et heure de déclenchement : {0} -incompatiblePodeDllMessage = Une version incompatible existante de Pode.DLL {0} est chargée. La version {1} est requise. Ouvrez une nouvelle session Powershell/pwsh et réessayez. -endpointNotExistMessage = Un point de terminaison avec le protocole '{0}' et l'adresse '{1}' ou l'adresse locale '{2}' n'existe pas -endpointNameNotExistMessage = Un point de terminaison avec le nom '{0}' n'existe pas -failedToConnectToUrlMessage = Échec de la connexion à l'URL : {0} -failedToParseAddressMessage = Échec de l'analyse de '{0}' en tant qu'adresse IP/Hôte:Port valide -invalidIpAddressMessage = L'adresse IP fournie n'est pas valide : {0} -invalidPortMessage = Le port ne peut pas être négatif : {0} -pathNotExistMessage = Le chemin n'existe pas : {0} +adModuleWindowsOnlyExceptionMessage = Le module Active Directory est uniquement disponible sur Windows. +adModuleNotInstalledExceptionMessage = Le module Active Directory n'est pas installé. +secretManagementModuleNotInstalledExceptionMessage = Le module Microsoft.PowerShell.SecretManagement n'est pas installé. +secretVaultAlreadyRegisteredExceptionMessage = Un coffre-fort secret avec le nom '{0}' a déjà été enregistré lors de l'importation automatique des coffres-forts secrets. +failedToOpenRunspacePoolExceptionMessage = Échec de l'ouverture de RunspacePool : {0} +cronExpressionInvalidExceptionMessage = L'expression Cron doit uniquement comporter 5 parties : {0} +invalidAliasFoundExceptionMessage = Alias {0} non valide trouvé : {1} +invalidAtomCharacterExceptionMessage = Caractère atomique non valide : {0} +minValueGreaterThanMaxExceptionMessage = La valeur minimale pour {0} ne doit pas être supérieure à la valeur maximale. +minValueInvalidExceptionMessage = La valeur minimale '{0}' pour {1} n'est pas valide, elle doit être supérieure ou égale à {2} +maxValueInvalidExceptionMessage = La valeur maximale '{0}' pour {1} n'est pas valide, elle doit être inférieure ou égale à {2} +valueOutOfRangeExceptionMessage = La valeur '{0}' pour {1} n'est pas valide, elle doit être comprise entre {2} et {3} +daysInMonthExceededExceptionMessage = {0} n'a que {1} jours, mais {2} a été fourni. +nextTriggerCalculationErrorExceptionMessage = Il semble que quelque chose ait mal tourné lors de la tentative de calcul de la prochaine date et heure de déclenchement : {0} +incompatiblePodeDllExceptionMessage = Une version incompatible existante de Pode.DLL {0} est chargée. La version {1} est requise. Ouvrez une nouvelle session Powershell/pwsh et réessayez. +endpointNotExistExceptionMessage = Un point de terminaison avec le protocole '{0}' et l'adresse '{1}' ou l'adresse locale '{2}' n'existe pas. +endpointNameNotExistExceptionMessage = Un point de terminaison avec le nom '{0}' n'existe pas. +failedToConnectToUrlExceptionMessage = Échec de la connexion à l'URL : {0} +failedToParseAddressExceptionMessage = Échec de l'analyse de '{0}' en tant qu'adresse IP/Hôte:Port valide +invalidIpAddressExceptionMessage = L'adresse IP fournie n'est pas valide : {0} +invalidPortExceptionMessage = Le port ne peut pas être négatif : {0} +pathNotExistExceptionMessage = Le chemin n'existe pas : {0} +noSecretForHmac256ExceptionMessage = Aucun secret fourni pour le hachage HMAC256. +noSecretForHmac384ExceptionMessage = Aucun secret fourni pour le hachage HMAC384. +noSecretForHmac512ExceptionMessage = Aucun secret fourni pour le hachage HMAC512. +noSecretForJwtSignatureExceptionMessage = Aucun secret fourni pour la signature JWT. +noSecretExpectedForNoSignatureExceptionMessage = Aucun secret attendu pour aucune signature. +unsupportedJwtAlgorithmExceptionMessage = L'algorithme JWT n'est actuellement pas pris en charge : {0} +invalidBase64JwtExceptionMessage = Valeur encodée en Base64 non valide trouvée dans le JWT +invalidJsonJwtExceptionMessage = Valeur JSON non valide trouvée dans le JWT +unsupportedFunctionInServerlessContextExceptionMessage = La fonction {0} n'est pas prise en charge dans un contexte sans serveur. +invalidPathWildcardOrDirectoryExceptionMessage = Le chemin fourni ne peut pas être un caractère générique ou un répertoire : {0} +invalidExceptionTypeExceptionMessage = L'exception est d'un type non valide, doit être soit WebException soit HttpRequestException, mais a obtenu : {0} +pathToLoadNotFoundExceptionMessage = Chemin à charger {0} non trouvé : {1} +singleValueForIntervalExceptionMessage = Vous ne pouvez fournir qu'une seule valeur {0} lorsque vous utilisez des intervalles. +scriptErrorExceptionMessage = Erreur '{0}' dans le script {1} {2} (ligne {3}) char {4} en exécutant {5} sur l'objet {6} '{7}' Classe : {8} ClasseBase : {9} +noScriptBlockSuppliedExceptionMessage = Aucun ScriptBlock fourni. +iisAspnetcoreTokenMissingExceptionMessage = Le jeton IIS ASPNETCORE_TOKEN est manquant. +invalidContentTypeForSchemaExceptionMessage = Type de contenu non valide trouvé pour le schéma : {0} +propertiesParameterWithoutNameExceptionMessage = Les paramètres Properties ne peuvent pas être utilisés si la propriété n'a pas de nom. +multiTypePropertiesRequireOpenApi31ExceptionMessage = Les propriétés multi-types nécessitent OpenApi Version 3.1 ou supérieure. +openApiVersionPropertyMandatoryExceptionMessage = La propriété Version OpenApi est obligatoire. +webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = La fonction Webhooks n'est pas prise en charge dans OpenAPI v3.0.x +authenticationMethodDoesNotExistExceptionMessage = La méthode d'authentification n'existe pas : {0} +unsupportedObjectExceptionMessage = Objet non pris en charge +validationOfAnyOfSchemaNotSupportedExceptionMessage = La validation d'un schéma qui inclut 'anyof' n'est pas prise en charge. +validationOfOneOfSchemaNotSupportedExceptionMessage = La validation d'un schéma qui inclut 'oneof' n'est pas prise en charge. +cannotCreatePropertyWithoutTypeExceptionMessage = Impossible de créer la propriété car aucun type n'est défini. +paramsNoAdditionalPropertiesExclusiveExceptionMessage = Les paramètres -NoAdditionalProperties et -AdditionalProperties sont mutuellement exclusifs. +headerMustHaveNameInEncodingContextExceptionMessage = L'en-tête doit avoir un nom lorsqu'il est utilisé dans un contexte de codage. +descriptionRequiredExceptionMessage = Une description est requise. +openApiDocumentNotCompliantExceptionMessage = Le document OpenAPI n'est pas conforme. +noComponentInDefinitionExceptionMessage = Aucun composant du type {0} nommé {1} n'est disponible dans la définition {2}. +methodPathAlreadyDefinedExceptionMessage = [{0}] {1} : Déjà défini. +methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1} : Déjà défini pour {2} +invalidMiddlewareTypeExceptionMessage = Un des Middlewares fournis est d'un type non valide. Attendu ScriptBlock ou Hashtable, mais a obtenu : {0} +hashtableMiddlewareNoLogicExceptionMessage = Un Middleware Hashtable fourni n'a aucune logique définie. +invalidLogicTypeInHashtableMiddlewareExceptionMessage = Un Middleware Hashtable fourni a un type de logique non valide. Attendu ScriptBlock, mais a obtenu : {0} +scopedVariableAlreadyDefinedExceptionMessage = La variable à portée est déjà définie : {0} +valueForUsingVariableNotFoundExceptionMessage = Valeur pour `$using:{0}` introuvable. +unlockSecretRequiredExceptionMessage = Une propriété 'UnlockSecret' est requise lors de l'utilisation de Microsoft.PowerShell.SecretStore +unlockSecretButNoScriptBlockExceptionMessage = Secret de déverrouillage fourni pour le type de coffre-fort personnalisé, mais aucun ScriptBlock de déverrouillage fourni. +noUnlockScriptBlockForVaultExceptionMessage = Aucun ScriptBlock de déverrouillage fourni pour déverrouiller le coffre '{0}' +noSetScriptBlockForVaultExceptionMessage = Aucun ScriptBlock de configuration fourni pour mettre à jour/créer des secrets dans le coffre '{0}' +noRemoveScriptBlockForVaultExceptionMessage = Aucun ScriptBlock de suppression fourni pour supprimer des secrets du coffre '{0}' +invalidSecretValueTypeExceptionMessage = La valeur du secret est d'un type non valide. Types attendus : String, SecureString, HashTable, Byte[], ou PSCredential. Mais a obtenu : {0} +limitValueCannotBeZeroOrLessExceptionMessage = La valeur de la limite ne peut pas être 0 ou inférieure pour {0} +secondsValueCannotBeZeroOrLessExceptionMessage = La valeur en secondes ne peut pas être 0 ou inférieure pour {0} +failedToCreateOpenSslCertExceptionMessage = Échec de la création du certificat openssl : {0} +certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Les empreintes digitales/Noms de certificat ne sont pris en charge que sous Windows. +noCertificateFoundExceptionMessage = Aucun certificat n'a été trouvé dans {0}\{1} pour '{2}' +runspacePoolFailedToLoadExceptionMessage = {0} RunspacePool n'a pas pu être chargé. +noServiceHandlersDefinedExceptionMessage = Aucun gestionnaire de service défini. +noSessionToSetOnResponseExceptionMessage = Aucune session disponible pour être définie sur la réponse. +noSessionToCalculateDataHashExceptionMessage = Aucune session disponible pour calculer le hachage de données. +moduleOrVersionNotFoundExceptionMessage = Module ou version introuvable sur {0} : {1}@{2} +noSmtpHandlersDefinedExceptionMessage = Aucun gestionnaire SMTP défini. +taskTimedOutExceptionMessage = La tâche a expiré après {0}ms. +verbAlreadyDefinedExceptionMessage = [Verbe] {0} : Déjà défini +verbAlreadyDefinedForUrlExceptionMessage = [Verbe] {0} : Déjà défini pour {1} +pathOrScriptBlockRequiredExceptionMessage = Un chemin ou un ScriptBlock est requis pour obtenir les valeurs d'accès personnalisées. +accessMethodAlreadyDefinedExceptionMessage = Méthode d'accès déjà définie : {0} +accessMethodNotExistForMergingExceptionMessage = La méthode d'accès n'existe pas pour la fusion : {0} +routeAlreadyContainsCustomAccessExceptionMessage = La route '[{0}] {1}' contient déjà un accès personnalisé avec le nom '{2}' +accessMethodNotExistExceptionMessage = La méthode d'accès n'existe pas : {0} +pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = La fonction PathItems n'est pas prise en charge dans OpenAPI v3.0.x '@ \ No newline at end of file diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index b542ea731..b9b2418d4 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -1,24 +1,88 @@ ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyMessage = Il modulo di Active Directory è disponibile solo su Windows -adModuleNotInstalledMessage = Il modulo di Active Directory non è installato -secretManagementModuleNotInstalledMessage = Il modulo Microsoft.PowerShell.SecretManagement non è installato -secretVaultAlreadyRegisteredMessage = Una Secret Vault con il nome '{0}' è già stata registrata durante l'importazione automatica delle Secret Vaults -failedToOpenRunspacePoolMessage = Errore nell'apertura di RunspacePool: {0} -cronExpressionInvalidMessage = L'espressione Cron deve consistere solo di 5 parti: {0} -invalidAliasFoundMessage = Alias {0} non valido trovato: {1} -invalidAtomCharacterMessage = Carattere atomico non valido: {0} -minValueGreaterThanMaxMessage = Il valore minimo per {0} non deve essere maggiore del valore massimo -minValueInvalidMessage = Il valore minimo '{0}' per {1} non è valido, deve essere maggiore o uguale a {2} -maxValueInvalidMessage = Il valore massimo '{0}' per {1} non è valido, deve essere minore o uguale a {2} -valueOutOfRangeMessage = Il valore '{0}' per {1} non è valido, deve essere compreso tra {2} e {3} -daysInMonthExceededMessage = {0} ha solo {1} giorni, ma è stato fornito {2} -nextTriggerCalculationErrorMessage = Sembra che qualcosa sia andato storto nel tentativo di calcolare la prossima data e ora del trigger: {0} -incompatiblePodeDllMessage = È stata caricata una versione incompatibile esistente di Pode.DLL {0}. È richiesta la versione {1}. Aprire una nuova sessione di Powershell/pwsh e riprovare. -endpointNotExistMessage = Non esiste un endpoint con il protocollo '{0}' e l'indirizzo '{1}' o l'indirizzo locale '{2}' -endpointNameNotExistMessage = Non esiste un endpoint con il nome '{0}' -failedToConnectToUrlMessage = Errore nella connessione all'URL: {0} -failedToParseAddressMessage = Errore nell'analisi di '{0}' come indirizzo IP/Host:Porto valido -invalidIpAddressMessage = L'indirizzo IP fornito non è valido: {0} -invalidPortMessage = La porta non può essere negativa: {0} -pathNotExistMessage = Il percorso non esiste: {0} -'@ \ No newline at end of file +adModuleWindowsOnlyExceptionMessage = Il modulo Active Directory è disponibile solo su Windows. +adModuleNotInstalledExceptionMessage = Il modulo Active Directory non è installato. +secretManagementModuleNotInstalledExceptionMessage = Il modulo Microsoft.PowerShell.SecretManagement non è installato. +secretVaultAlreadyRegisteredExceptionMessage = Una cassaforte segreta con il nome '{0}' è già stata registrata durante l'importazione automatica delle cassaforti segrete. +failedToOpenRunspacePoolExceptionMessage = Impossibile aprire RunspacePool: {0} +cronExpressionInvalidExceptionMessage = L'espressione Cron dovrebbe essere composta solo da 5 parti: {0} +invalidAliasFoundExceptionMessage = Alias {0} non valido trovato: {1} +invalidAtomCharacterExceptionMessage = Carattere atomo non valido: {0} +minValueGreaterThanMaxExceptionMessage = Il valore minimo per {0} non deve essere maggiore del valore massimo. +minValueInvalidExceptionMessage = Il valore minimo '{0}' per {1} non è valido, dovrebbe essere maggiore o uguale a {2} +maxValueInvalidExceptionMessage = Il valore massimo '{0}' per {1} non è valido, dovrebbe essere minore o uguale a {2} +valueOutOfRangeExceptionMessage = Il valore '{0}' per {1} non è valido, dovrebbe essere compreso tra {2} e {3} +daysInMonthExceededExceptionMessage = {0} ha solo {1} giorni, ma è stato fornito {2}. +nextTriggerCalculationErrorExceptionMessage = Sembra che ci sia stato un errore nel tentativo di calcolare la prossima data e ora del trigger: {0} +incompatiblePodeDllExceptionMessage = È caricata una versione incompatibile esistente di Pode.DLL {0}. È richiesta la versione {1}. Apri una nuova sessione Powershell/pwsh e riprova. +endpointNotExistExceptionMessage = Endpoint con protocollo '{0}' e indirizzo '{1}' o indirizzo locale '{2}' non esiste. +endpointNameNotExistExceptionMessage = Endpoint con nome '{0}' non esiste. +failedToConnectToUrlExceptionMessage = Impossibile connettersi all'URL: {0} +failedToParseAddressExceptionMessage = Impossibile analizzare '{0}' come indirizzo IP/Host:Port valido +invalidIpAddressExceptionMessage = L'indirizzo IP fornito non è valido: {0} +invalidPortExceptionMessage = La porta non può essere negativa: {0} +pathNotExistExceptionMessage = Il percorso non esiste: {0} +noSecretForHmac256ExceptionMessage = Nessun segreto fornito per l'hash HMAC256. +noSecretForHmac384ExceptionMessage = Nessun segreto fornito per l'hash HMAC384. +noSecretForHmac512ExceptionMessage = Nessun segreto fornito per l'hash HMAC512. +noSecretForJwtSignatureExceptionMessage = Nessun segreto fornito per la firma JWT. +noSecretExpectedForNoSignatureExceptionMessage = Non era previsto alcun segreto per nessuna firma. +unsupportedJwtAlgorithmExceptionMessage = L'algoritmo JWT non è attualmente supportato: {0} +invalidBase64JwtExceptionMessage = Valore codificato Base64 non valido trovato in JWT +invalidJsonJwtExceptionMessage = Valore JSON non valido trovato in JWT +unsupportedFunctionInServerlessContextExceptionMessage = La funzione {0} non è supportata in un contesto senza server. +invalidPathWildcardOrDirectoryExceptionMessage = Il percorso fornito non può essere un carattere jolly o una directory: {0} +invalidExceptionTypeExceptionMessage = L'eccezione è di un tipo non valido, dovrebbe essere WebException o HttpRequestException, ma è stato ottenuto: {0} +pathToLoadNotFoundExceptionMessage = Percorso per caricare {0} non trovato: {1} +singleValueForIntervalExceptionMessage = Puoi fornire solo un singolo valore {0} quando si utilizzano gli intervalli. +scriptErrorExceptionMessage = Errore '{0}' nello script {1} {2} (riga {3}) carattere {4} eseguendo {5} su {6} oggetto '{7}' Classe: {8} Classe di base: {9} +noScriptBlockSuppliedExceptionMessage = Nessun ScriptBlock fornito. +iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN è mancante. +invalidContentTypeForSchemaExceptionMessage = Tipo di contenuto non valido trovato per lo schema: {0} +propertiesParameterWithoutNameExceptionMessage = I parametri Properties non possono essere utilizzati se la proprietà non ha un nome. +multiTypePropertiesRequireOpenApi31ExceptionMessage = Le proprietà multi-tipo richiedono OpenApi versione 3.1 o superiore. +openApiVersionPropertyMandatoryExceptionMessage = La proprietà della versione OpenApi è obbligatoria. +webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = La funzionalità Webhooks non è supportata in OpenAPI v3.0.x +authenticationMethodDoesNotExistExceptionMessage = Il metodo di autenticazione non esiste: {0} +unsupportedObjectExceptionMessage = Oggetto non supportato +validationOfAnyOfSchemaNotSupportedExceptionMessage = La validazione di uno schema che include 'anyof' non è supportata. +validationOfOneOfSchemaNotSupportedExceptionMessage = La validazione di uno schema che include 'oneof' non è supportata. +cannotCreatePropertyWithoutTypeExceptionMessage = Impossibile creare la proprietà perché non è definito alcun tipo. +paramsNoAdditionalPropertiesExclusiveExceptionMessage = I parametri -NoAdditionalProperties e -AdditionalProperties si escludono a vicenda. +headerMustHaveNameInEncodingContextExceptionMessage = L'intestazione deve avere un nome quando viene utilizzata in un contesto di codifica. +descriptionRequiredExceptionMessage = È necessaria una descrizione. +openApiDocumentNotCompliantExceptionMessage = Il documento OpenAPI non è conforme. +noComponentInDefinitionExceptionMessage = Nessun componente del tipo {0} chiamato {1} è disponibile nella definizione {2}. +methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: Già definito. +methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: Già definito per {2} +invalidMiddlewareTypeExceptionMessage = Uno dei Middleware forniti è di un tipo non valido. Previsto ScriptBlock o Hashtable, ma ottenuto: {0} +hashtableMiddlewareNoLogicExceptionMessage = Un Middleware di tipo Hashtable fornito non ha una logica definita. +invalidLogicTypeInHashtableMiddlewareExceptionMessage = Un Middleware di tipo Hashtable fornito ha un tipo di logica non valido. Previsto ScriptBlock, ma ottenuto: {0} +scopedVariableAlreadyDefinedExceptionMessage = Variabile con ambito già definita: {0} +valueForUsingVariableNotFoundExceptionMessage = Impossibile trovare il valore per `$using:{0}`. +unlockSecretRequiredExceptionMessage = È necessaria una proprietà 'UnlockSecret' quando si utilizza Microsoft.PowerShell.SecretStore +unlockSecretButNoScriptBlockExceptionMessage = Segreto di sblocco fornito per tipo di cassaforte segreta personalizzata, ma nessun ScriptBlock di sblocco fornito. +noUnlockScriptBlockForVaultExceptionMessage = Nessun ScriptBlock di sblocco fornito per sbloccare la cassaforte '{0}' +noSetScriptBlockForVaultExceptionMessage = Nessun ScriptBlock fornito per aggiornare/creare segreti nella cassaforte '{0}' +noRemoveScriptBlockForVaultExceptionMessage = Nessun ScriptBlock fornito per rimuovere segreti dalla cassaforte '{0}' +invalidSecretValueTypeExceptionMessage = Il valore segreto è di un tipo non valido. Tipi previsti: String, SecureString, HashTable, Byte[] o PSCredential. Ma ottenuto: {0} +limitValueCannotBeZeroOrLessExceptionMessage = Il valore limite non può essere 0 o inferiore per {0} +secondsValueCannotBeZeroOrLessExceptionMessage = Il valore dei secondi non può essere 0 o inferiore per {0} +failedToCreateOpenSslCertExceptionMessage = Impossibile creare il certificato openssl: {0} +certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Impronte digitali/nome del certificato supportati solo su Windows. +noCertificateFoundExceptionMessage = Nessun certificato trovato in {0}\{1} per '{2}' +runspacePoolFailedToLoadExceptionMessage = Impossibile caricare RunspacePool per {0}. +noServiceHandlersDefinedExceptionMessage = Non sono stati definiti gestori di servizio. +noSessionToSetOnResponseExceptionMessage = Non c'è nessuna sessione disponibile da impostare sulla risposta. +noSessionToCalculateDataHashExceptionMessage = Nessuna sessione disponibile per calcolare l'hash dei dati. +moduleOrVersionNotFoundExceptionMessage = Modulo o versione non trovati su {0}: {1}@{2} +noSmtpHandlersDefinedExceptionMessage = Non sono stati definiti gestori SMTP. +taskTimedOutExceptionMessage = Il compito è scaduto dopo {0}ms. +verbAlreadyDefinedExceptionMessage = [Verbo] {0}: Già definito +verbAlreadyDefinedForUrlExceptionMessage = [Verbo] {0}: Già definito per {1} +pathOrScriptBlockRequiredExceptionMessage = È necessario un percorso o un ScriptBlock per ottenere i valori di accesso personalizzati. +accessMethodAlreadyDefinedExceptionMessage = Metodo di accesso già definito: {0} +accessMethodNotExistForMergingExceptionMessage = Il metodo di accesso non esiste per l'unione: {0} +routeAlreadyContainsCustomAccessExceptionMessage = Il percorso '[{0}] {1}' contiene già un accesso personalizzato con nome '{2}' +accessMethodNotExistExceptionMessage = Il metodo di accesso non esiste: {0} +pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = La funzionalità PathItems non è supportata in OpenAPI v3.0.x +'@ diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index 18b377c3b..6204b57b5 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -1,24 +1,88 @@ ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyMessage = Active DirectoryモジュールはWindowsでのみ利用可能です -adModuleNotInstalledMessage = Active Directoryモジュールがインストールされていません -secretManagementModuleNotInstalledMessage = Microsoft.PowerShell.SecretManagementモジュールがインストールされていません -secretVaultAlreadyRegisteredMessage = シークレットボールト'{0}'は既に登録されています(シークレットボールトの自動インポート中) -failedToOpenRunspacePoolMessage = RunspacePoolのオープンに失敗しました: {0} -cronExpressionInvalidMessage = Cron式は5つの部分で構成される必要があります: {0} -invalidAliasFoundMessage = 無効な{0}エイリアスが見つかりました: {1} -invalidAtomCharacterMessage = 無効なアトム文字: {0} -minValueGreaterThanMaxMessage = {0}の最小値は最大値を超えることはできません -minValueInvalidMessage = {1}の最小値'{0}'は無効です。{2}以上でなければなりません -maxValueInvalidMessage = {1}の最大値'{0}'は無効です。{2}以下でなければなりません -valueOutOfRangeMessage = {1}の値'{0}'は無効です。{2}から{3}の間でなければなりません -daysInMonthExceededMessage = {0}は{1}日しかありませんが、{2}が指定されました -nextTriggerCalculationErrorMessage = 次のトリガー日時の計算中に問題が発生したようです: {0} -incompatiblePodeDllMessage = 既存の互換性のないPode.DLLバージョン{0}がロードされています。バージョン{1}が必要です。新しいPowershell/pwshセッションを開いて再試行してください。 -endpointNotExistMessage = プロトコル'{0}'とアドレス'{1}'またはローカルアドレス'{2}'のエンドポイントが存在しません -endpointNameNotExistMessage = 名前'{0}'のエンドポイントが存在しません -failedToConnectToUrlMessage = URLへの接続に失敗しました: {0} -failedToParseAddressMessage = '{0}'を有効なIP/ホスト:ポートアドレスとして解析できませんでした -invalidIpAddressMessage = 提供されたIPアドレスは無効です: {0} -invalidPortMessage = ポートは負であってはなりません: {0} -pathNotExistMessage = パスが存在しません: {0} +adModuleWindowsOnlyExceptionMessage = Active DirectoryモジュールはWindowsでのみ利用可能です。 +adModuleNotInstalledExceptionMessage = Active Directoryモジュールがインストールされていません。 +secretManagementModuleNotInstalledExceptionMessage = Microsoft.PowerShell.SecretManagementモジュールがインストールされていません。 +secretVaultAlreadyRegisteredExceptionMessage = シークレットボールト'{0}'は既に登録されています(シークレットボールトの自動インポート中)。 +failedToOpenRunspacePoolExceptionMessage = RunspacePoolのオープンに失敗しました: {0} +cronExpressionInvalidExceptionMessage = Cron式は5つの部分で構成される必要があります: {0} +invalidAliasFoundExceptionMessage = 無効な{0}エイリアスが見つかりました: {1} +invalidAtomCharacterExceptionMessage = 無効なアトム文字: {0} +minValueGreaterThanMaxExceptionMessage = {0}の最小値は最大値を超えることはできません。 +minValueInvalidExceptionMessage = {1}の最小値'{0}'は無効です。{2}以上でなければなりません。 +maxValueInvalidExceptionMessage = {1}の最大値'{0}'は無効です。{2}以下でなければなりません。 +valueOutOfRangeExceptionMessage = {1}の値'{0}'は無効です。{2}から{3}の間でなければなりません。 +daysInMonthExceededExceptionMessage = {0}は{1}日しかありませんが、{2}が指定されました。 +nextTriggerCalculationErrorExceptionMessage = 次のトリガー日時の計算中に問題が発生したようです: {0} +incompatiblePodeDllExceptionMessage = 既存の互換性のないPode.DLLバージョン{0}がロードされています。バージョン{1}が必要です。新しいPowerShell/pwshセッションを開いて再試行してください。 +endpointNotExistExceptionMessage = プロトコル'{0}'、アドレス'{1}'またはローカルアドレス'{2}'のエンドポイントが存在しません。 +endpointNameNotExistExceptionMessage = 名前'{0}'のエンドポイントが存在しません。 +failedToConnectToUrlExceptionMessage = URLへの接続に失敗しました: {0} +failedToParseAddressExceptionMessage = '{0}'を有効なIP/ホスト:ポートアドレスとして解析できませんでした。 +invalidIpAddressExceptionMessage = 提供されたIPアドレスは無効です: {0} +invalidPortExceptionMessage = ポートは負であってはなりません: {0} +pathNotExistExceptionMessage = パスが存在しません: {0} +noSecretForHmac256ExceptionMessage = HMAC256ハッシュに対する秘密が提供されていません。 +noSecretForHmac384ExceptionMessage = HMAC384ハッシュに対する秘密が提供されていません。 +noSecretForHmac512ExceptionMessage = HMAC512ハッシュに対する秘密が提供されていません。 +noSecretForJwtSignatureExceptionMessage = JWT署名に対する秘密が提供されていません。 +noSecretExpectedForNoSignatureExceptionMessage = 署名なしのための秘密が提供されることを期待していませんでした。 +unsupportedJwtAlgorithmExceptionMessage = 現在サポートされていないJWTアルゴリズムです: {0} +invalidBase64JwtExceptionMessage = JWTに無効なBase64エンコード値が見つかりました。 +invalidJsonJwtExceptionMessage = JWTに無効なJSON値が見つかりました。 +unsupportedFunctionInServerlessContextExceptionMessage = サーバーレスコンテキストではサポートされていない関数です: {0} +invalidPathWildcardOrDirectoryExceptionMessage = 指定されたパスはワイルドカードまたはディレクトリにすることはできません: {0} +invalidExceptionTypeExceptionMessage = 例外が無効な型です。WebExceptionまたはHttpRequestExceptionのいずれかである必要がありますが、次の型を取得しました: {0} +pathToLoadNotFoundExceptionMessage = 読み込むパス{0}が見つかりません: {1} +singleValueForIntervalExceptionMessage = インターバルを使用する場合、単一の{0}値しか指定できません。 +scriptErrorExceptionMessage = スクリプト{1} {2}(行{3})のエラー'{0}'(文字{4})が{6}オブジェクト'{7}'の{5}を実行中に発生しました クラス: {8} 基底クラス: {9} +noScriptBlockSuppliedExceptionMessage = ScriptBlockが提供されていません。 +iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKENがありません。 +invalidContentTypeForSchemaExceptionMessage = スキーマに対して無効なコンテンツタイプが見つかりました: {0} +propertiesParameterWithoutNameExceptionMessage = プロパティに名前がない場合、プロパティパラメータは使用できません。 +multiTypePropertiesRequireOpenApi31ExceptionMessage = 複数タイプのプロパティはOpenApiバージョン3.1以上が必要です。 +openApiVersionPropertyMandatoryExceptionMessage = OpenApiバージョンプロパティは必須です。 +webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = Webhooks機能はOpenAPI v3.0.xではサポートされていません。 +authenticationMethodDoesNotExistExceptionMessage = 認証方法が存在しません: {0} +unsupportedObjectExceptionMessage = サポートされていないオブジェクトです。 +validationOfAnyOfSchemaNotSupportedExceptionMessage = 'anyof'を含むスキーマの検証はサポートされていません。 +validationOfOneOfSchemaNotSupportedExceptionMessage = 'oneof'を含むスキーマの検証はサポートされていません。 +cannotCreatePropertyWithoutTypeExceptionMessage = 型が定義されていないため、プロパティを作成できません。 +paramsNoAdditionalPropertiesExclusiveExceptionMessage = パラメータ -NoAdditionalPropertiesと-AdditionalPropertiesは相互に排他です。 +headerMustHaveNameInEncodingContextExceptionMessage = エンコーディングコンテキストで使用される場合、ヘッダーには名前が必要です。 +descriptionRequiredExceptionMessage = 説明が必要です。 +openApiDocumentNotCompliantExceptionMessage = OpenAPIドキュメントが準拠していません。 +noComponentInDefinitionExceptionMessage = {2}定義に{0}タイプの名前{1}コンポーネントが利用できません。 +methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: 既に定義されています。 +methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: {2}用に既に定義されています。 +invalidMiddlewareTypeExceptionMessage = 提供されたMiddlewaresの1つが無効な型です。ScriptBlockまたはHashtableのいずれかを期待しましたが、次を取得しました: {0} +hashtableMiddlewareNoLogicExceptionMessage = 提供されたHashtableミドルウェアにロジックが定義されていません。 +invalidLogicTypeInHashtableMiddlewareExceptionMessage = 提供されたHashtableミドルウェアに無効なロジック型があります。ScriptBlockを期待しましたが、次を取得しました: {0} +scopedVariableAlreadyDefinedExceptionMessage = スコープ付き変数が既に定義されています: {0} +valueForUsingVariableNotFoundExceptionMessage = `$using:{0}`の値が見つかりませんでした。 +unlockSecretRequiredExceptionMessage = Microsoft.PowerShell.SecretStoreを使用する場合、'UnlockSecret'プロパティが必要です。 +unlockSecretButNoScriptBlockExceptionMessage = カスタムシークレットボールトタイプに対してアンロックシークレットが提供されましたが、アンロックスクリプトブロックが提供されていません。 +noUnlockScriptBlockForVaultExceptionMessage = ボールト'{0}'のロック解除に必要なスクリプトブロックが提供されていません。 +noSetScriptBlockForVaultExceptionMessage = ボールト'{0}'のシークレットを更新/作成するためのスクリプトブロックが提供されていません。 +noRemoveScriptBlockForVaultExceptionMessage = ボールト'{0}'のシークレットを削除するためのスクリプトブロックが提供されていません。 +invalidSecretValueTypeExceptionMessage = シークレットの値が無効な型です。期待される型: String、SecureString、HashTable、Byte[]、またはPSCredential。しかし、次を取得しました: {0} +limitValueCannotBeZeroOrLessExceptionMessage = {0}の制限値は0またはそれ以下にすることはできません。 +secondsValueCannotBeZeroOrLessExceptionMessage = {0}の秒数値は0またはそれ以下にすることはできません。 +failedToCreateOpenSslCertExceptionMessage = OpenSSL証明書の作成に失敗しました: {0} +certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Certificate Thumbprints/NameはWindowsでのみサポートされています。 +noCertificateFoundExceptionMessage = '{2}'用の{0}\{1}に証明書が見つかりませんでした。 +runspacePoolFailedToLoadExceptionMessage = {0} RunspacePoolの読み込みに失敗しました。 +noServiceHandlersDefinedExceptionMessage = サービスハンドラが定義されていません。 +noSessionToSetOnResponseExceptionMessage = レスポンスに設定するセッションがありません。 +noSessionToCalculateDataHashExceptionMessage = データハッシュを計算するセッションがありません。 +moduleOrVersionNotFoundExceptionMessage = {0}でモジュールまたはバージョンが見つかりません: {1}@{2} +noSmtpHandlersDefinedExceptionMessage = SMTPハンドラが定義されていません。 +taskTimedOutExceptionMessage = タスクが{0}ミリ秒後にタイムアウトしました。 +verbAlreadyDefinedExceptionMessage = [動詞] {0}: すでに定義されています +verbAlreadyDefinedForUrlExceptionMessage = [動詞] {0}: {1}にすでに定義されています +pathOrScriptBlockRequiredExceptionMessage = カスタムアクセス値のソース化には、パスまたはスクリプトブロックが必要です。 +accessMethodAlreadyDefinedExceptionMessage = アクセス方法はすでに定義されています: {0} +accessMethodNotExistForMergingExceptionMessage = マージするアクセス方法が存在しません: {0} +routeAlreadyContainsCustomAccessExceptionMessage = ルート '[{0}] {1}' はすでに名前 '{2}' のカスタムアクセスを含んでいます +accessMethodNotExistExceptionMessage = アクセス方法が存在しません: {0} +pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = PathItems機能はOpenAPI v3.0.xではサポートされていません。 '@ \ No newline at end of file diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 new file mode 100644 index 000000000..3cb6a8034 --- /dev/null +++ b/src/Locales/pl/Pode.psd1 @@ -0,0 +1,88 @@ +ConvertFrom-StringData -StringData @' +adModuleWindowsOnlyExceptionMessage = Moduł Active Directory jest dostępny tylko w systemie Windows. +adModuleNotInstalledExceptionMessage = Moduł Active Directory nie jest zainstalowany. +secretManagementModuleNotInstalledExceptionMessage = Moduł Microsoft.PowerShell.SecretManagement nie jest zainstalowany. +secretVaultAlreadyRegisteredExceptionMessage = Skarbiec z nazwą '{0}' został już zarejestrowany podczas automatycznego importowania skarbców. +failedToOpenRunspacePoolExceptionMessage = Nie udało się otworzyć RunspacePool: {0} +cronExpressionInvalidExceptionMessage = Wyrażenie Cron powinno składać się tylko z 5 części: {0} +invalidAliasFoundExceptionMessage = Znaleziono nieprawidłowy alias {0}: {1} +invalidAtomCharacterExceptionMessage = Nieprawidłowy znak atomu: {0} +minValueGreaterThanMaxExceptionMessage = Minimalna wartość dla {0} nie powinna być większa od maksymalnej wartości. +minValueInvalidExceptionMessage = Minimalna wartość '{0}' dla {1} jest nieprawidłowa, powinna być większa lub równa {2} +maxValueInvalidExceptionMessage = Maksymalna wartość '{0}' dla {1} jest nieprawidłowa, powinna być mniejsza lub równa {2} +valueOutOfRangeExceptionMessage = Wartość '{0}' dla {1} jest nieprawidłowa, powinna być pomiędzy {2} a {3} +daysInMonthExceededExceptionMessage = {0} ma tylko {1} dni, ale podano {2}. +nextTriggerCalculationErrorExceptionMessage = Wygląda na to, że coś poszło nie tak przy próbie obliczenia następnej daty i godziny wyzwalacza: {0} +incompatiblePodeDllExceptionMessage = Istnieje niekompatybilna wersja Pode.DLL {0}. Wymagana wersja {1}. Otwórz nową sesję Powershell/pwsh i spróbuj ponownie. +endpointNotExistExceptionMessage = Punkt końcowy z protokołem '{0}' i adresem '{1}' lub adresem lokalnym '{2}' nie istnieje. +endpointNameNotExistExceptionMessage = Punkt końcowy o nazwie '{0}' nie istnieje. +failedToConnectToUrlExceptionMessage = Nie udało się połączyć z URL: {0} +failedToParseAddressExceptionMessage = Nie udało się przeanalizować '{0}' jako poprawnego adresu IP/Host:Port +invalidIpAddressExceptionMessage = Podany adres IP jest nieprawidłowy: {0} +invalidPortExceptionMessage = Port nie może być ujemny: {0} +pathNotExistExceptionMessage = Ścieżka nie istnieje: {0} +noSecretForHmac256ExceptionMessage = Nie podano tajemnicy dla haszowania HMAC256. +noSecretForHmac384ExceptionMessage = Nie podano tajemnicy dla haszowania HMAC384. +noSecretForHmac512ExceptionMessage = Nie podano tajemnicy dla haszowania HMAC512. +noSecretForJwtSignatureExceptionMessage = Nie podano tajemnicy dla podpisu JWT. +noSecretExpectedForNoSignatureExceptionMessage = Nie oczekiwano podania tajemnicy dla braku podpisu. +unsupportedJwtAlgorithmExceptionMessage = Algorytm JWT nie jest obecnie obsługiwany: {0} +invalidBase64JwtExceptionMessage = Nieprawidłowa wartość zakodowana w Base64 znaleziona w JWT +invalidJsonJwtExceptionMessage = Nieprawidłowa wartość JSON znaleziona w JWT +unsupportedFunctionInServerlessContextExceptionMessage = Funkcja {0} nie jest obsługiwana w kontekście bezserwerowym. +invalidPathWildcardOrDirectoryExceptionMessage = Podana ścieżka nie może być symbolem wieloznacznym ani katalogiem: {0} +invalidExceptionTypeExceptionMessage = Wyjątek jest nieprawidłowego typu, powinien być WebException lub HttpRequestException, ale otrzymano: {0} +pathToLoadNotFoundExceptionMessage = Ścieżka do załadowania {0} nie znaleziona: {1} +singleValueForIntervalExceptionMessage = Możesz podać tylko jedną wartość {0} podczas korzystania z interwałów. +scriptErrorExceptionMessage = Błąd '{0}' w skrypcie {1} {2} (linia {3}) znak {4} podczas wykonywania {5} na {6} obiekt '{7}' Klasa: {8} Klasa bazowa: {9} +noScriptBlockSuppliedExceptionMessage = Nie podano ScriptBlock. +iisAspnetcoreTokenMissingExceptionMessage = Brakujący IIS ASPNETCORE_TOKEN. +invalidContentTypeForSchemaExceptionMessage = Znaleziono nieprawidłowy typ zawartości dla schematu: {0} +propertiesParameterWithoutNameExceptionMessage = Parametry Properties nie mogą być używane, jeśli właściwość nie ma nazwy. +multiTypePropertiesRequireOpenApi31ExceptionMessage = Właściwości wielotypowe wymagają wersji OpenApi 3.1 lub wyższej. +openApiVersionPropertyMandatoryExceptionMessage = Właściwość wersji OpenApi jest obowiązkowa. +webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = Funkcja Webhooks nie jest obsługiwana w OpenAPI v3.0.x +pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = Funkcja PathItems nie jest obsługiwana w OpenAPI v3.0.x +authenticationMethodDoesNotExistExceptionMessage = Metoda uwierzytelniania nie istnieje: {0} +unsupportedObjectExceptionMessage = Obiekt nieobsługiwany +validationOfAnyOfSchemaNotSupportedExceptionMessage = Walidacja schematu, który zawiera 'anyof', nie jest obsługiwana. +validationOfOneOfSchemaNotSupportedExceptionMessage = Walidacja schematu, który zawiera 'oneof', nie jest obsługiwana. +cannotCreatePropertyWithoutTypeExceptionMessage = Nie można utworzyć właściwości, ponieważ nie zdefiniowano typu. +paramsNoAdditionalPropertiesExclusiveExceptionMessage = Parametry -NoAdditionalProperties i -AdditionalProperties wykluczają się wzajemnie. +headerMustHaveNameInEncodingContextExceptionMessage = Nagłówek musi mieć nazwę, gdy jest używany w kontekście kodowania. +descriptionRequiredExceptionMessage = Wymagany jest opis. +openApiDocumentNotCompliantExceptionMessage = Dokument OpenAPI nie jest zgodny. +noComponentInDefinitionExceptionMessage = Brak komponentu typu {0} o nazwie {1} dostępnego w definicji {2}. +methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: Już zdefiniowane. +methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: Już zdefiniowane dla {2} +invalidMiddlewareTypeExceptionMessage = Jeden z dostarczonych Middleware jest nieprawidłowego typu. Oczekiwano ScriptBlock lub Hashtable, ale otrzymano: {0} +hashtableMiddlewareNoLogicExceptionMessage = Dostarczone Middleware typu Hashtable nie ma zdefiniowanej logiki. +invalidLogicTypeInHashtableMiddlewareExceptionMessage = Dostarczone Middleware typu Hashtable ma nieprawidłowy typ logiki. Oczekiwano ScriptBlock, ale otrzymano: {0} +scopedVariableAlreadyDefinedExceptionMessage = Zmienna z zakresem już zdefiniowana: {0} +valueForUsingVariableNotFoundExceptionMessage = Nie można znaleźć wartości dla `$using:{0}`. +unlockSecretRequiredExceptionMessage = Właściwość 'UnlockSecret' jest wymagana przy używaniu Microsoft.PowerShell.SecretStore +unlockSecretButNoScriptBlockExceptionMessage = Podano tajemnicę odblokowania dla niestandardowego typu skarbca, ale nie podano ScriptBlock odblokowania. +noUnlockScriptBlockForVaultExceptionMessage = Nie podano ScriptBlock odblokowania dla odblokowania skarbca '{0}' +noSetScriptBlockForVaultExceptionMessage = Nie podano ScriptBlock dla aktualizacji/tworzenia tajemnic w skarbcu '{0}' +noRemoveScriptBlockForVaultExceptionMessage = Nie podano ScriptBlock dla usuwania tajemnic ze skarbca '{0}' +invalidSecretValueTypeExceptionMessage = Wartość tajemnicy jest nieprawidłowego typu. Oczekiwane typy: String, SecureString, HashTable, Byte[] lub PSCredential. Ale otrzymano: {0} +limitValueCannotBeZeroOrLessExceptionMessage = Wartość limitu nie może być 0 lub mniejsza dla {0} +secondsValueCannotBeZeroOrLessExceptionMessage = Wartość sekund nie może być 0 lub mniejsza dla {0} +failedToCreateOpenSslCertExceptionMessage = Nie udało się utworzyć certyfikatu openssl: {0} +certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Odciski palców/nazwa certyfikatu są obsługiwane tylko w systemie Windows. +noCertificateFoundExceptionMessage = Nie znaleziono certyfikatu w {0}\{1} dla '{2}' +runspacePoolFailedToLoadExceptionMessage = {0} Nie udało się załadować RunspacePool. +noServiceHandlersDefinedExceptionMessage = Nie zdefiniowano żadnych obsługujących usług. +noSessionToSetOnResponseExceptionMessage = Brak dostępnej sesji do ustawienia odpowiedzi. +noSessionToCalculateDataHashExceptionMessage = Brak dostępnej sesji do obliczenia skrótu danych. +moduleOrVersionNotFoundExceptionMessage = Nie znaleziono modułu lub wersji na {0}: {1}@{2} +noSmtpHandlersDefinedExceptionMessage = Nie zdefiniowano żadnych obsługujących SMTP. +taskTimedOutExceptionMessage = Zadanie przekroczyło limit czasu po {0}ms. +verbAlreadyDefinedExceptionMessage = [Czasownik] {0}: Już zdefiniowane +verbAlreadyDefinedForUrlExceptionMessage = [Czasownik] {0}: Już zdefiniowane dla {1} +pathOrScriptBlockRequiredExceptionMessage = Ścieżka lub ScriptBlock są wymagane do pozyskiwania wartości dostępu niestandardowego. +accessMethodAlreadyDefinedExceptionMessage = Metoda dostępu już zdefiniowana: {0} +accessMethodNotExistForMergingExceptionMessage = Metoda dostępu nie istnieje do scalania: {0} +routeAlreadyContainsCustomAccessExceptionMessage = Trasa '[{0}] {1}' już zawiera dostęp niestandardowy z nazwą '{2}' +accessMethodNotExistExceptionMessage = Metoda dostępu nie istnieje: {0} +'@ diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 new file mode 100644 index 000000000..02866c758 --- /dev/null +++ b/src/Locales/pt/Pode.psd1 @@ -0,0 +1,88 @@ +ConvertFrom-StringData -StringData @' +adModuleWindowsOnlyExceptionMessage = O módulo Active Directory está disponível apenas no Windows. +adModuleNotInstalledExceptionMessage = O módulo Active Directory não está instalado. +secretManagementModuleNotInstalledExceptionMessage = O módulo Microsoft.PowerShell.SecretManagement não está instalado. +secretVaultAlreadyRegisteredExceptionMessage = Um Cofre de Segredos com o nome '{0}' já foi registrado durante a importação automática de Cofres de Segredos. +failedToOpenRunspacePoolExceptionMessage = Falha ao abrir o RunspacePool: {0} +cronExpressionInvalidExceptionMessage = A expressão Cron deve consistir apenas em 5 partes: {0} +invalidAliasFoundExceptionMessage = Alias {0} inválido encontrado: {1} +invalidAtomCharacterExceptionMessage = Caractere atômico inválido: {0} +minValueGreaterThanMaxExceptionMessage = O valor mínimo para {0} não deve ser maior que o valor máximo. +minValueInvalidExceptionMessage = O valor mínimo '{0}' para {1} é inválido, deve ser maior ou igual a {2} +maxValueInvalidExceptionMessage = O valor máximo '{0}' para {1} é inválido, deve ser menor ou igual a {2} +valueOutOfRangeExceptionMessage = O valor '{0}' para {1} é inválido, deve estar entre {2} e {3} +daysInMonthExceededExceptionMessage = {0} tem apenas {1} dias, mas {2} foi fornecido. +nextTriggerCalculationErrorExceptionMessage = Parece que algo deu errado ao tentar calcular a próxima data e hora do gatilho: {0} +incompatiblePodeDllExceptionMessage = Uma versão incompatível existente do Pode.DLL {0} está carregada. É necessária a versão {1}. Abra uma nova sessão do Powershell/pwsh e tente novamente. +endpointNotExistExceptionMessage = O ponto de extremidade com o protocolo '{0}' e endereço '{1}' ou endereço local '{2}' não existe. +endpointNameNotExistExceptionMessage = O ponto de extremidade com o nome '{0}' não existe. +failedToConnectToUrlExceptionMessage = Falha ao conectar ao URL: {0} +failedToParseAddressExceptionMessage = Falha ao analisar '{0}' como um endereço IP/Host:Port válido +invalidIpAddressExceptionMessage = O endereço IP fornecido é inválido: {0} +invalidPortExceptionMessage = A porta não pode ser negativa: {0} +pathNotExistExceptionMessage = O caminho não existe: {0} +noSecretForHmac256ExceptionMessage = Nenhum segredo fornecido para o hash HMAC256. +noSecretForHmac384ExceptionMessage = Nenhum segredo fornecido para o hash HMAC384. +noSecretForHmac512ExceptionMessage = Nenhum segredo fornecido para o hash HMAC512. +noSecretForJwtSignatureExceptionMessage = Nenhum segredo fornecido para a assinatura JWT. +noSecretExpectedForNoSignatureExceptionMessage = Não era esperado nenhum segredo para nenhuma assinatura. +unsupportedJwtAlgorithmExceptionMessage = O algoritmo JWT não é atualmente suportado: {0} +invalidBase64JwtExceptionMessage = Valor codificado Base64 inválido encontrado no JWT +invalidJsonJwtExceptionMessage = Valor JSON inválido encontrado no JWT +unsupportedFunctionInServerlessContextExceptionMessage = A função {0} não é suportada em um contexto serverless. +invalidPathWildcardOrDirectoryExceptionMessage = O caminho fornecido não pode ser um curinga ou um diretório: {0} +invalidExceptionTypeExceptionMessage = A exceção é de um tipo inválido, deve ser WebException ou HttpRequestException, mas foi obtido: {0} +pathToLoadNotFoundExceptionMessage = Caminho para carregar {0} não encontrado: {1} +singleValueForIntervalExceptionMessage = Você pode fornecer apenas um único valor {0} ao usar intervalos. +scriptErrorExceptionMessage = Erro '{0}' no script {1} {2} (linha {3}) caractere {4} executando {5} em {6} objeto '{7}' Classe: {8} ClasseBase: {9} +noScriptBlockSuppliedExceptionMessage = Nenhum ScriptBlock fornecido. +iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN está ausente. +invalidContentTypeForSchemaExceptionMessage = Tipo de conteúdo inválido encontrado para o esquema: {0} +propertiesParameterWithoutNameExceptionMessage = Os parâmetros Properties não podem ser usados se a propriedade não tiver um nome. +multiTypePropertiesRequireOpenApi31ExceptionMessage = Propriedades de múltiplos tipos requerem a versão 3.1 ou superior do OpenApi. +openApiVersionPropertyMandatoryExceptionMessage = A propriedade da versão do OpenApi é obrigatória. +webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = O recurso Webhooks não é suportado no OpenAPI v3.0.x +pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = O recurso PathItems não é suportado no OpenAPI v3.0.x +authenticationMethodDoesNotExistExceptionMessage = O método de autenticação não existe: {0} +unsupportedObjectExceptionMessage = Objeto não suportado +validationOfAnyOfSchemaNotSupportedExceptionMessage = A validação de um esquema que inclui 'anyof' não é suportada. +validationOfOneOfSchemaNotSupportedExceptionMessage = A validação de um esquema que inclui 'oneof' não é suportada. +cannotCreatePropertyWithoutTypeExceptionMessage = Não é possível criar a propriedade porque nenhum tipo é definido. +paramsNoAdditionalPropertiesExclusiveExceptionMessage = Os parâmetros -NoAdditionalProperties e -AdditionalProperties se excluem mutuamente. +headerMustHaveNameInEncodingContextExceptionMessage = O cabeçalho deve ter um nome quando usado em um contexto de codificação. +descriptionRequiredExceptionMessage = É necessária uma descrição. +openApiDocumentNotCompliantExceptionMessage = O documento OpenAPI não está em conformidade. +noComponentInDefinitionExceptionMessage = Nenhum componente do tipo {0} chamado {1} está disponível na definição {2}. +methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: Já definido. +methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: Já definido para {2} +invalidMiddlewareTypeExceptionMessage = Um dos Middlewares fornecidos é de um tipo inválido. Esperado ScriptBlock ou Hashtable, mas obtido: {0} +hashtableMiddlewareNoLogicExceptionMessage = Um Middleware do tipo Hashtable fornecido não tem lógica definida. +invalidLogicTypeInHashtableMiddlewareExceptionMessage = Um Middleware do tipo Hashtable fornecido tem um tipo de lógica inválido. Esperado ScriptBlock, mas obtido: {0} +scopedVariableAlreadyDefinedExceptionMessage = Variável de escopo já definida: {0} +valueForUsingVariableNotFoundExceptionMessage = Valor para `$using:{0}` não pôde ser encontrado. +unlockSecretRequiredExceptionMessage = É necessária uma propriedade 'UnlockSecret' ao usar Microsoft.PowerShell.SecretStore +unlockSecretButNoScriptBlockExceptionMessage = Segredo de desbloqueio fornecido para tipo de Cofre Secreto personalizado, mas nenhum ScriptBlock de desbloqueio fornecido. +noUnlockScriptBlockForVaultExceptionMessage = Nenhum ScriptBlock de desbloqueio fornecido para desbloquear o cofre '{0}' +noSetScriptBlockForVaultExceptionMessage = Nenhum ScriptBlock fornecido para atualizar/criar segredos no cofre '{0}' +noRemoveScriptBlockForVaultExceptionMessage = Nenhum ScriptBlock fornecido para remover segredos do cofre '{0}' +invalidSecretValueTypeExceptionMessage = O valor do segredo é de um tipo inválido. Tipos esperados: String, SecureString, HashTable, Byte[] ou PSCredential. Mas obtido: {0} +limitValueCannotBeZeroOrLessExceptionMessage = O valor limite não pode ser 0 ou inferior para {0} +secondsValueCannotBeZeroOrLessExceptionMessage = O valor dos segundos não pode ser 0 ou inferior para {0} +failedToCreateOpenSslCertExceptionMessage = Falha ao criar o certificado openssl: {0} +certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Impressões digitais/nome do certificado são suportados apenas no Windows. +noCertificateFoundExceptionMessage = Nenhum certificado encontrado em {0}\{1} para '{2}' +runspacePoolFailedToLoadExceptionMessage = {0} Falha ao carregar RunspacePool. +noServiceHandlersDefinedExceptionMessage = Nenhum manipulador de serviço definido. +noSessionToSetOnResponseExceptionMessage = Não há sessão disponível para definir na resposta. +noSessionToCalculateDataHashExceptionMessage = Nenhuma sessão disponível para calcular o hash dos dados. +moduleOrVersionNotFoundExceptionMessage = Módulo ou versão não encontrada em {0}: {1}@{2} +noSmtpHandlersDefinedExceptionMessage = Nenhum manipulador SMTP definido. +taskTimedOutExceptionMessage = A tarefa expirou após {0}ms. +verbAlreadyDefinedExceptionMessage = [Verbo] {0}: Já definido +verbAlreadyDefinedForUrlExceptionMessage = [Verbo] {0}: Já definido para {1} +pathOrScriptBlockRequiredExceptionMessage = É necessário um Caminho ou ScriptBlock para obter os valores de acesso personalizados. +accessMethodAlreadyDefinedExceptionMessage = Método de acesso já definido: {0} +accessMethodNotExistForMergingExceptionMessage = O método de acesso não existe para a mesclagem: {0} +routeAlreadyContainsCustomAccessExceptionMessage = A rota '[{0}] {1}' já contém Acesso Personalizado com o nome '{2}' +accessMethodNotExistExceptionMessage = O método de acesso não existe: {0} +'@ diff --git a/src/Locales/zn/Pode.psd1 b/src/Locales/zn/Pode.psd1 index 0e0c8729b..c6ebfb915 100644 --- a/src/Locales/zn/Pode.psd1 +++ b/src/Locales/zn/Pode.psd1 @@ -1,24 +1,88 @@ ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyMessage = Active Directory模块仅在Windows上可用 -adModuleNotInstalledMessage = Active Directory模块未安装 -secretManagementModuleNotInstalledMessage = Microsoft.PowerShell.SecretManagement模块未安装 -secretVaultAlreadyRegisteredMessage = 在自动导入秘密库时,名为'{0}'的秘密库已注册 -failedToOpenRunspacePoolMessage = 无法打开RunspacePool: {0} -cronExpressionInvalidMessage = Cron表达式应仅由5部分组成: {0} -invalidAliasFoundMessage = 找到无效的{0}别名:{1} -invalidAtomCharacterMessage = 无效的原子字符:{0} -minValueGreaterThanMaxMessage = {0}的最小值不应大于最大值 -minValueInvalidMessage = {1}的最小值'{0}'无效,应大于或等于{2} -maxValueInvalidMessage = {1}的最大值'{0}'无效,应小于或等于{2} -valueOutOfRangeMessage = {1}的值'{0}'无效,应介于{2}和{3}之间 -daysInMonthExceededMessage = {0}只有{1}天,但提供了{2} -nextTriggerCalculationErrorMessage = 计算下一个触发日期时间时似乎出了问题:{0} -incompatiblePodeDllMessage = 已加载现有的不兼容Pode.DLL版本{0}。需要版本{1}。请打开一个新的Powershell/pwsh会话并重试。 -endpointNotExistMessage = 协议为'{0}'且地址为'{1}'或本地地址为'{2}'的端点不存在 -endpointNameNotExistMessage = 名称为'{0}'的端点不存在 -failedToConnectToUrlMessage = 无法连接到URL: {0} -failedToParseAddressMessage = 无法将'{0}'解析为有效的IP/主机:端口地址 -invalidIpAddressMessage = 提供的IP地址无效:{0} -invalidPortMessage = 端口不能为负:{0} -pathNotExistMessage = 路径不存在:{0} +adModuleWindowsOnlyExceptionMessage = 仅支持 Windows 的 Active Directory 模块。 +adModuleNotInstalledExceptionMessage = 未安装 Active Directory 模块。 +secretManagementModuleNotInstalledExceptionMessage = 未安装 Microsoft.PowerShell.SecretManagement 模块。 +secretVaultAlreadyRegisteredExceptionMessage = 已经注册了名称为 '{0}' 的秘密保险库,同时正在自动导入秘密保险库。 +failedToOpenRunspacePoolExceptionMessage = 打开 RunspacePool 失败: {0} +cronExpressionInvalidExceptionMessage = Cron 表达式应仅包含 5 个部分: {0} +invalidAliasFoundExceptionMessage = 找到了无效的 {0} 别名: {1} +invalidAtomCharacterExceptionMessage = 无效的原子字符: {0} +minValueGreaterThanMaxExceptionMessage = {0} 的最小值不应大于最大值。 +minValueInvalidExceptionMessage = {1} 的最小值 '{0}' 无效,应大于或等于 {2} +maxValueInvalidExceptionMessage = {1} 的最大值 '{0}' 无效,应小于或等于 {2} +valueOutOfRangeExceptionMessage = {1} 的值 '{0}' 无效,应在 {2} 和 {3} 之间 +daysInMonthExceededExceptionMessage = {0} 仅有 {1} 天,但提供了 {2} 天。 +nextTriggerCalculationErrorExceptionMessage = 似乎在尝试计算下一个触发器日期时间时出现了问题: {0} +incompatiblePodeDllExceptionMessage = 已加载存在不兼容的 Pode.DLL 版本 {0}。需要版本 {1}。请打开新的 Powershell/pwsh 会话并重试。 +endpointNotExistExceptionMessage = 具有协议 '{0}' 和地址 '{1}' 或本地地址 '{2}' 的端点不存在。 +endpointNameNotExistExceptionMessage = 名为 '{0}' 的端点不存在。 +failedToConnectToUrlExceptionMessage = 连接到 URL 失败: {0} +failedToParseAddressExceptionMessage = 无法将 '{0}' 解析为有效的 IP/主机:端口地址 +invalidIpAddressExceptionMessage = 提供的 IP 地址无效: {0} +invalidPortExceptionMessage = 端口不能为负数: {0} +pathNotExistExceptionMessage = 路径不存在: {0} +noSecretForHmac256ExceptionMessage = 未提供 HMAC256 哈希的密钥。 +noSecretForHmac384ExceptionMessage = 未提供 HMAC384 哈希的密钥。 +noSecretForHmac512ExceptionMessage = 未提供 HMAC512 哈希的密钥。 +noSecretForJwtSignatureExceptionMessage = 未提供 JWT 签名的密钥。 +noSecretExpectedForNoSignatureExceptionMessage = 预期未提供签名的密钥。 +unsupportedJwtAlgorithmExceptionMessage = 当前不支持的 JWT 算法: {0} +invalidBase64JwtExceptionMessage = 在 JWT 中找到无效的 Base64 编码值 +invalidJsonJwtExceptionMessage = 在 JWT 中找到无效的 JSON 值 +unsupportedFunctionInServerlessContextExceptionMessage = 不支持在无服务器上下文中使用 {0} 函数。 +invalidPathWildcardOrDirectoryExceptionMessage = 提供的路径不能是通配符或目录: {0} +invalidExceptionTypeExceptionMessage = 异常类型无效,应为 WebException 或 HttpRequestException,但得到了: {0} +pathToLoadNotFoundExceptionMessage = 未找到要加载的路径 {0}: {1} +singleValueForIntervalExceptionMessage = 当使用间隔时,只能提供单个 {0} 值。 +scriptErrorExceptionMessage = 脚本 '{0}' 在 {1} {2} (第 {3} 行) 第 {4} 个字符处执行 {5} 对象 '{7}' 的错误。类: {8} 基类: {9} +noScriptBlockSuppliedExceptionMessage = 未提供脚本块。 +iisAspnetcoreTokenMissingExceptionMessage = 缺少 IIS ASPNETCORE_TOKEN。 +invalidContentTypeForSchemaExceptionMessage = 为模式找到的内容类型无效: {0} +propertiesParameterWithoutNameExceptionMessage = 如果属性没有名称,则不能使用 Properties 参数。 +multiTypePropertiesRequireOpenApi31ExceptionMessage = 多类型属性需要 OpenApi 版本 3.1 或更高版本。 +openApiVersionPropertyMandatoryExceptionMessage = OpenApi 版本属性是必需的。 +webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = 在 OpenAPI v3.0.x 中不支持 Webhooks 功能 +authenticationMethodDoesNotExistExceptionMessage = 认证方法不存在: {0} +unsupportedObjectExceptionMessage = 不支持的对象 +validationOfAnyOfSchemaNotSupportedExceptionMessage = 不支持包含 'anyof' 的模式的验证。 +validationOfOneOfSchemaNotSupportedExceptionMessage = 不支持包含 'oneof' 的模式的验证。 +cannotCreatePropertyWithoutTypeExceptionMessage = 无法创建属性,因为未定义类型。 +paramsNoAdditionalPropertiesExclusiveExceptionMessage = Params -NoAdditionalProperties 和 -AdditionalProperties 互斥。 +headerMustHaveNameInEncodingContextExceptionMessage = 在编码上下文中使用时,标头必须有名称。 +descriptionRequiredExceptionMessage = 描述是必需的。 +openApiDocumentNotCompliantExceptionMessage = OpenAPI 文档不符合规范。 +noComponentInDefinitionExceptionMessage = 定义中没有类型为 {0} 名称为 {1} 的组件。 +methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: 已经定义。 +methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: 已经为 {2} 定义。 +invalidMiddlewareTypeExceptionMessage = 提供的中间件之一是无效的类型。期望是 ScriptBlock 或 Hashtable,但得到了: {0} +hashtableMiddlewareNoLogicExceptionMessage = 提供的 Hashtable 中间件没有定义逻辑。 +invalidLogicTypeInHashtableMiddlewareExceptionMessage = 提供的 Hashtable 中间件具有无效的逻辑类型。期望是 ScriptBlock,但得到了: {0} +scopedVariableAlreadyDefinedExceptionMessage = 已经定义了作用域变量: {0} +valueForUsingVariableNotFoundExceptionMessage = 未找到 `$using:{0}` 的值。 +unlockSecretRequiredExceptionMessage = 使用 Microsoft.PowerShell.SecretStore 时需要 'UnlockSecret' 属性。 +unlockSecretButNoScriptBlockExceptionMessage = 为自定义秘密保险库类型提供了解锁密钥,但未提供解锁 ScriptBlock。 +noUnlockScriptBlockForVaultExceptionMessage = 未为解锁保险库 '{0}' 提供解锁 ScriptBlock。 +noSetScriptBlockForVaultExceptionMessage = 未为更新/创建保险库 '{0}' 中的秘密提供设置 ScriptBlock。 +noRemoveScriptBlockForVaultExceptionMessage = 未为从保险库 '{0}' 中删除秘密提供删除 ScriptBlock。 +invalidSecretValueTypeExceptionMessage = 密钥值是无效的类型。期望类型: 字符串、SecureString、HashTable、Byte[] 或 PSCredential。但得到了: {0} +limitValueCannotBeZeroOrLessExceptionMessage = {0} 的限制值不能为 0 或更小。 +secondsValueCannotBeZeroOrLessExceptionMessage = {0} 的秒数值不能为 0 或更小。 +failedToCreateOpenSslCertExceptionMessage = 创建 openssl 证书失败: {0} +certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 证书指纹/名称仅在 Windows 上受支持。 +noCertificateFoundExceptionMessage = 在 {0}\{1} 中找不到证书 '{2}'。 +runspacePoolFailedToLoadExceptionMessage = {0} RunspacePool 加载失败。 +noServiceHandlersDefinedExceptionMessage = 未定义服务处理程序。 +noSessionToSetOnResponseExceptionMessage = 没有可用的会话来设置响应。 +noSessionToCalculateDataHashExceptionMessage = 没有可用的会话来计算数据哈希。 +moduleOrVersionNotFoundExceptionMessage = 在 {0} 上找不到模块或版本: {1}@{2} +noSmtpHandlersDefinedExceptionMessage = 未定义 SMTP 处理程序。 +taskTimedOutExceptionMessage = 任务在 {0} 毫秒后超时。 +verbAlreadyDefinedExceptionMessage = [Verb] {0}: 已经定义 +verbAlreadyDefinedForUrlExceptionMessage = [Verb] {0}: 已经为 {1} 定义 +pathOrScriptBlockRequiredExceptionMessage = 对于源自自定义访问值,需要路径或 ScriptBlock。 +accessMethodAlreadyDefinedExceptionMessage = 访问方法已经定义: {0} +accessMethodNotExistForMergingExceptionMessage = 合并时访问方法不存在: {0} +routeAlreadyContainsCustomAccessExceptionMessage = 路由 '[{0}] {1}' 已经包含名称为 '{2}' 的自定义访问。 +accessMethodNotExistExceptionMessage = 访问方法不存在: {0} +pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 在 OpenAPI v3.0.x 中不支持 PathItems 功能。 '@ \ No newline at end of file diff --git a/src/Pode.Internal.psd1 b/src/Pode.Internal.psd1 index 2384bc7ea..d8b1b475b 100644 --- a/src/Pode.Internal.psd1 +++ b/src/Pode.Internal.psd1 @@ -21,4 +21,5 @@ # Minimum version of the Windows PowerShell engine required by this module PowerShellVersion = '5.1' + } \ No newline at end of file diff --git a/src/Pode.psm1 b/src/Pode.psm1 index 32d555b03..72e91050b 100644 --- a/src/Pode.psm1 +++ b/src/Pode.psm1 @@ -1,8 +1,9 @@ +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')] +param() # root path $root = Split-Path -Parent -Path $MyInvocation.MyCommand.Path - # Import localized messages -Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $root -ChildPath 'Locales') +$global:msgTable = Import-LocalizedData -BaseDirectory (Join-Path -Path $root -ChildPath 'Locales') # load assemblies Add-Type -AssemblyName System.Web @@ -20,7 +21,7 @@ if ($podeDll) { if ( $moduleManifest.ModuleVersion -ne '$version$') { $moduleVersion = ([version]::new($moduleManifest.ModuleVersion + '.0')) if ($podeDll.GetName().Version -ne $moduleVersion) { - throw ($msgTable.incompatiblePodeDllMessage -f $podeDll.GetName().Version, $moduleVersion) #"An existing incompatible Pode.DLL version $($podeDll.GetName().Version) is loaded. Version $moduleVersion is required. Open a new Powershell/pwsh session and retry." + throw ($msgTable.incompatiblePodeDllExceptionMessage -f $podeDll.GetName().Version, $moduleVersion) #"An existing incompatible Pode.DLL version $($podeDll.GetName().Version) is loaded. Version $moduleVersion is required. Open a new Powershell/pwsh session and retry." } } } diff --git a/src/Private/Authentication.ps1 b/src/Private/Authentication.ps1 index 7bf7a6cdd..97a812b21 100644 --- a/src/Private/Authentication.ps1 +++ b/src/Private/Authentication.ps1 @@ -2194,11 +2194,11 @@ function Expand-PodeAuthMerge { function Import-PodeAuthADModule { if (!(Test-PodeIsWindows)) { - throw $msgTable.adModuleWindowsOnlyMessage #'Active Directory module only available on Windows' + throw $msgTable.adModuleWindowsOnlyExceptionMessage #'Active Directory module only available on Windows' } if (!(Test-PodeModuleInstalled -Name ActiveDirectory)) { - throw $msgTable.adModuleNotInstalledMessage #'Active Directory module is not installed' + throw $msgTable.adModuleNotInstalledExceptionMessage #'Active Directory module is not installed' } Import-Module -Name ActiveDirectory -Force -ErrorAction Stop diff --git a/src/Private/AutoImport.ps1 b/src/Private/AutoImport.ps1 index f196d577b..65f1f0b9e 100644 --- a/src/Private/AutoImport.ps1 +++ b/src/Private/AutoImport.ps1 @@ -177,7 +177,7 @@ function Import-PodeSecretManagementVaultsIntoRegistry { # error if SecretManagement module not installed if (!(Test-PodeModuleInstalled -Name Microsoft.PowerShell.SecretManagement)) { - throw $msgTable.secretManagementModuleNotInstalledMessage #'Microsoft.PowerShell.SecretManagement module not installed' + throw $msgTable.secretManagementModuleNotInstalledExceptionMessage #'Microsoft.PowerShell.SecretManagement module not installed' } # import the module @@ -195,7 +195,7 @@ function Import-PodeSecretManagementVaultsIntoRegistry { # is a vault with this name already registered? if (Test-PodeSecretVault -Name $vault.Name) { - throw ($msgTable.secretVaultAlreadyRegisteredMessage -f $vault.Name) #"A Secret Vault with the name '$($vault.Name)' has already been registered while auto-importing Secret Vaults" + throw ($msgTable.secretVaultAlreadyRegisteredExceptionMessage -f $vault.Name) #"A Secret Vault with the name '$($vault.Name)' has already been registered while auto-importing Secret Vaults" } # register the vault diff --git a/src/Private/Context.ps1 b/src/Private/Context.ps1 index 0472e3eed..b60e0629b 100644 --- a/src/Private/Context.ps1 +++ b/src/Private/Context.ps1 @@ -666,7 +666,7 @@ function Open-PodeRunspacePools { if ($item.Pool.RunspacePoolStateInfo.State -ieq 'broken') { $item.Pool.EndOpen($item.Result) | Out-Default - throw ($msgTable.failedToOpenRunspacePoolMessage -f $key) #"Failed to open RunspacePool: $($key)" + throw ($msgTable.failedToOpenRunspacePoolExceptionMessage -f $key) #"Failed to open RunspacePool: $($key)" } } @@ -722,7 +722,7 @@ function Close-PodeRunspacePools { if ($item.Pool.RunspacePoolStateInfo.State -ieq 'broken') { $item.Pool.EndClose($item.Result) | Out-Default - throw ($msgTable.failedToOpenRunspacePoolMessage -f $key) #"Failed to open RunspacePool: $($key)" + throw ($msgTable.failedToOpenRunspacePoolExceptionMessage -f $key) #"Failed to open RunspacePool: $($key)" } } diff --git a/src/Private/CronParser.ps1 b/src/Private/CronParser.ps1 index da231d4c5..d3358732a 100644 --- a/src/Private/CronParser.ps1 +++ b/src/Private/CronParser.ps1 @@ -109,7 +109,7 @@ function ConvertFrom-PodeCronExpression { # split and check atoms length $atoms = @($Expression -isplit '\s+') if ($atoms.Length -ne 5) { - throw ($msgTable.cronExpressionInvalidMessage -f $Expression) #"Cron expression should only consist of 5 parts: $($Expression)" + throw ($msgTable.cronExpressionInvalidExceptionMessage -f $Expression) #"Cron expression should only consist of 5 parts: $($Expression)" } # basic variables @@ -140,7 +140,7 @@ function ConvertFrom-PodeCronExpression { while ($_atom -imatch $aliasRgx) { $_alias = $_aliases[$Matches['tag']] if ($null -eq $_alias) { - throw ($msgTable.invalidAliasFoundMessage -f $_field, $Matches['tag']) #"Invalid $($_field) alias found: $($Matches['tag'])" + throw ($msgTable.invalidAliasFoundExceptionMessage -f $_field, $Matches['tag']) #"Invalid $($_field) alias found: $($Matches['tag'])" } $_atom = $_atom -ireplace $Matches['tag'], $_alias @@ -150,7 +150,7 @@ function ConvertFrom-PodeCronExpression { # ensure atom is a valid value if (!($_atom -imatch '^[\d|/|*|\-|,r]+$')) { - throw ($msgTable.invalidAtomCharacterMessage -f $_atom)#"Invalid atom character: $($_atom)" + throw ($msgTable.invalidAtomCharacterExceptionMessage -f $_atom)#"Invalid atom character: $($_atom)" } # replace * with min/max constraint @@ -214,28 +214,28 @@ function ConvertFrom-PodeCronExpression { # error else { - throw ($msgTable.invalidAtomCharacterMessage -f $_atom)#"Invalid cron atom format found: $($_atom)" + throw ($msgTable.invalidAtomCharacterExceptionMessage -f $_atom)#"Invalid cron atom format found: $($_atom)" } # ensure cron expression values are valid if ($null -ne $_cronExp.Range) { if ($_cronExp.Range.Min -gt $_cronExp.Range.Max) { - throw ($msgTable.minValueGreaterThanMaxMessage -f $_field) #"Min value for $($_field) should not be greater than the max value" + throw ($msgTable.minValueGreaterThanMaxExceptionMessage -f $_field) #"Min value for $($_field) should not be greater than the max value" } if ($_cronExp.Range.Min -lt $_constraint[0]) { - throw ($msgTable.minValueInvalidMessage -f $_cronExp.Range.Min, $_field, $_constraint[0]) #"Min value '$($_cronExp.Range.Min)' for $($_field) is invalid, should be greater than/equal to $($_constraint[0])" + throw ($msgTable.minValueInvalidExceptionMessage -f $_cronExp.Range.Min, $_field, $_constraint[0]) #"Min value '$($_cronExp.Range.Min)' for $($_field) is invalid, should be greater than/equal to $($_constraint[0])" } if ($_cronExp.Range.Max -gt $_constraint[1]) { - throw ($msgTable.maxValueInvalidMessage -f $_cronExp.Range.Max, $_field, $_constraint[1]) #"Max value '$($_cronExp.Range.Max)' for $($_field) is invalid, should be less than/equal to $($_constraint[1])" + throw ($msgTable.maxValueInvalidExceptionMessage -f $_cronExp.Range.Max, $_field, $_constraint[1]) #"Max value '$($_cronExp.Range.Max)' for $($_field) is invalid, should be less than/equal to $($_constraint[1])" } } if ($null -ne $_cronExp.Values) { $_cronExp.Values | ForEach-Object { if ($_ -lt $_constraint[0] -or $_ -gt $_constraint[1]) { - throw ($msgTable.valueOutOfRangeMessage -f $value, $_field, $_constraint[0], $_constraint[1]) #"Value '$($_)' for $($_field) is invalid, should be between $($_constraint[0]) and $($_constraint[1])" + throw ($msgTable.valueOutOfRangeExceptionMessage -f $value, $_field, $_constraint[0], $_constraint[1]) #"Value '$($_)' for $($_field) is invalid, should be between $($_constraint[0]) and $($_constraint[1])" } } } @@ -250,7 +250,7 @@ function ConvertFrom-PodeCronExpression { foreach ($mon in $cron['Month'].Values) { foreach ($day in $cron['DayOfMonth'].Values) { if ($day -gt $constraints.DaysInMonths[$mon - 1]) { - throw ($msgTable.daysInMonthExceededMessage -f $constraints.Months[$mon - 1], $constraints.DaysInMonths[$mon - 1], $day) #"$($constraints.Months[$mon - 1]) only has $($constraints.DaysInMonths[$mon - 1]) days, but $($day) was supplied" + throw ($msgTable.daysInMonthExceededExceptionMessage -f $constraints.Months[$mon - 1], $constraints.DaysInMonths[$mon - 1], $day) #"$($constraints.Months[$mon - 1]) only has $($constraints.DaysInMonths[$mon - 1]) days, but $($day) was supplied" } } } @@ -518,7 +518,7 @@ function Get-PodeCronNextTrigger { # before we return, make sure the time is valid if (!(Test-PodeCronExpression -Expression $Expression -DateTime $NextTime)) { - throw ($msgTable.nextTriggerCalculationErrorMessage -f $NextTime) #"Looks like something went wrong trying to calculate the next trigger datetime: $($NextTime)" + throw ($msgTable.nextTriggerCalculationErrorExceptionMessage -f $NextTime) #"Looks like something went wrong trying to calculate the next trigger datetime: $($NextTime)" } # if before the start or after end then return null diff --git a/src/Private/Cryptography.ps1 b/src/Private/Cryptography.ps1 index 76805e20a..c0f76de02 100644 --- a/src/Private/Cryptography.ps1 +++ b/src/Private/Cryptography.ps1 @@ -19,7 +19,7 @@ function Invoke-PodeHMACSHA256Hash { } if ($SecretBytes.Length -eq 0) { - throw 'No secret supplied for HMAC256 hash' + throw $msgTable.noSecretForHmac256ExceptionMessage #'No secret supplied for HMAC256 hash' } $crypto = [System.Security.Cryptography.HMACSHA256]::new($SecretBytes) @@ -47,7 +47,7 @@ function Invoke-PodeHMACSHA384Hash { } if ($SecretBytes.Length -eq 0) { - throw 'No secret supplied for HMAC384 hash' + throw $msgTable.noSecretForHmac384ExceptionMessage #'No secret supplied for HMAC384 hash' } $crypto = [System.Security.Cryptography.HMACSHA384]::new($SecretBytes) @@ -75,7 +75,7 @@ function Invoke-PodeHMACSHA512Hash { } if ($SecretBytes.Length -eq 0) { - throw 'No secret supplied for HMAC512 hash' + throw $msgTable.noSecretForHmac512ExceptionMessage #'No secret supplied for HMAC512 hash' } $crypto = [System.Security.Cryptography.HMACSHA512]::new($SecretBytes) @@ -304,11 +304,11 @@ function New-PodeJwtSignature { ) if (($Algorithm -ine 'none') -and (($null -eq $SecretBytes) -or ($SecretBytes.Length -eq 0))) { - throw 'No Secret supplied for JWT signature' + throw $msgTable.noSecretForJwtSignatureExceptionMessage #'No Secret supplied for JWT signature' } if (($Algorithm -ieq 'none') -and (($null -ne $secretBytes) -and ($SecretBytes.Length -gt 0))) { - throw 'Expected no secret to be supplied for no signature' + throw $msgTable.noSecretExpectedForNoSignatureExceptionMessage #'Expected no secret to be supplied for no signature' } $sig = $null @@ -334,7 +334,7 @@ function New-PodeJwtSignature { } default { - throw "The JWT algorithm is not currently supported: $($Algorithm)" + throw ($msgTable.unsupportedJwtAlgorithmExceptionMessage -f $Algorithm) #"The JWT algorithm is not currently supported: $($Algorithm)" } } @@ -393,7 +393,7 @@ function ConvertFrom-PodeJwtBase64Value { $Value = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Value)) } catch { - throw 'Invalid Base64 encoded value found in JWT' + throw $msgTable.invalidBase64JwtExceptionMessage #'Invalid Base64 encoded value found in JWT' } # return json @@ -401,6 +401,6 @@ function ConvertFrom-PodeJwtBase64Value { return ($Value | ConvertFrom-Json) } catch { - throw 'Invalid JSON value found in JWT' + throw $msgTable.invalidJsonJwtExceptionMessage #'Invalid JSON value found in JWT' } } \ No newline at end of file diff --git a/src/Private/Endpoints.ps1 b/src/Private/Endpoints.ps1 index 1cb70a5cc..86e34f436 100644 --- a/src/Private/Endpoints.ps1 +++ b/src/Private/Endpoints.ps1 @@ -282,7 +282,7 @@ function Find-PodeEndpointName { # error? if ($ThrowError) { - throw ($msgTable.endpointNotExistMessage -f $Protocol, $Address, $_localAddress) #"Endpoint with protocol '$($Protocol)' and address '$($Address)' or local address '$($_localAddress)' does not exist" + throw ($msgTable.endpointNotExistExceptionMessage -f $Protocol, $Address, $_localAddress) #"Endpoint with protocol '$($Protocol)' and address '$($Address)' or local address '$($_localAddress)' does not exist" } return $null @@ -310,7 +310,7 @@ function Get-PodeEndpointByName { # error? if ($ThrowError) { - throw ($msgTable.endpointNameNotExistMessage -f $Name) #"Endpoint with name '$($Name)' does not exist" + throw ($msgTable.endpointNameNotExistExceptionMessage -f $Name) #"Endpoint with name '$($Name)' does not exist" } return $null diff --git a/src/Private/Gui.ps1 b/src/Private/Gui.ps1 index 10a32a695..8372c273a 100644 --- a/src/Private/Gui.ps1 +++ b/src/Private/Gui.ps1 @@ -41,7 +41,7 @@ function Start-PodeGuiRunspace { Start-Sleep -Milliseconds 200 } else { - throw ($msgTable.failedToConnectToUrlMessage -f $uri) #"Failed to connect to URL: $($uri)" + throw ($msgTable.failedToConnectToUrlExceptionMessage -f $uri) #"Failed to connect to URL: $($uri)" } } } diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index 71066827e..f22920830 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -190,7 +190,7 @@ function Get-PodeEndpointInfo { # validate that we have a valid ip/host:port address if (!(($Address -imatch "^$($cmbdRgx)$") -or ($Address -imatch "^$($hostRgx)[\:]{0,1}") -or ($Address -imatch "[\:]{0,1}$($portRgx)$"))) { - throw ($msgTable.failedToParseAddressMessage -f $Address)#"Failed to parse '$($Address)' as a valid IP/Host:Port address" + throw ($msgTable.failedToParseAddressExceptionMessage -f $Address)#"Failed to parse '$($Address)' as a valid IP/Host:Port address" } # grab the ip address/hostname @@ -201,7 +201,7 @@ function Get-PodeEndpointInfo { # ensure we have a valid ip address/hostname if (!(Test-PodeIPAddress -IP $_host)) { - throw ($msgTable.invalidIpAddressMessage -f $_host) #"The IP address supplied is invalid: $($_host)" + throw ($msgTable.invalidIpAddressExceptionMessage -f $_host) #"The IP address supplied is invalid: $($_host)" } # grab the port @@ -212,7 +212,7 @@ function Get-PodeEndpointInfo { # ensure the port is valid if ($_port -lt 0) { - throw ($msgTable.invalidPortMessage -f $_port)#"The port cannot be negative: $($_port)" + throw ($msgTable.invalidPortExceptionMessage -f $_port)#"The port cannot be negative: $($_port)" } # return the info @@ -873,7 +873,7 @@ function New-PodePSDrive { # if the path supplied doesn't exist, error if (!(Test-Path $Path)) { - throw ($msgTable.pathNotExistMessage -f $Path)#"Path does not exist: $($Path)" + throw ($msgTable.pathNotExistExceptionMessage -f $Path)#"Path does not exist: $($Path)" } # resolve the path @@ -2333,7 +2333,7 @@ function Get-PodeRelativePath { # if flagged, test the path and throw error if it doesn't exist if ($TestPath -and !(Test-PodePath $Path -NoStatus)) { - throw "The path does not exist: $(Protect-PodeValue -Value $Path -Default $_rawPath)" + throw ($msgTable.pathNotExistExceptionMessage -f (Protect-PodeValue -Value $Path -Default $_rawPath))#"The path does not exist: $(Protect-PodeValue -Value $Path -Default $_rawPath)" } return $Path @@ -2379,7 +2379,7 @@ function Test-PodeIsServerless { ) if ($PodeContext.Server.IsServerless -and $ThrowError) { - throw "The $($FunctionName) function is not supported in a serverless context" + throw ($msgTable.unsupportedFunctionInServerlessContextExceptionMessage -f $FunctionName) #"The $($FunctionName) function is not supported in a serverless context" } if (!$ThrowError) { @@ -2502,24 +2502,25 @@ function Get-PodeHandler { function Convert-PodeFileToScriptBlock { param( [Parameter(Mandatory = $true)] + [Alias("FilePath")] [string] - $FilePath + $Path ) # resolve for relative path - $FilePath = Get-PodeRelativePath -Path $FilePath -JoinRoot + $Path = Get-PodeRelativePath -Path $Path -JoinRoot - # if file doesn't exist, error - if (!(Test-PodePath -Path $FilePath -NoStatus)) { - throw "The FilePath supplied does not exist: $($FilePath)" + # if Path doesn't exist, error + if (!(Test-PodePath -Path $Path -NoStatus)) { + throw ($msgTable.pathNotExistExceptionMessage -f $Path) # "The Path supplied does not exist: $($Path)" } # if the path is a wildcard or directory, error - if (!(Test-PodePathIsFile -Path $FilePath -FailOnWildcard)) { - throw "The FilePath supplied cannot be a wildcard or a directory: $($FilePath)" + if (!(Test-PodePathIsFile -Path $Path -FailOnWildcard)) { + throw ($msgTable.invalidPathWildcardOrDirectoryExceptionMessage -f $Path) # "The Path supplied cannot be a wildcard or a directory: $($Path)" } - return ([scriptblock](Use-PodeScript -Path $FilePath)) + return ([scriptblock](Use-PodeScript -Path $Path)) } function Convert-PodeQueryStringToHashTable { @@ -2597,15 +2598,16 @@ function Get-PodeDotSourcedFiles { function Get-PodeAstFromFile { param( [Parameter(Mandatory = $true)] + [Alias("FilePath")] [string] - $FilePath + $Path ) - if (!(Test-Path $FilePath)) { - throw "Path to script file does not exist: $($FilePath)" + if (!(Test-Path $Path)) { + throw ($msgTable.pathNotExistExceptionMessage -f $Path) # "The Path supplied does not exist: $($Path)" } - return [System.Management.Automation.Language.Parser]::ParseFile($FilePath, [ref]$null, [ref]$null) + return [System.Management.Automation.Language.Parser]::ParseFile($Path, [ref]$null, [ref]$null) } function Get-PodeFunctionsFromFile { @@ -2741,7 +2743,7 @@ function Use-PodeFolder { # fail if path not found if (!(Test-PodePath -Path $Path -NoStatus)) { - throw "Path to load $($DefaultPath) not found: $($Path)" + throw ($msgTable.pathToLoadNotFoundExceptionMessage -f $DefaultPath, $Path) #"Path to load $($DefaultPath) not found: $($Path)" } # get .ps1 files and load them @@ -2845,7 +2847,7 @@ function Set-PodeCronInterval { } if ($Value.Length -gt 1) { - throw "You can only supply a single $($Type) value when using intervals" + throw ($msgTable.singleValueForIntervalExceptionMessage -f $Type) #"You can only supply a single $($Type) value when using intervals" } if ($Value.Length -eq 1) { @@ -3313,7 +3315,8 @@ function ConvertTo-PodeYamlInternal { catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException - throw "Error'$($_)' in script $($_.InvocationInfo.ScriptName) $($_.InvocationInfo.Line.Trim()) (line $($_.InvocationInfo.ScriptLineNumber)) char $($_.InvocationInfo.OffsetInLine) executing $($_.InvocationInfo.MyCommand) on $type object '$($InputObject)' Class: $($InputObject.GetType().Name) BaseClass: $($InputObject.GetType().BaseType.Name) " + throw ($msgTable.scriptErrorExceptionMessage -f $_, $_.InvocationInfo.ScriptName, $_.InvocationInfo.Line.Trim(), $_.InvocationInfo.ScriptLineNumber, $_.InvocationInfo.OffsetInLine, $_.InvocationInfo.MyCommand, $type, $InputObject, $InputObject.GetType().Name, $InputObject.GetType().BaseType.Name) + #"Error'$($_)' in script $($_.InvocationInfo.ScriptName) $($_.InvocationInfo.Line.Trim()) (line $($_.InvocationInfo.ScriptLineNumber)) char $($_.InvocationInfo.OffsetInLine) executing $($_.InvocationInfo.MyCommand) on $type object '$($InputObject)' Class: $($InputObject.GetType().Name) BaseClass: $($InputObject.GetType().BaseType.Name) " } } } \ No newline at end of file diff --git a/src/Private/Middleware.ps1 b/src/Private/Middleware.ps1 index 4f5d74599..8d621dcd1 100644 --- a/src/Private/Middleware.ps1 +++ b/src/Private/Middleware.ps1 @@ -78,7 +78,7 @@ function New-PodeMiddlewareInternal { ) if (Test-PodeIsEmpty $ScriptBlock) { - throw '[Middleware]: No ScriptBlock supplied' + throw $msgTable.noScriptBlockSuppliedExceptionMessage #'No ScriptBlock supplied' } # if route is empty, set it to root @@ -392,7 +392,7 @@ function Initialize-PodeIISMiddleware { # fail if no iis token - because there should be! if ([string]::IsNullOrWhiteSpace($PodeContext.Server.IIS.Token)) { - throw 'IIS ASPNETCORE_TOKEN is missing' + throw $msgTable.iisAspnetcoreTokenMissingExceptionMessage #'IIS ASPNETCORE_TOKEN is missing' } # add middleware to check every request has the token diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index c0c14be1b..d3e56cf8a 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -43,7 +43,7 @@ function ConvertTo-PodeOAObjectSchema { # Ensure all content types are valid MIME types foreach ($type in $Content.Keys) { if ($type -inotmatch '^(application|audio|image|message|model|multipart|text|video|\*)\/[\w\.\-\*]+(;[\s]*(charset|boundary)=[\w\.\-\*]+)*$|^"\*\/\*"$') { - throw "Invalid content-type found for schema: $($type)" + throw ($msgTable.invalidContentTypeForSchemaExceptionMessage -f $type) #"Invalid content-type found for schema: $($type)" } } # manage generic schema json conversion issue @@ -181,7 +181,7 @@ function ConvertTo-PodeOAObjectSchema { } } else { - Throw 'The Properties parameters cannot be used if the Property has no name' + Throw $msgTable.propertiesParameterWithoutNameExceptionMessage #'The Properties parameters cannot be used if the Property has no name' } } else { @@ -373,7 +373,7 @@ function ConvertTo-PodeOASchemaProperty { $schema = [ordered]@{ } if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag ) { if ($Property.type -is [string[]]) { - throw 'Multi type properties requeired OpenApi Version 3.1 or above' + throw $msgTable.multiTypePropertiesRequireOpenApi31ExceptionMessage#'Multi type properties requeired OpenApi Version 3.1 or above' } $schema['type'] = $Property.type.ToLower() } @@ -806,7 +806,7 @@ function Get-PodeOpenApiDefinitionInternal { $Definition = $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag] if (!$Definition.Version) { - throw 'OpenApi openapi field is required' + throw $msgTable.openApiVersionPropertyMandatoryExceptionMessage#'OpenApi Version property is mandatory' } $localEndpoint = $null # set the openapi version @@ -862,7 +862,7 @@ function Get-PodeOpenApiDefinitionInternal { $def['paths'] = [ordered]@{} if ($Definition.webhooks.count -gt 0) { if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag) { - throw 'Feature webhooks is unsupported in OpenAPI v3.0.x' + throw $msgTable.webhooksFeatureNotSupportedInOpenApi30ExceptionMessage #'Webhooks feature is unsupported in OpenAPI v3.0.x' } else { $keys = [string[]]$Definition.webhooks.Keys @@ -909,7 +909,7 @@ function Get-PodeOpenApiDefinitionInternal { } if ($components.pathItems.count -gt 0) { if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag) { - throw 'Feature pathItems is unsupported in OpenAPI v3.0.x' + throw $msgTable.pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage #'Feature pathItems is unsupported in OpenAPI v3.0.x' } else { $keys = [string[]]$components.pathItems.Keys @@ -1313,7 +1313,7 @@ function Set-PodeOAAuth { # Validate the existence of specified authentication methods foreach ($n in @($Name)) { if (!(Test-PodeAuthExists -Name $n)) { - throw "Authentication method does not exist: $($n)" + throw ($msgTable.authenticationMethodDoesNotExistExceptionMessage -f $n) #"Authentication method does not exist: $($n)" } } } @@ -1380,7 +1380,7 @@ function Set-PodeOAGlobalAuth { # Check if the specified authentication method exists if (!(Test-PodeAuthExists -Name $Name)) { - throw "Authentication method does not exist: $($Name)" + throw ($msgTable.authenticationMethodDoesNotExistExceptionMessage -f $Name) #"Authentication method does not exist: $($Name)" } # Iterate over each definition tag to apply the authentication method @@ -1457,7 +1457,7 @@ function Resolve-PodeOAReference { $tmpProp += Resolve-PodeOAReference -DefinitionTag $DefinitionTag -ComponentSchema$comp } else { - throw 'Unsupported object' + throw $msgTable.unsupportedObjectExceptionMessage #'Unsupported object' } } } @@ -1472,10 +1472,10 @@ function Resolve-PodeOAReference { } elseif ($key -ieq 'oneof') { - throw 'Validation of schema with oneof is not supported' + throw $msgTable.validationOfOneOfSchemaNotSupportedExceptionMessage #'Validation of schema with oneof is not supported' } elseif ($key -ieq 'anyof') { - throw 'Validation of schema with anyof is not supported' + throw $msgTable.validationOfAnyOfSchemaNotSupportedExceptionMessage #'Validation of schema with anyof is not supported' } } elseif ($ComponentSchema.properties[$key].type -eq 'object') { @@ -1557,7 +1557,7 @@ function New-PodeOAPropertyInternal { $param.type = $Params.type } else { - throw 'Cannot create the property no type is defined' + throw $msgTable.cannotCreatePropertyWithoutTypeExceptionMessage #'Cannot create the property no type is defined' } } @@ -1639,7 +1639,7 @@ function New-PodeOAPropertyInternal { if ($Params.ExternalDocs) { $param.externalDocs = $Params.ExternalDocs } if ($Params.NoAdditionalProperties.IsPresent -and $Params.AdditionalProperties) { - throw 'Params -NoAdditionalProperties and -AdditionalProperties are mutually exclusive' + throw $msgTable.paramsNoAdditionalPropertiesExclusiveExceptionMessage #'Params -NoAdditionalProperties and -AdditionalProperties are mutually exclusive' } else { if ($Params.NoAdditionalProperties.IsPresent) { $param.additionalProperties = $false } @@ -1699,7 +1699,7 @@ function ConvertTo-PodeOAHeaderProperty { } } else { - throw 'Header requires a name when used in an encoding context' + throw $msgTable.headerMustHaveNameInEncodingContextExceptionMessage #'Header requires a name when used in an encoding context' } } @@ -1814,7 +1814,7 @@ function New-PodeOResponseInternal { $Description = Get-PodeStatusDescription -StatusCode $Params.StatusCode } else { - throw 'A Description is required' + throw $msgTable.descriptionRequiredExceptionMessage #'A Description is required' } } else { @@ -1984,7 +1984,7 @@ function Test-PodeOADefinitionInternal { } # Throw an error indicating non-compliance with OpenAPI standards - throw 'OpenAPI document compliance issues' + throw $msgTable.openApiDocumentNotCompliantExceptionMessage #'OpenAPI document compliance issues' } } @@ -2056,7 +2056,7 @@ function Test-PodeOAComponentInternal { if (!($PodeContext.Server.OpenAPI.Definitions[$tag].components[$field].keys -ccontains $Name)) { # If $Name is not found in the current $tag, return $false or throw an exception if ($ThrowException.IsPresent ) { - throw "No components of type $field named $Name are available in the $tag definition." + throw ($msgTable.noComponentInDefinitionExceptionMessage -f $field, $Name, $tag) #"No component of type $field named $Name is available in the $tag definition." } else { return $false diff --git a/src/Private/Routes.ps1 b/src/Private/Routes.ps1 index 301f45d90..37501e82c 100644 --- a/src/Private/Routes.ps1 +++ b/src/Private/Routes.ps1 @@ -504,10 +504,10 @@ function Test-PodeRouteInternal { } if ([string]::IsNullOrEmpty($_url)) { - throw "[$($Method)] $($Path): Already defined" + throw ($msgTable.methodPathAlreadyDefinedExceptionMessage -f $Method, $Path) #"[$($Method)] $($Path): Already defined" } - throw "[$($Method)] $($Path): Already defined for $($_url)" + throw ($msgTable.methodPathAlreadyDefinedForUrlExceptionMessage -f $Method, $Path, $_url) #"[$($Method)] $($Path): Already defined for $($_url)" } function Convert-PodeFunctionVerbToHttpMethod { @@ -652,17 +652,17 @@ function ConvertTo-PodeMiddleware { # check middleware is a type valid if (($mid -isnot [scriptblock]) -and ($mid -isnot [hashtable])) { - throw "One of the Middlewares supplied is an invalid type. Expected either a ScriptBlock or Hashtable, but got: $($mid.GetType().Name)" + throw ($msgTable.invalidMiddlewareTypeExceptionMessage -f $mid.GetType().Name)#"One of the Middlewares supplied is an invalid type. Expected either a ScriptBlock or Hashtable, but got: $($mid.GetType().Name)" } # if middleware is hashtable, ensure the keys are valid (logic is a scriptblock) if ($mid -is [hashtable]) { if ($null -eq $mid.Logic) { - throw 'A Hashtable Middleware supplied has no Logic defined' + throw $msgTable.hashtableMiddlewareNoLogicExceptionMessage#'A Hashtable Middleware supplied has no Logic defined' } if ($mid.Logic -isnot [scriptblock]) { - throw "A Hashtable Middleware supplied has an invalid Logic type. Expected ScriptBlock, but got: $($mid.Logic.GetType().Name)" + throw ($msgTable.invalidLogicTypeInHashtableMiddlewareExceptionMessage -f $mid.Logic.GetType().Name)#"A Hashtable Middleware supplied has an invalid Logic type. Expected ScriptBlock, but got: $($mid.Logic.GetType().Name)" } } } diff --git a/src/Private/ScopedVariables.ps1 b/src/Private/ScopedVariables.ps1 index 5fe266963..c0ee77e94 100644 --- a/src/Private/ScopedVariables.ps1 +++ b/src/Private/ScopedVariables.ps1 @@ -27,7 +27,7 @@ function Add-PodeScopedVariableInternal { # check if var already defined if (Test-PodeScopedVariable -Name $Name) { - throw "Scoped Variable already defined: $($Name)" + throw ($msgTable.scopedVariableAlreadyDefinedExceptionMessage -f $Name)#"Scoped Variable already defined: $($Name)" } # add scoped var definition @@ -169,7 +169,7 @@ function Find-PodeScopedVariableUsingVariableValues { } if ([string]::IsNullOrEmpty($value)) { - throw "Value for `$using:$($varName) could not be found" + throw ($msgTable.valueForUsingVariableNotFoundExceptionMessage -f $varName) #"Value for `$using:$($varName) could not be found" } # add to mapped diff --git a/src/Private/Secrets.ps1 b/src/Private/Secrets.ps1 index 744ddd31c..1f80e137f 100644 --- a/src/Private/Secrets.ps1 +++ b/src/Private/Secrets.ps1 @@ -45,7 +45,7 @@ function Register-PodeSecretManagementVault { # check if we have an unlock password for local secret store if ($isSecretStore) { if ([string]::IsNullOrEmpty($VaultConfig.Unlock.Secret)) { - throw 'An "-UnlockSecret" is required when using Microsoft.PowerShell.SecretStore' + throw $msgTable.unlockSecretRequiredExceptionMessage#'An "-UnlockSecret" is required when using Microsoft.PowerShell.SecretStore' } } @@ -145,7 +145,7 @@ function Register-PodeSecretCustomVault { # unlock secret with no script? if ($VaultConfig.Unlock.Enabled -and (Test-PodeIsEmpty $UnlockScriptBlock)) { - throw 'Unlock secret supplied for custom Secret Vault type, but not Unlock ScriptBlock supplied' + throw $msgTable.unlockSecretButNoScriptBlockExceptionMessage #'Unlock secret supplied for custom Secret Vault type, but not Unlock ScriptBlock supplied' } # all is good, so set the config @@ -195,7 +195,7 @@ function Unlock-PodeSecretCustomVault { # do we have an unlock scriptblock if ($null -eq $VaultConfig.Custom.Unlock) { - throw "No Unlock ScriptBlock supplied for unlocking the vault '$($VaultConfig.Name)'" + throw ($msgTable.noUnlockScriptBlockForVaultExceptionMessage -f $VaultConfig.Name) #"No Unlock ScriptBlock supplied for unlocking the vault '$($VaultConfig.Name)'" } # unlock the vault, and get back an expiry @@ -352,7 +352,7 @@ function Set-PodeSecretCustomKey { # do we have a set scriptblock? if ($null -eq $_vault.Custom.Set) { - throw "No Set ScriptBlock supplied for updating/creating secrets in the vault '$($_vault.Name)'" + throw ($msgTable.noSetScriptBlockForVaultExceptionMessage -f $_vault.Name) #"No Set ScriptBlock supplied for updating/creating secrets in the vault '$($_vault.Name)'" } # set the secret @@ -402,7 +402,7 @@ function Remove-PodeSecretCustomKey { # do we have a remove scriptblock? if ($null -eq $_vault.Custom.Remove) { - throw "No Remove ScriptBlock supplied for removing secrets from the vault '$($_vault.Name)'" + throw ($msgTable.noRemoveScriptBlockForVaultExceptionMessage -f $_vault.Name) #"No Remove ScriptBlock supplied for removing secrets from the vault '$($_vault.Name)'" } # remove the secret @@ -505,7 +505,7 @@ function Protect-PodeSecretValueType { ($Value -is [pscredential]) -or ($Value -is [System.Management.Automation.OrderedHashtable]) )) { - throw "Value to set secret to is of an invalid type. Expected either String, SecureString, HashTable, Byte[], or PSCredential. But got: $($Value.GetType().Name)" + throw ($msgTable.invalidSecretValueTypeExceptionMessage -f $Value.GetType().Name) #"Value to set secret to is of an invalid type. Expected either String, SecureString, HashTable, Byte[], or PSCredential. But got: $($Value.GetType().Name)" } return $Value diff --git a/src/Private/Security.ps1 b/src/Private/Security.ps1 index 559f672d0..f5691f6bb 100644 --- a/src/Private/Security.ps1 +++ b/src/Private/Security.ps1 @@ -348,11 +348,11 @@ function Add-PodeIPLimit { # ensure limit and seconds are non-zero and negative if ($Limit -le 0) { - throw "Limit value cannot be 0 or less for $($IP)" + throw ($msgTable.limitValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Limit value cannot be 0 or less for $($IP)" } if ($Seconds -le 0) { - throw "Seconds value cannot be 0 or less for $($IP)" + throw ($msgTable.secondsValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Seconds value cannot be 0 or less for $($IP)" } # get current rules @@ -426,11 +426,11 @@ function Add-PodeRouteLimit { # ensure limit and seconds are non-zero and negative if ($Limit -le 0) { - throw "Limit value cannot be 0 or less for $($IP)" + throw ($msgTable.limitValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Limit value cannot be 0 or less for $($IP)" } if ($Seconds -le 0) { - throw "Seconds value cannot be 0 or less for $($IP)" + throw ($msgTable.secondsValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Seconds value cannot be 0 or less for $($IP)" } # get current rules @@ -482,16 +482,16 @@ function Add-PodeEndpointLimit { # does the endpoint exist? $endpoint = Get-PodeEndpointByName -Name $EndpointName if ($null -eq $endpoint) { - throw "Endpoint not found: $($EndpointName)" + throw ($msgTable.endpointNameNotExistExceptionMessage -f $EndpointName) #"Endpoint not found: $($EndpointName)" } # ensure limit and seconds are non-zero and negative if ($Limit -le 0) { - throw "Limit value cannot be 0 or less for $($IP)" + throw ($msgTable.limitValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Limit value cannot be 0 or less for $($IP)" } if ($Seconds -le 0) { - throw "Seconds value cannot be 0 or less for $($IP)" + throw ($msgTable.secondsValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Seconds value cannot be 0 or less for $($IP)" } # get current rules @@ -816,7 +816,7 @@ function Get-PodeCertificateByPemFile { $result = openssl pkcs12 -inkey $keyPath -in $certPath -export -passin pass:$Password -password pass:$Password -out $tempFile if (!$?) { - throw "Failed to create openssl cert: $($result)" + throw ($msgTable.failedToCreateOpenSslCertExceptionMessage -f $result) #"Failed to create openssl cert: $($result)" } $cert = [X509Certificates.X509Certificate2]::new($tempFile, $Password) @@ -850,7 +850,7 @@ function Find-PodeCertificateInCertStore { # fail if not windows if (!(Test-PodeIsWindows)) { - throw 'Certificate Thumbprints/Name are only supported on Windows' + throw $msgTable.certificateThumbprintsNameSupportedOnWindowsExceptionMessage #'Certificate Thumbprints/Name are only supported on Windows' } # open the currentuser\my store @@ -870,7 +870,7 @@ function Find-PodeCertificateInCertStore { # fail if no cert found for query if (($null -eq $x509certs) -or ($x509certs.Count -eq 0)) { - throw "No certificate could be found in $($StoreLocation)\$($StoreName) for '$($Query)'" + throw ($msgTable.noCertificateFoundExceptionMessage -f $StoreLocation, $StoreName, $Query) # "No certificate could be found in $($StoreLocation)\$($StoreName) for '$($Query)'" } return ([X509Certificates.X509Certificate2]($x509certs[0])) diff --git a/src/Private/Server.ps1 b/src/Private/Server.ps1 index 367d065fd..bdad25560 100644 --- a/src/Private/Server.ps1 +++ b/src/Private/Server.ps1 @@ -136,7 +136,7 @@ function Start-PodeInternalServer { # errored? if ($PodeContext.RunspacePools[$pool].State -ieq 'error') { - throw "$($pool) RunspacePool failed to load" + throw ($msgTable.runspacePoolFailedToLoadExceptionMessage -f $pool) #"$($pool) RunspacePool failed to load" } } } diff --git a/src/Private/ServiceServer.ps1 b/src/Private/ServiceServer.ps1 index 9f39bb535..e1e66491e 100644 --- a/src/Private/ServiceServer.ps1 +++ b/src/Private/ServiceServer.ps1 @@ -1,7 +1,7 @@ function Start-PodeServiceServer { # ensure we have service handlers if (Test-PodeIsEmpty (Get-PodeHandler -Type Service)) { - throw 'No Service handlers have been defined' + throw $msgTable.noServiceHandlersDefinedExceptionMessage #'No Service handlers have been defined' } # state we're running diff --git a/src/Private/Sessions.ps1 b/src/Private/Sessions.ps1 index 35445d1cc..43074e223 100644 --- a/src/Private/Sessions.ps1 +++ b/src/Private/Sessions.ps1 @@ -40,7 +40,7 @@ function Get-PodeSessionFullId { function Set-PodeSession { if ($null -eq $WebEvent.Session) { - throw 'there is no session available to set on the response' + throw $msgTable.noSessionToSetOnResponseExceptionMessage #'there is no session available to set on the response' } # convert secret to strict mode @@ -137,7 +137,7 @@ function Revoke-PodeSession { function Set-PodeSessionDataHash { if ($null -eq $WebEvent.Session) { - throw 'No session available to calculate data hash' + throw $msgTable.noSessionToCalculateDataHashExceptionMessage #'No session available to calculate data hash' } if (($null -eq $WebEvent.Session.Data) -or ($WebEvent.Session.Data.Count -eq 0)) { diff --git a/src/Private/Setup.ps1 b/src/Private/Setup.ps1 index 340706864..9756736de 100644 --- a/src/Private/Setup.ps1 +++ b/src/Private/Setup.ps1 @@ -60,7 +60,7 @@ function Install-PodeLocalModules { } catch { Write-Host 'Failed' -ForegroundColor Red - throw "Module or version not found on $($_repository): $($_name)@$($_version)" + throw ($msgTable.moduleOrVersionNotFoundExceptionMessage -f $_repository, $_name, $_version) #"Module or version not found on $($_repository): $($_name)@$($_version)" } } } \ No newline at end of file diff --git a/src/Private/SmtpServer.ps1 b/src/Private/SmtpServer.ps1 index 603e08dff..e434504c1 100644 --- a/src/Private/SmtpServer.ps1 +++ b/src/Private/SmtpServer.ps1 @@ -3,7 +3,7 @@ using namespace Pode function Start-PodeSmtpServer { # ensure we have smtp handlers if (Test-PodeIsEmpty (Get-PodeHandler -Type Smtp)) { - throw 'No SMTP handlers have been defined' + throw $msgTable.noSmtpHandlersDefinedExceptionMessage #'No SMTP handlers have been defined' } # work out which endpoints to listen on diff --git a/src/Private/Tasks.ps1 b/src/Private/Tasks.ps1 index 1ab6ad6bb..88b4d090c 100644 --- a/src/Private/Tasks.ps1 +++ b/src/Private/Tasks.ps1 @@ -168,7 +168,7 @@ function Wait-PodeNetTaskInternal { # if the main task isnt complete, it timed out if (($null -ne $timeoutTask) -and (!$Task.IsCompleted)) { - throw [System.TimeoutException]::new("Task has timed out after $($Timeout)ms") + throw [System.TimeoutException]::new($msgTable.taskTimedOutExceptionMessage -f $Timeout) #"Task has timed out after $($Timeout)ms") } # only return a value if the result has one diff --git a/src/Private/Verbs.ps1 b/src/Private/Verbs.ps1 index 002e61571..7ace07a1d 100644 --- a/src/Private/Verbs.ps1 +++ b/src/Private/Verbs.ps1 @@ -117,9 +117,9 @@ function Test-PodeVerbAndError { } if ([string]::IsNullOrEmpty($_url)) { - throw "[Verb] $($Verb): Already defined" + throw ($msgTable.verbAlreadyDefinedExceptionMessage -f $Verb) #"[Verb] $($Verb): Already defined" } else { - throw "[Verb] $($Verb): Already defined for $($_url)" + throw ($msgTable.verbAlreadyDefinedForUrlExceptionMessage -f $Verb, $_url) # "[Verb] $($Verb): Already defined for $($_url)" } } \ No newline at end of file diff --git a/src/Public/Access.ps1 b/src/Public/Access.ps1 index 3e7a56ef5..4a949031b 100644 --- a/src/Public/Access.ps1 +++ b/src/Public/Access.ps1 @@ -69,7 +69,7 @@ function New-PodeAccessScheme { # for custom access a validator is mandatory if ($Custom) { if ([string]::IsNullOrWhiteSpace($Path) -and (Test-PodeIsEmpty $ScriptBlock)) { - throw 'A Path or ScriptBlock is required for sourcing the Custom access values' + throw $msgTable.pathOrScriptBlockRequiredExceptionMessage #'A Path or ScriptBlock is required for sourcing the Custom access values' } } @@ -174,7 +174,7 @@ function Add-PodeAccess { # check name unique if (Test-PodeAccessExists -Name $Name) { - throw "Access method already defined: $($Name)" + throw ($msgTable.accessMethodAlreadyDefinedExceptionMessage -f $Name) #"Access method already defined: $($Name)" } # parse using variables in validator scriptblock @@ -241,13 +241,13 @@ function Merge-PodeAccess { # ensure the name doesn't already exist if (Test-PodeAccessExists -Name $Name) { - throw "Access method already defined: $($Name)" + throw ($msgTable.accessMethodAlreadyDefinedExceptionMessage -f $Name) #"Access method already defined: $($Name)" } # ensure all the access methods exist foreach ($accName in $Access) { if (!(Test-PodeAccessExists -Name $accName)) { - throw "Access method does not exist for merging: $($accName)" + throw ($msgTable.accessMethodNotExistForMergingExceptionMessage -f $accName) #"Access method does not exist for merging: $($accName)" } } @@ -313,7 +313,7 @@ function Add-PodeAccessCustom { end { foreach ($r in $routes) { if ($r.AccessMeta.Custom.ContainsKey($Name)) { - throw "Route '[$($r.Method)] $($r.Path)' already contains Custom Access with name '$($Name)'" + throw ($msgTable.routeAlreadyContainsCustomAccessExceptionMessage -f $r.Method, $r.Path, $Name) #"Route '[$($r.Method)] $($r.Path)' already contains Custom Access with name '$($Name)'" } $r.AccessMeta.Custom[$Name] = $Value @@ -663,7 +663,7 @@ function Add-PodeAccessMiddleware { ) if (!(Test-PodeAccessExists -Name $Access)) { - throw "Access method does not exist: $($Access)" + throw ($msgTable.accessMethodNotExistExceptionMessage -f $Access) #"Access method does not exist: $($Access)" } Get-PodeAccessMiddlewareScript | diff --git a/tests/unit/Helpers.Tests.ps1 b/tests/unit/Helpers.Tests.ps1 index dd59ea60e..912cb97bb 100644 --- a/tests/unit/Helpers.Tests.ps1 +++ b/tests/unit/Helpers.Tests.ps1 @@ -1075,7 +1075,7 @@ Describe 'Get-PodeRelativePath' { It 'Throws error for path ot existing' { Mock Test-PodePath { return $false } - { Get-PodeRelativePath -Path './path' -TestPath } | Should -Throw -ExpectedMessage '*The path does not exist*' + { Get-PodeRelativePath -Path './path' -TestPath } | Should -Throw -ExpectedMessage ($msgTable.pathNotExistExceptionMessage -f './path') # '*The path does not exist*' } } diff --git a/tests/unit/Localization.Tests.ps1 b/tests/unit/Localization.Tests.ps1 new file mode 100644 index 000000000..6edc585f2 --- /dev/null +++ b/tests/unit/Localization.Tests.ps1 @@ -0,0 +1,37 @@ +# Save this script as Check-LocalizationKeys.Tests.ps1 +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')] +param() + +Describe 'Localization Files Key Check' { + $path = $PSCommandPath + $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src' + # All language directories + $localizationDir = "$src/Locales" + + # Path to the English localization file + $englishFilePath = "$localizationDir/en/Pode.psd1" + $podeFileContent = Get-Content -Path $englishFilePath -Raw + # Execute the content and assign the result to a variable + $localizationMessages = Invoke-Expression $podeFileContent + $global:localizationKeys = $localizationMessages.Keys + # Discover all language directories + $languageDirs = Get-ChildItem -Path $localizationDir -Directory | Where-Object { $_.Name -ne 'en' } + + $languageDirs.foreach({ + Describe "Language $($_.Name) Test" { + # describe "Checking localization $($_.Name)" { + $filePath = "$($_.FullName)/Pode.psd1" + it 'Language resource file exist' { + Test-Path $filePath | Should -BeTrue + } + $podeFileContent = Get-Content -Path $filePath -Raw + $global:content = Invoke-Expression $podeFileContent + It -ForEach ($global:localizationKeys) -Name 'Resource File contain <_>' { + foreach ($key in $global:localizationKeys) { + #$global:content.Keys | Should -Contain $_ #-contains $_ | Should -BeTrue + $global:content.Keys -contains $_ | Should -BeTrue + } + } + } + }) +} diff --git a/tests/unit/Mappers.Tests.ps1 b/tests/unit/Mappers.Tests.ps1 index abb8dc845..e86bbe69d 100644 --- a/tests/unit/Mappers.Tests.ps1 +++ b/tests/unit/Mappers.Tests.ps1 @@ -1461,5 +1461,5 @@ Describe 'Get-PodeStatusDescription' { Get-PodeStatusDescription -StatusCode $_ | Should -Be $codes[$_] } - }#> + } } \ No newline at end of file diff --git a/tests/unit/Routes.Tests.ps1 b/tests/unit/Routes.Tests.ps1 index 004f8d72a..591b64342 100644 --- a/tests/unit/Routes.Tests.ps1 +++ b/tests/unit/Routes.Tests.ps1 @@ -619,7 +619,7 @@ Describe 'Add-PodePage' { It 'Throws error for invalid FilePath' { $PodeContext.Server = @{ 'Root' = $pwd } - { Add-PodePage -Name 'RickMorty' -FilePath './fake/path' } | Should -Throw -ExpectedMessage '*the path does not exist*' + { Add-PodePage -Name 'RickMorty' -FilePath './fake/path' } | Should -Throw -ExpectedMessage ($msgTable.pathNotExistExceptionMessage -f '*/fake/path') #'*the path does not exist*' } It 'Call Add-PodeRoute once for ScriptBlock page' { From ea6156e9fa70698d26d6394f641c50dd51a0f3c8 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Thu, 30 May 2024 14:34:07 -0700 Subject: [PATCH 010/177] Remove a redundant code in Write-PodeYamlResponse --- src/Public/Responses.ps1 | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index a1d142157..4fc103ef6 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -932,12 +932,6 @@ function Write-PodeYamlResponse { $Value = $pipelineValue } - if ($Value -is [hashtable]) { - $Value = @(foreach ($v in $Value) { - New-Object psobject -Property $v - }) - } - if ($Value -isnot [string]) { $Value = ConvertTo-PodeYaml -InputObject $Value -Depth $Depth From eae6442ca19a452c74b64105119b446f8a13745e Mon Sep 17 00:00:00 2001 From: mdaneri Date: Thu, 30 May 2024 14:58:22 -0700 Subject: [PATCH 011/177] test fixed --- tests/unit/Localization.Tests.ps1 | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/tests/unit/Localization.Tests.ps1 b/tests/unit/Localization.Tests.ps1 index 6edc585f2..32a85f70d 100644 --- a/tests/unit/Localization.Tests.ps1 +++ b/tests/unit/Localization.Tests.ps1 @@ -17,21 +17,19 @@ Describe 'Localization Files Key Check' { # Discover all language directories $languageDirs = Get-ChildItem -Path $localizationDir -Directory | Where-Object { $_.Name -ne 'en' } - $languageDirs.foreach({ - Describe "Language $($_.Name) Test" { - # describe "Checking localization $($_.Name)" { - $filePath = "$($_.FullName)/Pode.psd1" - it 'Language resource file exist' { - Test-Path $filePath | Should -BeTrue - } - $podeFileContent = Get-Content -Path $filePath -Raw - $global:content = Invoke-Expression $podeFileContent - It -ForEach ($global:localizationKeys) -Name 'Resource File contain <_>' { - foreach ($key in $global:localizationKeys) { - #$global:content.Keys | Should -Contain $_ #-contains $_ | Should -BeTrue - $global:content.Keys -contains $_ | Should -BeTrue - } - } + Describe "Language [<_.Name>]" -ForEach ($languageDirs) { + it 'Language resource file exist' { + Test-Path -Path "$($_.FullName)/Pode.psd1" | Should -BeTrue + } + $podeFileContent = Get-Content -Path "$($_.FullName)/Pode.psd1" -Raw + $global:content = Invoke-Expression $podeFileContent + it 'Total number of keys equal to the [en]'{ + $global:content.Keys.Count | Should -be $global:localizationKeys.Count + } + It -ForEach ($global:localizationKeys) -Name 'Resource File contain <_>' { + foreach ($key in $global:localizationKeys) { + $global:content.Keys -contains $_ | Should -BeTrue } - }) + } + } } From e23d11267225f478e09082fb2453cd40680ed2b1 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 31 May 2024 08:47:07 -0700 Subject: [PATCH 012/177] Update Helpers.ps1 Add conversion PSCustomObject to YAML using ConvertTo-PodeYaml Fix ConvertTo-PodeYaml piping --- src/Private/Helpers.ps1 | 275 ++++++++++++++++++++++------------------ 1 file changed, 153 insertions(+), 122 deletions(-) diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index c9b1dedf2..d9c409e6d 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -3084,10 +3084,10 @@ function Test-PodeVersionPwshEOL { creates a YAML description of the data in the object - based on https://github.com/Phil-Factor/PSYaml .DESCRIPTION - This produces YAML from any object you pass to it. It isn't suitable for the huge objects produced by some of the cmdlets such as Get-Process, but fine for simple objects + This produces YAML from any object you pass to it. - .PARAMETER Object - The object that you want scripted out +.PARAMETER Object + The object that you want scripted out. This parameter accepts input via the pipeline. .PARAMETER Depth The depth that you want your object scripted to @@ -3108,15 +3108,28 @@ function ConvertTo-PodeYaml { $Depth = 16 ) - if ($null -eq $PodeContext.Server.InternalCache.YamlModuleImported) { - $PodeContext.Server.InternalCache.YamlModuleImported = ((Test-PodeModuleInstalled -Name 'PSYaml') -or (Test-PodeModuleInstalled -Name 'powershell-yaml')) + begin { + $pipelineObject = @() } - if ($PodeContext.Server.InternalCache.YamlModuleImported) { - return ($InputObject | ConvertTo-Yaml) + process { + $pipelineObject += $_ } - else { - return ConvertTo-PodeYamlInternal -InputObject $InputObject -Depth $Depth -NoNewLine + + end { + if ($null -eq $PodeContext.Server.InternalCache.YamlModuleImported) { + $PodeContext.Server.InternalCache.YamlModuleImported = ((Test-PodeModuleInstalled -Name 'PSYaml') -or (Test-PodeModuleInstalled -Name 'powershell-yaml')) + } + if ($pipelineObject) { + $InputObject = $pipelineObject + } + + if ($PodeContext.Server.InternalCache.YamlModuleImported) { + return ($InputObject | ConvertTo-Yaml) + } + else { + return ConvertTo-PodeYamlInternal -InputObject $InputObject -Depth $Depth -NoNewLine + } } } @@ -3130,7 +3143,7 @@ function ConvertTo-PodeYaml { The depth of conversion can be controlled, allowing for nested objects to be accurately represented. .PARAMETER InputObject - The PowerShell object to convert to YAML. This parameter accepts input via the pipeline. + The PowerShell object to convert to YAML. .PARAMETER Depth Specifies the maximum depth of object nesting to convert. Default is 10 levels deep. @@ -3145,9 +3158,9 @@ function ConvertTo-PodeYaml { System.String. Returns a string in YAML format. .EXAMPLE - $object | ConvertTo-PodeYamlInternal + ConvertTo-PodeYamlInternal -InputObject $object - Converts the object piped to it into a YAML string. + Converts the object into a YAML string. .NOTES This is an internal function and may change in future releases of Pode. @@ -3159,7 +3172,7 @@ function ConvertTo-PodeYamlInternal { [CmdletBinding()] [OutputType([string])] param ( - [parameter(Mandatory = $true, ValueFromPipeline = $true)] + [parameter(Mandatory = $true, ValueFromPipeline = $false)] [AllowNull()] $InputObject, @@ -3176,149 +3189,167 @@ function ConvertTo-PodeYamlInternal { $NoNewLine ) - process { - # if it is null return null - If ( !($InputObject) ) { - if ($InputObject -is [Object[]]) { - return '[]' - } - else { - return '' - } + #report the leaves in terms of object type + if ($Depth -ilt $NestingLevel) { + return '' + } + # if it is null return null + If ( !($InputObject) ) { + if ($InputObject -is [Object[]]) { + return '[]' } + else { + return '' + } + } - $padding = [string]::new(' ', $NestingLevel * 2) # lets just create our left-padding for the block - try { - $Type = $InputObject.GetType().Name # we start by getting the object's type - if ($InputObject -is [object[]]) { - #what it really is - $Type = "$($InputObject.GetType().BaseType.Name)" - } + $padding = [string]::new(' ', $NestingLevel * 2) # lets just create our left-padding for the block + try { + $Type = $InputObject.GetType().Name # we start by getting the object's type + if ($InputObject -is [object[]]) { + #what it really is + $Type = "$($InputObject.GetType().BaseType.Name)" + } - #report the leaves in terms of object type - if ($Depth -ilt $NestingLevel) { - $Type = 'OutOfDepth' - } + # Check for specific value types (int, bool, float, double, string, etc.) + if ($Type -notin @('Int32', 'Boolean', 'Single', 'Double', 'String')) { # prevent these values being identified as an object if ($InputObject -is [System.Collections.Specialized.OrderedDictionary]) { - $Type = 'HashTable' + $Type = 'hashTable' } elseif ($Type -ieq 'List`1') { - $Type = 'Array' + $Type = 'array' } elseif ($InputObject -is [array]) { - $Type = 'Array' + $Type = 'array' } # whatever it thinks it is called - elseif ($InputObject -is [hashtable]) { - $Type = 'HashTable' + elseif ($InputObject -is [hashtable] ) { + $Type = 'hashTable' } # for our purposes it is a hashtable + } + + $output += switch ($Type.ToLower()) { + 'string' { + $String = "$InputObject" + if (($string -match '[\r\n]' -or $string.Length -gt 80) -and ($string -notlike 'http*')) { + $multiline = [System.Text.StringBuilder]::new("|`n") - $output += switch ($Type.ToLower()) { - 'string' { - $String = "$InputObject" - if (($string -match '[\r\n]' -or $string.Length -gt 80) -and ($string -notlike 'http*')) { - $multiline = [System.Text.StringBuilder]::new("|`n") - - $items = $string.Split("`n") - for ($i = 0; $i -lt $items.Length; $i++) { - $workingString = $items[$i] -replace '\r$' - $length = $workingString.Length - $index = 0 - $wrap = 80 - - while ($index -lt $length) { - $breakpoint = $wrap - $linebreak = $false - - if (($length - $index) -gt $wrap) { - $lastSpaceIndex = $workingString.LastIndexOf(' ', $index + $wrap, $wrap) - if ($lastSpaceIndex -ne -1) { - $breakpoint = $lastSpaceIndex - $index - } - else { - $linebreak = $true - $breakpoint-- - } + $items = $string.Split("`n") + for ($i = 0; $i -lt $items.Length; $i++) { + $workingString = $items[$i] -replace '\r$' + $length = $workingString.Length + $index = 0 + $wrap = 80 + + while ($index -lt $length) { + $breakpoint = $wrap + $linebreak = $false + + if (($length - $index) -gt $wrap) { + $lastSpaceIndex = $workingString.LastIndexOf(' ', $index + $wrap, $wrap) + if ($lastSpaceIndex -ne -1) { + $breakpoint = $lastSpaceIndex - $index } else { - $breakpoint = $length - $index - } - - $null = $multiline.Append($padding).Append($workingString.Substring($index, $breakpoint).Trim()) - if ($linebreak) { - $null = $multiline.Append('\') + $linebreak = $true + $breakpoint-- } + } + else { + $breakpoint = $length - $index + } - $index += $breakpoint - if ($index -lt $length) { - $null = $multiline.Append([System.Environment]::NewLine) - } + $null = $multiline.Append($padding).Append($workingString.Substring($index, $breakpoint).Trim()) + if ($linebreak) { + $null = $multiline.Append('\') } - if ($i -lt ($items.Length - 1)) { + $index += $breakpoint + if ($index -lt $length) { $null = $multiline.Append([System.Environment]::NewLine) } } - $multiline.ToString().TrimEnd() - break - } - else { - if ($string -match '^[#\[\]@\{\}\!\*]') { - "'$($string -replace '''', '''''')'" - } - else { - $string + if ($i -lt ($items.Length - 1)) { + $null = $multiline.Append([System.Environment]::NewLine) } - break } + + $multiline.ToString().TrimEnd() break } - 'hashtable' { - if ($InputObject.Count -gt 0 ) { - $index = 0 - $string = [System.Text.StringBuilder]::new() - foreach ($item in $InputObject.Keys) { - if ($InputObject[$item] -is [string]) { $increment = 2 } else { $increment = 1 } - if ($NoNewLine -and $index++ -eq 0) { $NewPadding = '' } else { $NewPadding = "`n$padding" } - $null = $string.Append( $NewPadding).Append( $item).Append(': ').Append((ConvertTo-PodeYamlInternal -InputObject $InputObject[$item] -Depth $Depth -NestingLevel ($NestingLevel + $increment))) - } - $string.ToString() + else { + if ($string -match '^[#\[\]@\{\}\!\*]') { + "'$($string -replace '''', '''''')'" + } + else { + $string } - else { '{}' } - break - } - 'boolean' { - if ($InputObject -eq $true) { 'true' } else { 'false' } break } - 'array' { - $string = [System.Text.StringBuilder]::new() + break + } + 'hashtable' { + if ($InputObject.Count -gt 0 ) { $index = 0 - foreach ($item in $InputObject ) { + $string = [System.Text.StringBuilder]::new() + foreach ($item in $InputObject.Keys) { + if ($InputObject[$item] -is [string]) { $increment = 2 } else { $increment = 1 } if ($NoNewLine -and $index++ -eq 0) { $NewPadding = '' } else { $NewPadding = "`n$padding" } - $null = $string.Append($NewPadding).Append('- ').Append((ConvertTo-PodeYamlInternal -InputObject $item -depth $Depth -NestingLevel ($NestingLevel + 1) -NoNewLine)) + $null = $string.Append( $NewPadding).Append( $item).Append(': ').Append((ConvertTo-PodeYamlInternal -InputObject $InputObject[$item] -Depth $Depth -NestingLevel ($NestingLevel + $increment))) } $string.ToString() - break - } - 'int32' { - $InputObject } - 'double' { - $InputObject + else { '{}' } + break + } + 'pscustomobject' { + if ($InputObject.Count -gt 0 ) { + $index = 0 + $string = [System.Text.StringBuilder]::new() + foreach ($item in ($InputObject | Get-Member -MemberType Properties | Select-Object -ExpandProperty Name)) { + if ($InputObject.$item -is [string]) { $increment = 2 } else { $increment = 1 } + if ($NoNewLine -and $index++ -eq 0) { $NewPadding = '' } else { $NewPadding = "`n$padding" } + $null = $string.Append( $NewPadding).Append( $item).Append(': ').Append((ConvertTo-PodeYamlInternal -InputObject $InputObject.$item -Depth $Depth -NestingLevel ($NestingLevel + $increment))) + } + $string.ToString() } - default { - "'$InputObject'" + else { '{}' } + break + } + 'boolean' { + if ($InputObject -eq $true) { 'true' } else { 'false' } + break + } + 'array' { + $string = [System.Text.StringBuilder]::new() + $index = 0 + foreach ($item in $InputObject ) { + if ($NoNewLine -and $index++ -eq 0) { $NewPadding = '' } else { $NewPadding = "`n$padding" } + $null = $string.Append($NewPadding).Append('- ').Append((ConvertTo-PodeYamlInternal -InputObject $item -depth $Depth -NestingLevel ($NestingLevel + 1) -NoNewLine)) } + $string.ToString() + break + } + 'int32' { + $InputObject + } + 'double' { + $InputObject + } + 'single' { + $InputObject + } + default { + "'$InputObject'" } - return $Output - } - catch { - $_ | Write-PodeErrorLog - $_.Exception | Write-PodeErrorLog -CheckInnerException - throw "Error'$($_)' in script $($_.InvocationInfo.ScriptName) $($_.InvocationInfo.Line.Trim()) (line $($_.InvocationInfo.ScriptLineNumber)) char $($_.InvocationInfo.OffsetInLine) executing $($_.InvocationInfo.MyCommand) on $type object '$($InputObject)' Class: $($InputObject.GetType().Name) BaseClass: $($InputObject.GetType().BaseType.Name) " } + return $Output + } + catch { + $_ | Write-PodeErrorLog + $_.Exception | Write-PodeErrorLog -CheckInnerException + throw "Error'$($_)' in script $($_.InvocationInfo.ScriptName) $($_.InvocationInfo.Line.Trim()) (line $($_.InvocationInfo.ScriptLineNumber)) char $($_.InvocationInfo.OffsetInLine) executing $($_.InvocationInfo.MyCommand) on $type object '$($InputObject)' Class: $($InputObject.GetType().Name) BaseClass: $($InputObject.GetType().BaseType.Name) " } } @@ -3364,16 +3395,16 @@ function Resolve-PodeObjectArray { else { # If the hashtable has more than one item, recursively resolve each item return @(foreach ($p in $Property) { - Resolve-PodeObjectArray -Property $p - }) + Resolve-PodeObjectArray -Property $p + }) } } # Check if the property is an array of objects elseif ($Property -is [object[]]) { # Recursively resolve each item in the array return @(foreach ($p in $Property) { - Resolve-PodeObjectArray -Property $p - }) + Resolve-PodeObjectArray -Property $p + }) } # Check if the property is already a PowerShell object elseif ($Property -is [psobject]) { From 30c90298bab0d28521ae0cb35144292fa0e43574 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 31 May 2024 09:19:41 -0700 Subject: [PATCH 013/177] Fix OpenApi extenal route Remove an unwanted character from the $pm variable add some comments and headers --- examples/OpenApiTuttiFrutti.ps1 | 4 +-- src/Private/OpenApi.ps1 | 63 ++++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/examples/OpenApiTuttiFrutti.ps1 b/examples/OpenApiTuttiFrutti.ps1 index 691c1043b..7e6c7fb97 100644 --- a/examples/OpenApiTuttiFrutti.ps1 +++ b/examples/OpenApiTuttiFrutti.ps1 @@ -965,8 +965,8 @@ Some useful links: } - $yaml = PodeOADefinition -Format Yaml -DefinitionTag 'v3.1' - $json = PodeOADefinition -Format Json -DefinitionTag 'v3' + $yaml = Get-PodeOADefinition -Format Yaml -DefinitionTag 'v3.1' + $json = Get-PodeOADefinition -Format Json -DefinitionTag 'v3' Write-PodeHost "`rYAML Tag: v3.1 Output:`r $yaml" diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index c0c14be1b..571ec1dc1 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -1109,13 +1109,31 @@ function Get-PodeOpenApiDefinitionInternal { } $pm = Set-PodeOpenApiRouteValue -Route $_route -DefinitionTag $DefinitionTag # add path's http method to defintition - $def.paths[$_route.OpenAPI.Path][$method.ToLower()] = $pmF + $def.paths[$_route.OpenAPI.Path][$method.ToLower()] = $pm } } } return $def } +<# +.SYNOPSIS + Converts a cmdlet parameter to a Pode OpenAPI property. + +.DESCRIPTION + This internal function takes a cmdlet parameter and converts it into an appropriate Pode OpenAPI property based on its type. + The function supports boolean, integer, float, and string parameter types. + +.PARAMETER Parameter + The cmdlet parameter metadata that needs to be converted. This parameter is mandatory and accepts values from the pipeline. + +.EXAMPLE + $metadata = Get-Command -Name Get-Process | Select-Object -ExpandProperty Parameters + $metadata.Values | ConvertTo-PodeOAPropertyFromCmdletParameter + +.NOTES + This is an internal function and may change in future releases of Pode. +#> function ConvertTo-PodeOAPropertyFromCmdletParameter { param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] @@ -1411,6 +1429,33 @@ function Set-PodeOAGlobalAuth { } } +<# +.SYNOPSIS + Resolves references in a Pode OpenAPI component schema. + +.DESCRIPTION + This internal function resolves `$ref` references in a Pode OpenAPI component schema, replacing them with the actual schema definitions. + It supports `allOf` references and ensures that nested objects and references are resolved appropriately. + +.PARAMETER ComponentSchema + The hashtable representing the component schema with potential references to be resolved. This parameter is mandatory and accepts values from the pipeline. + +.PARAMETER DefinitionTag + The tag used to identify the OpenAPI definition in the Pode context. This parameter is mandatory. + +.EXAMPLE + $schema = @{ + properties = @{ + prop1 = @{ + '$ref' = '#/components/schemas/ReferencedSchema' + } + } + } + Resolve-PodeOAReference -ComponentSchema $schema -DefinitionTag 'MyDefinition' + +.NOTES + This is an internal function and may change in future releases of Pode. +#> function Resolve-PodeOAReference { param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] @@ -1423,27 +1468,36 @@ function Resolve-PodeOAReference { ) begin { + # Retrieve the schema definitions from the Pode context $Schemas = $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.schemaJson + # Initialize an array to store the keys of the properties to process $Keys = @() } process { + # If the schema has properties, add their keys to the $Keys array if ($ComponentSchema.properties) { foreach ($item in $ComponentSchema.properties.Keys) { $Keys += $item } } + + # Add keys for any 'allOf', 'oneOf', or 'anyOf' properties to the $Keys array foreach ($item in $ComponentSchema.Keys) { if ( @('allof', 'oneof', 'anyof') -icontains $item ) { $Keys += $item } } + # Process each key in the $Keys array foreach ($key in $Keys) { if ( @('allof', 'oneof', 'anyof') -icontains $key ) { if ($key -ieq 'allof') { + # Initialize an array to hold temporary properties $tmpProp = @() + # Process each component in the 'allOf' array foreach ( $comp in $ComponentSchema[$key] ) { + # If the component is a reference, resolve it if ($comp.'$ref') { if (($comp.'$ref').StartsWith('#/components/schemas/')) { $refName = ($comp.'$ref') -replace '#/components/schemas/', '' @@ -1453,6 +1507,7 @@ function Resolve-PodeOAReference { } } elseif ( $comp.properties) { + # If the component has properties, resolve them recursively if ($comp.type -eq 'object') { $tmpProp += Resolve-PodeOAReference -DefinitionTag $DefinitionTag -ComponentSchema$comp } @@ -1462,8 +1517,10 @@ function Resolve-PodeOAReference { } } + # Set the schema type to 'object' and remove the 'allOf' key $ComponentSchema.type = 'object' $ComponentSchema.remove('allOf') + # Add the properties from the resolved components if ($tmpProp.count -gt 0) { foreach ($t in $tmpProp) { $ComponentSchema.properties += $t.properties @@ -1478,9 +1535,11 @@ function Resolve-PodeOAReference { throw 'Validation of schema with anyof is not supported' } } + # If the property type is 'object', resolve its properties recursively elseif ($ComponentSchema.properties[$key].type -eq 'object') { $ComponentSchema.properties[$key].properties = Resolve-PodeOAReference -DefinitionTag $DefinitionTag -ComponentSchema $ComponentSchema.properties[$key].properties } + # If the property is a reference, resolve it elseif ($ComponentSchema.properties[$key].'$ref') { if (($ComponentSchema.properties[$key].'$ref').StartsWith('#/components/schemas/')) { $refName = ($ComponentSchema.properties[$key].'$ref') -replace '#/components/schemas/', '' @@ -1489,6 +1548,7 @@ function Resolve-PodeOAReference { } } } + # If the property has items and the items are references, resolve them elseif ($ComponentSchema.properties[$key].items -and $ComponentSchema.properties[$key].items.'$ref' ) { if (($ComponentSchema.properties[$key].items.'$ref').StartsWith('#/components/schemas/')) { $refName = ($ComponentSchema.properties[$key].items.'$ref') -replace '#/components/schemas/', '' @@ -1501,6 +1561,7 @@ function Resolve-PodeOAReference { } end { + # Return the resolved component schema return $ComponentSchema } } From b3f3d408a788181bbae8c4471c437408170ecba1 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 31 May 2024 09:41:13 -0700 Subject: [PATCH 014/177] improvement and yaml test fix --- src/Private/Helpers.ps1 | 2 +- src/Public/Responses.ps1 | 10 +++--- tests/unit/Helpers.Tests.ps1 | 66 ++++++++++++++++++++++++++++++++---- 3 files changed, 66 insertions(+), 12 deletions(-) diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index d9c409e6d..2d8529576 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -3120,7 +3120,7 @@ function ConvertTo-PodeYaml { if ($null -eq $PodeContext.Server.InternalCache.YamlModuleImported) { $PodeContext.Server.InternalCache.YamlModuleImported = ((Test-PodeModuleInstalled -Name 'PSYaml') -or (Test-PodeModuleInstalled -Name 'powershell-yaml')) } - if ($pipelineObject) { + if ($pipelineObject -and $pipelineObject.Count -gt 1) { $InputObject = $pipelineObject } diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index 4fc103ef6..6a6b50b1f 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -474,7 +474,7 @@ function Write-PodeCsvResponse { } 'value' { - if ($pipelineValue) { + if ($pipelineValue -and $pipelineValue.Count -gt 1) { $Value = $pipelineValue } @@ -560,7 +560,7 @@ function Write-PodeHtmlResponse { } 'value' { - if ($pipelineValue) { + if ($pipelineValue -and $pipelineValue.Count -gt 1) { $Value = $pipelineValue } if ($Value -isnot [string]) { @@ -724,7 +724,7 @@ function Write-PodeJsonResponse { } 'value' { - if ($pipelineValue) { + if ($pipelineValue -and $pipelineValue.Count -gt 1) { $Value = $pipelineValue } if ($Value -isnot [string]) { @@ -831,7 +831,7 @@ function Write-PodeXmlResponse { } 'value' { - if ($pipelineValue) { + if ($pipelineValue -and $pipelineValue.Count -gt 1) { $Value = $pipelineValue } @@ -928,7 +928,7 @@ function Write-PodeYamlResponse { } 'value' { - if ($pipelineValue) { + if ($pipelineValue -and $pipelineValue.Count -gt 1) { $Value = $pipelineValue } diff --git a/tests/unit/Helpers.Tests.ps1 b/tests/unit/Helpers.Tests.ps1 index d80e5c543..adee1afb3 100644 --- a/tests/unit/Helpers.Tests.ps1 +++ b/tests/unit/Helpers.Tests.ps1 @@ -1717,21 +1717,75 @@ Describe 'New-PodeCron' { + +Describe 'ConvertTo-PodeYaml Tests' { + BeforeAll { + $PodeContext = @{ Server = @{InternalCache = @{} } } + } + Context 'When converting basic types' { + It 'Converts strings correctly' { + $result = 'hello world' | ConvertTo-PodeYaml + $result | Should -Be 'hello world' + } + + It 'Converts arrays correctly' { + $result = @('one', 'two', 'three') | ConvertTo-PodeYaml + $expected = (@' +- one +- two +- three +'@) + $result | Should -Be ($expected.Trim() -Replace "`r`n", "`n") + } + + It 'Converts hashtables correctly' { + $hashTable = [ordered]@{ + key1 = 'value1' + key2 = 'value2' + } + $result = $hashTable | ConvertTo-PodeYaml + $result | Should -Be "key1: value1`nkey2: value2" + } + } + + Context 'When converting complex objects' { + It 'Handles nested hashtables' { + $nestedHash = @{ + parent = @{ + child = 'value' + } + } + $result = $nestedHash | ConvertTo-PodeYaml + + $result | Should -Be "parent: `n child: value" + } + } + + Context 'Error handling' { + It 'Returns empty string for null input' { + $result = $null | ConvertTo-PodeYaml + $result | Should -Be '' + } + } +} + + Describe 'ConvertTo-PodeYamlInternal Tests' { Context 'When converting basic types' { It 'Converts strings correctly' { - $result = 'hello world' | ConvertTo-PodeYamlInternal + + $result = ConvertTo-PodeYamlInternal -InputObject 'hello world' $result | Should -Be 'hello world' } It 'Converts arrays correctly' { - $result = ConvertTo-PodeYamlInternal -InputObject @('one', 'two', 'three') -NoNewLine + $result = ConvertTo-PodeYamlInternal -InputObject @('one', 'two', 'three') -NoNewLine $expected = (@' - one - two - three '@) - $result | Should -Be ($expected.Trim() -Replace "`r`n","`n") + $result | Should -Be ($expected.Trim() -Replace "`r`n", "`n") } It 'Converts hashtables correctly' { @@ -1739,7 +1793,7 @@ Describe 'ConvertTo-PodeYamlInternal Tests' { key1 = 'value1' key2 = 'value2' } - $result = $hashTable | ConvertTo-PodeYamlInternal -NoNewLine + $result = ConvertTo-PodeYamlInternal -InputObject $hashTable -NoNewLine $result | Should -Be "key1: value1`nkey2: value2" } } @@ -1751,7 +1805,7 @@ Describe 'ConvertTo-PodeYamlInternal Tests' { child = 'value' } } - $result = $nestedHash | ConvertTo-PodeYamlInternal -NoNewLine + $result = ConvertTo-PodeYamlInternal -InputObject $nestedHash -NoNewLine $result | Should -Be "parent: `n child: value" } @@ -1759,7 +1813,7 @@ Describe 'ConvertTo-PodeYamlInternal Tests' { Context 'Error handling' { It 'Returns empty string for null input' { - $result = $null | ConvertTo-PodeYamlInternal + $result = ConvertTo-PodeYamlInternal -InputObject $null $result | Should -Be '' } } From 5b44b18a1cc9824bcc71c923ce34eea82058e0f4 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 31 May 2024 10:49:52 -0700 Subject: [PATCH 015/177] remove redundant check --- src/Private/Helpers.ps1 | 2 +- src/Public/Responses.ps1 | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index 2d8529576..bd966925b 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -3120,7 +3120,7 @@ function ConvertTo-PodeYaml { if ($null -eq $PodeContext.Server.InternalCache.YamlModuleImported) { $PodeContext.Server.InternalCache.YamlModuleImported = ((Test-PodeModuleInstalled -Name 'PSYaml') -or (Test-PodeModuleInstalled -Name 'powershell-yaml')) } - if ($pipelineObject -and $pipelineObject.Count -gt 1) { + if ($pipelineObject.Count -gt 1) { $InputObject = $pipelineObject } diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index 6a6b50b1f..b3b2b9d8c 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -474,7 +474,7 @@ function Write-PodeCsvResponse { } 'value' { - if ($pipelineValue -and $pipelineValue.Count -gt 1) { + if ($pipelineValue.Count -gt 1) { $Value = $pipelineValue } @@ -560,7 +560,7 @@ function Write-PodeHtmlResponse { } 'value' { - if ($pipelineValue -and $pipelineValue.Count -gt 1) { + if ($pipelineValue.Count -gt 1) { $Value = $pipelineValue } if ($Value -isnot [string]) { @@ -724,7 +724,7 @@ function Write-PodeJsonResponse { } 'value' { - if ($pipelineValue -and $pipelineValue.Count -gt 1) { + if ($pipelineValue.Count -gt 1) { $Value = $pipelineValue } if ($Value -isnot [string]) { @@ -831,7 +831,7 @@ function Write-PodeXmlResponse { } 'value' { - if ($pipelineValue -and $pipelineValue.Count -gt 1) { + if ($pipelineValue.Count -gt 1) { $Value = $pipelineValue } @@ -928,7 +928,7 @@ function Write-PodeYamlResponse { } 'value' { - if ($pipelineValue -and $pipelineValue.Count -gt 1) { + if ($pipelineValue.Count -gt 1) { $Value = $pipelineValue } From e0d94b3d59789794d3f1b321bc263d729777bd2b Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Fri, 31 May 2024 18:55:57 +0100 Subject: [PATCH 016/177] applies fix for PS7.5 bug with Remove-Item --- pode.build.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pode.build.ps1 b/pode.build.ps1 index 6fa324e7b..15b851219 100644 --- a/pode.build.ps1 +++ b/pode.build.ps1 @@ -15,6 +15,9 @@ param( $ReleaseNoteVersion ) +# Fix for PS7.5 Preview - https://github.com/PowerShell/PowerShell/issues/23868 +$ProgressPreference = 'SilentlyContinue' + <# # Dependency Versions #> From 780496afc847df4066a1ec1484a672101226112f Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Fri, 31 May 2024 19:08:12 +0100 Subject: [PATCH 017/177] #1039: fix build error when dotnet tries to restore from offline nuget cache --- src/Listener/NuGet.config | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/Listener/NuGet.config diff --git a/src/Listener/NuGet.config b/src/Listener/NuGet.config new file mode 100644 index 000000000..83a2e372f --- /dev/null +++ b/src/Listener/NuGet.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 53688f07cc21edb42d1db89de12a304e3c9bbb43 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 31 May 2024 15:30:14 -0700 Subject: [PATCH 018/177] Korean language Add Korean additional messages migrated added a new UICulture property to the module `Import-Module -Name "Pode" -ArgumentList @{UICulture ='ko-KR'}` failback to English if culture doesn't exist --- src/Locales/ar/Pode.psd1 | 32 ++++++++ src/Locales/de/Pode.psd1 | 33 +++++++- src/Locales/en/Pode.psd1 | 31 ++++++++ src/Locales/es/Pode.psd1 | 33 +++++++- src/Locales/fr/Pode.psd1 | 33 +++++++- src/Locales/it/Pode.psd1 | 32 ++++++++ src/Locales/ja/Pode.psd1 | 33 +++++++- src/Locales/kr/Pode.psd1 | 119 ++++++++++++++++++++++++++++ src/Locales/pl/Pode.psd1 | 33 +++++++- src/Locales/pt/Pode.psd1 | 33 +++++++- src/Locales/zn/Pode.psd1 | 33 +++++++- src/Pode.psm1 | 89 +++++++++++++++++---- src/Private/Helpers.ps1 | 2 +- src/Public/Authentication.ps1 | 88 ++++++++++---------- src/Public/AutoImport.ps1 | 2 +- src/Public/Events.ps1 | 4 +- tests/unit/Authentication.Tests.ps1 | 4 +- 17 files changed, 560 insertions(+), 74 deletions(-) create mode 100644 src/Locales/kr/Pode.psd1 diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index ad6ea3766..840103194 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -85,4 +85,36 @@ accessMethodNotExistForMergingExceptionMessage = طريقة الوصول غير routeAlreadyContainsCustomAccessExceptionMessage = المسار '[{0}] {1}' يحتوي بالفعل على وصول مخصص باسم '{2}' accessMethodNotExistExceptionMessage = طريقة الوصول غير موجودة: {0} pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = ميزة PathItems غير مدعومة في OpenAPI v3.0.x +nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = مطلوب ScriptBlock غير فارغ لخطة المصادقة المخصصة. +oauth2InnerSchemeInvalidExceptionMessage = يمكن أن تكون OAuth2 InnerScheme إما مصادقة Basic أو Form فقط، ولكن تم الحصول على: {0} +sessionsRequiredForOAuth2WithPKCEExceptionMessage = تتطلب OAuth2 مع PKCE جلسات. +oauth2ClientSecretRequiredExceptionMessage = تتطلب OAuth2 سر العميل عند عدم استخدام PKCE. +authMethodAlreadyDefinedExceptionMessage = طريقة المصادقة محددة بالفعل: {0} +invalidSchemeForAuthValidatorExceptionMessage = تتطلب الخطة '{0}' المقدمة لمحقق المصادقة '{1}' ScriptBlock صالح. +sessionsRequiredForSessionPersistentAuthExceptionMessage = تتطلب المصادقة المستمرة للجلسة جلسات. +oauth2RequiresAuthorizeUrlExceptionMessage = تتطلب OAuth2 توفير عنوان URL للتفويض. +authMethodNotExistForMergingExceptionMessage = طريقة المصادقة غير موجودة للدمج: {0} +mergeDefaultAuthNotInListExceptionMessage = المصادقة MergeDefault '{0}' غير موجودة في قائمة المصادقة المقدمة. +defaultAuthNotInListExceptionMessage = المصادقة الافتراضية '{0}' غير موجودة في قائمة المصادقة المقدمة. +scriptBlockRequiredForMergingUsersExceptionMessage = مطلوب ScriptBlock لدمج عدة مستخدمين مصادق عليهم في كائن واحد عندما تكون Valid هي All. +noDomainServerNameForWindowsAdAuthExceptionMessage = لم يتم توفير اسم خادم المجال لمصادقة Windows AD. +sessionsNotConfiguredExceptionMessage = لم يتم تكوين الجلسات. +windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = دعم المصادقة المحلية لـ Windows هو فقط لنظام Windows. +iisAuthSupportIsForWindowsOnlyExceptionMessage = دعم مصادقة IIS هو فقط لنظام Windows. +noAlgorithmInJwtHeaderExceptionMessage = لم يتم توفير أي خوارزمية في رأس JWT. +invalidJwtSuppliedExceptionMessage = JWT المقدم غير صالح. +invalidJwtHeaderAlgorithmSuppliedExceptionMessage = خوارزمية رأس JWT المقدمة غير صالحة. +noJwtSignatureForAlgorithmExceptionMessage = لم يتم توفير توقيع JWT لـ {0}. +expectedNoJwtSignatureSuppliedExceptionMessage = لم يكن من المتوقع توفير توقيع JWT. +invalidJwtSignatureSuppliedExceptionMessage = توقيع JWT المقدم غير صالح. +jwtExpiredExceptionMessage = انتهت صلاحية JWT. +jwtNotYetValidExceptionMessage = JWT غير صالح للاستخدام بعد. +snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Snapins مدعومة فقط في Windows PowerShell. +userFileDoesNotExistExceptionMessage = ملف المستخدم غير موجود: {0} +schemeRequiresValidScriptBlockExceptionMessage = تتطلب الخطة المقدمة لمحقق المصادقة '{0}' ScriptBlock صالح. +oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = مزود OAuth2 لا يدعم نوع الاستجابة 'code'. +oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = مزود OAuth2 لا يدعم نوع المنحة 'password' المطلوبة لاستخدام InnerScheme. +eventAlreadyRegisteredExceptionMessage = الحدث {0} مسجل بالفعل: {1} +noEventRegisteredExceptionMessage = لا يوجد حدث {0} مسجل: {1} '@ + diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index 5776e7c5b..ab5cca0e3 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -85,4 +85,35 @@ accessMethodNotExistForMergingExceptionMessage = Zugriffsmethode zum Zusammenfü routeAlreadyContainsCustomAccessExceptionMessage = Die Route '[{0}] {1}' enthält bereits einen benutzerdefinierten Zugriff mit dem Namen '{2}'. accessMethodNotExistExceptionMessage = Zugriffsmethode nicht vorhanden: {0}. pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = Das PathItems-Feature wird in OpenAPI v3.0.x nicht unterstützt. -'@ \ No newline at end of file +nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = Ein nicht leerer ScriptBlock ist für das benutzerdefinierte Authentifizierungsschema erforderlich. +oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme kann nur entweder Basic oder Form-Authentifizierung sein, aber erhalten: {0} +sessionsRequiredForOAuth2WithPKCEExceptionMessage = Sitzungen sind erforderlich, um OAuth2 mit PKCE zu verwenden. +oauth2ClientSecretRequiredExceptionMessage = OAuth2 erfordert ein Client Secret, wenn PKCE nicht verwendet wird. +authMethodAlreadyDefinedExceptionMessage = Authentifizierungsmethode bereits definiert: {0} +invalidSchemeForAuthValidatorExceptionMessage = Das bereitgestellte '{0}'-Schema für den Authentifizierungsvalidator '{1}' erfordert einen gültigen ScriptBlock. +sessionsRequiredForSessionPersistentAuthExceptionMessage = Sitzungen sind erforderlich, um die sitzungsbeständige Authentifizierung zu verwenden. +oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 erfordert die Angabe einer Autorisierungs-URL. +authMethodNotExistForMergingExceptionMessage = Die Authentifizierungsmethode existiert nicht zum Zusammenführen: {0} +mergeDefaultAuthNotInListExceptionMessage = Die MergeDefault-Authentifizierung '{0}' befindet sich nicht in der angegebenen Authentifizierungsliste. +defaultAuthNotInListExceptionMessage = Die Standardauthentifizierung '{0}' befindet sich nicht in der angegebenen Authentifizierungsliste. +scriptBlockRequiredForMergingUsersExceptionMessage = Ein ScriptBlock ist erforderlich, um mehrere authentifizierte Benutzer zu einem Objekt zusammenzuführen, wenn Valid All ist. +noDomainServerNameForWindowsAdAuthExceptionMessage = Es wurde kein Domänenservername für die Windows-AD-Authentifizierung angegeben. +sessionsNotConfiguredExceptionMessage = Sitzungen wurden nicht konfiguriert. +windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Die Unterstützung der lokalen Windows-Authentifizierung gilt nur für Windows. +iisAuthSupportIsForWindowsOnlyExceptionMessage = Die IIS-Authentifizierungsunterstützung gilt nur für Windows. +noAlgorithmInJwtHeaderExceptionMessage = Kein Algorithmus im JWT-Header angegeben. +invalidJwtSuppliedExceptionMessage = Ungültiger JWT angegeben. +invalidJwtHeaderAlgorithmSuppliedExceptionMessage = Ungültiger JWT-Header-Algorithmus angegeben. +noJwtSignatureForAlgorithmExceptionMessage = Keine JWT-Signatur für {0} angegeben. +expectedNoJwtSignatureSuppliedExceptionMessage = Es wurde keine JWT-Signatur erwartet. +invalidJwtSignatureSuppliedExceptionMessage = Ungültige JWT-Signatur angegeben. +jwtExpiredExceptionMessage = Der JWT ist abgelaufen. +jwtNotYetValidExceptionMessage = Der JWT ist noch nicht gültig. +snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Snapins werden nur in Windows PowerShell unterstützt. +userFileDoesNotExistExceptionMessage = Die Benutzerdaten-Datei existiert nicht: {0} +schemeRequiresValidScriptBlockExceptionMessage = Das bereitgestellte Schema für den Authentifizierungsvalidator '{0}' erfordert einen gültigen ScriptBlock. +oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = Der OAuth2-Anbieter unterstützt den 'code'-Antworttyp nicht. +oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = Der OAuth2-Anbieter unterstützt den für die Verwendung eines InnerScheme erforderlichen 'password'-Grant-Typ nicht. +eventAlreadyRegisteredExceptionMessage = Ereignis {0} bereits registriert: {1} +noEventRegisteredExceptionMessage = Kein Ereignis {0} registriert: {1} +'@ diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 8acaf4230..d2df449f0 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -85,4 +85,35 @@ accessMethodNotExistForMergingExceptionMessage = Access method does not exist fo routeAlreadyContainsCustomAccessExceptionMessage = Route '[{0}] {1}' already contains Custom Access with name '{2}' accessMethodNotExistExceptionMessage = Access method does not exist: {0} pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = The PathItems feature is not supported in OpenAPI v3.0.x +nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = A non-empty ScriptBlock is required for the Custom authentication scheme. +oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme can only be one of either Basic or Form authentication, but got: {0} +sessionsRequiredForOAuth2WithPKCEExceptionMessage = Sessions are required to use OAuth2 with PKCE +oauth2ClientSecretRequiredExceptionMessage = OAuth2 requires a Client Secret when not using PKCE. +authMethodAlreadyDefinedExceptionMessage = Authentication method already defined: {0} +invalidSchemeForAuthValidatorExceptionMessage = The supplied '{0}' Scheme for the '{1}' authentication validator requires a valid ScriptBlock. +sessionsRequiredForSessionPersistentAuthExceptionMessage = Sessions are required to use session persistent authentication. +oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 requires an Authorize URL to be supplied +authMethodNotExistForMergingExceptionMessage = Authentication method does not exist for merging: {0} +mergeDefaultAuthNotInListExceptionMessage = The MergeDefault Authentication '{0}' is not in the Authentication list supplied. +defaultAuthNotInListExceptionMessage = The Default Authentication '{0}' is not in the Authentication list supplied. +scriptBlockRequiredForMergingUsersExceptionMessage = A Scriptblock for merging multiple authenticated users into 1 object is required When Valid is All. +noDomainServerNameForWindowsAdAuthExceptionMessage = No domain server name has been supplied for Windows AD authentication +sessionsNotConfiguredExceptionMessage = Sessions have not been configured. +windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Windows Local Authentication support is for Windows only. +iisAuthSupportIsForWindowsOnlyExceptionMessage = IIS Authentication support is for Windows only. +noAlgorithmInJwtHeaderExceptionMessage = No algorithm supplied in JWT Header. +invalidJwtSuppliedExceptionMessage = Invalid JWT supplied. +invalidJwtHeaderAlgorithmSuppliedExceptionMessage = Invalid JWT header algorithm supplied. +noJwtSignatureForAlgorithmExceptionMessage = No JWT signature supplied for {0}. +expectedNoJwtSignatureSuppliedExceptionMessage = Expected no JWT signature to be supplied. +invalidJwtSignatureSuppliedExceptionMessage = Invalid JWT signature supplied. +jwtExpiredExceptionMessage = The JWT has expired. +jwtNotYetValidExceptionMessage = The JWT is not yet valid for use. +snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Snapins are only supported on Windows PowerShell. +userFileDoesNotExistExceptionMessage = The user file does not exist: {0} +schemeRequiresValidScriptBlockExceptionMessage = The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock. +oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = The OAuth2 provider does not support the 'code' response_type. +oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = The OAuth2 provider does not support the 'password' grant_type required by using an InnerScheme. +eventAlreadyRegisteredExceptionMessage = {0} event already registered: {1} +noEventRegisteredExceptionMessage = No {0} event registered: {1} '@ \ No newline at end of file diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index c670efd3e..237fec72f 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -85,4 +85,35 @@ accessMethodNotExistForMergingExceptionMessage = El método de acceso no existe routeAlreadyContainsCustomAccessExceptionMessage = La ruta '[{0}] {1}' ya contiene acceso personalizado con el nombre '{2}' accessMethodNotExistExceptionMessage = El método de acceso no existe: {0} pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = La función de elementos de ruta no es compatible con OpenAPI v3.0.x -'@ \ No newline at end of file +nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = Se requiere un ScriptBlock no vacío para el esquema de autenticación personalizado. +oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme solo puede ser Basic o Form, pero se obtuvo: {0} +sessionsRequiredForOAuth2WithPKCEExceptionMessage = Se requieren sesiones para usar OAuth2 con PKCE. +oauth2ClientSecretRequiredExceptionMessage = OAuth2 requiere un Client Secret cuando no se usa PKCE. +authMethodAlreadyDefinedExceptionMessage = Método de autenticación ya definido: {0} +invalidSchemeForAuthValidatorExceptionMessage = El esquema '{0}' proporcionado para el validador de autenticación '{1}' requiere un ScriptBlock válido. +sessionsRequiredForSessionPersistentAuthExceptionMessage = Se requieren sesiones para usar la autenticación persistente de sesión. +oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 requiere que se proporcione una URL de autorización. +authMethodNotExistForMergingExceptionMessage = El método de autenticación no existe para la fusión: {0} +mergeDefaultAuthNotInListExceptionMessage = La autenticación MergeDefault '{0}' no está en la lista de autenticación proporcionada. +defaultAuthNotInListExceptionMessage = La autenticación predeterminada '{0}' no está en la lista de autenticación proporcionada. +scriptBlockRequiredForMergingUsersExceptionMessage = Se requiere un ScriptBlock para fusionar múltiples usuarios autenticados en un solo objeto cuando Valid es All. +noDomainServerNameForWindowsAdAuthExceptionMessage = No se ha proporcionado un nombre de servidor de dominio para la autenticación AD de Windows. +sessionsNotConfiguredExceptionMessage = Las sesiones no se han configurado. +windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = El soporte de autenticación local de Windows es solo para Windows. +iisAuthSupportIsForWindowsOnlyExceptionMessage = El soporte de autenticación IIS es solo para Windows. +noAlgorithmInJwtHeaderExceptionMessage = No se proporcionó un algoritmo en el encabezado JWT. +invalidJwtSuppliedExceptionMessage = JWT proporcionado no válido. +invalidJwtHeaderAlgorithmSuppliedExceptionMessage = Algoritmo del encabezado JWT proporcionado no válido. +noJwtSignatureForAlgorithmExceptionMessage = No se proporcionó una firma JWT para {0}. +expectedNoJwtSignatureSuppliedExceptionMessage = No se esperaba que se proporcionara una firma JWT. +invalidJwtSignatureSuppliedExceptionMessage = Firma JWT proporcionada no válida. +jwtExpiredExceptionMessage = El JWT ha expirado. +jwtNotYetValidExceptionMessage = El JWT aún no es válido. +snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Los Snapins solo son compatibles con Windows PowerShell. +userFileDoesNotExistExceptionMessage = El archivo de usuario no existe: {0} +schemeRequiresValidScriptBlockExceptionMessage = El esquema proporcionado para el validador de autenticación '{0}' requiere un ScriptBlock válido. +oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = El proveedor de OAuth2 no admite el tipo de respuesta 'code'. +oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = El proveedor de OAuth2 no admite el tipo de concesión 'password' requerido al usar un InnerScheme. +eventAlreadyRegisteredExceptionMessage = Evento {0} ya registrado: {1} +noEventRegisteredExceptionMessage = No hay evento {0} registrado: {1} +'@ diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index bc41e11a4..b3da880c2 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -85,4 +85,35 @@ accessMethodNotExistForMergingExceptionMessage = La méthode d'accès n'existe p routeAlreadyContainsCustomAccessExceptionMessage = La route '[{0}] {1}' contient déjà un accès personnalisé avec le nom '{2}' accessMethodNotExistExceptionMessage = La méthode d'accès n'existe pas : {0} pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = La fonction PathItems n'est pas prise en charge dans OpenAPI v3.0.x -'@ \ No newline at end of file +nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = Un ScriptBlock non vide est requis pour le schéma d'authentification personnalisé. +oauth2InnerSchemeInvalidExceptionMessage = Le OAuth2 InnerScheme ne peut être que Basic ou Form, mais obtenu : {0} +sessionsRequiredForOAuth2WithPKCEExceptionMessage = Des sessions sont nécessaires pour utiliser OAuth2 avec PKCE. +oauth2ClientSecretRequiredExceptionMessage = OAuth2 nécessite un Client Secret lorsque PKCE n'est pas utilisé. +authMethodAlreadyDefinedExceptionMessage = Méthode d'authentification déjà définie : {0} +invalidSchemeForAuthValidatorExceptionMessage = Le schéma '{0}' fourni pour le validateur d'authentification '{1}' nécessite un ScriptBlock valide. +sessionsRequiredForSessionPersistentAuthExceptionMessage = Des sessions sont nécessaires pour utiliser l'authentification persistante par session. +oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 nécessite une URL d'autorisation. +authMethodNotExistForMergingExceptionMessage = La méthode d'authentification n'existe pas pour la fusion : {0} +mergeDefaultAuthNotInListExceptionMessage = L'authentification MergeDefault '{0}' n'est pas dans la liste d'authentification fournie. +defaultAuthNotInListExceptionMessage = L'authentification par défaut '{0}' n'est pas dans la liste d'authentification fournie. +scriptBlockRequiredForMergingUsersExceptionMessage = Un ScriptBlock est requis pour fusionner plusieurs utilisateurs authentifiés en un seul objet lorsque Valid est All. +noDomainServerNameForWindowsAdAuthExceptionMessage = Aucun nom de serveur de domaine n'a été fourni pour l'authentification Windows AD. +sessionsNotConfiguredExceptionMessage = Les sessions n'ont pas été configurées. +windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Le support de l'authentification locale Windows est uniquement pour Windows. +iisAuthSupportIsForWindowsOnlyExceptionMessage = Le support de l'authentification IIS est uniquement pour Windows. +noAlgorithmInJwtHeaderExceptionMessage = Aucun algorithme fourni dans l'en-tête JWT. +invalidJwtSuppliedExceptionMessage = JWT fourni invalide. +invalidJwtHeaderAlgorithmSuppliedExceptionMessage = Algorithme de l'en-tête JWT fourni invalide. +noJwtSignatureForAlgorithmExceptionMessage = Aucune signature JWT fournie pour {0}. +expectedNoJwtSignatureSuppliedExceptionMessage = Aucune signature JWT n'était attendue. +invalidJwtSignatureSuppliedExceptionMessage = Signature JWT fournie invalide. +jwtExpiredExceptionMessage = Le JWT a expiré. +jwtNotYetValidExceptionMessage = Le JWT n'est pas encore valide pour une utilisation. +snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Les Snapins sont uniquement pris en charge sur Windows PowerShell. +userFileDoesNotExistExceptionMessage = Le fichier utilisateur n'existe pas : {0} +schemeRequiresValidScriptBlockExceptionMessage = Le schéma fourni pour le validateur d'authentification '{0}' nécessite un ScriptBlock valide. +oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = Le fournisseur OAuth2 ne supporte pas le type de réponse 'code'. +oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = Le fournisseur OAuth2 ne supporte pas le type de subvention 'password' requis par l'utilisation d'un InnerScheme. +eventAlreadyRegisteredExceptionMessage = Événement {0} déjà enregistré : {1} +noEventRegisteredExceptionMessage = Aucun événement {0} enregistré : {1} +'@ diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index b9b2418d4..32ecfe5ff 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -85,4 +85,36 @@ accessMethodNotExistForMergingExceptionMessage = Il metodo di accesso non esiste routeAlreadyContainsCustomAccessExceptionMessage = Il percorso '[{0}] {1}' contiene già un accesso personalizzato con nome '{2}' accessMethodNotExistExceptionMessage = Il metodo di accesso non esiste: {0} pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = La funzionalità PathItems non è supportata in OpenAPI v3.0.x +nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = È richiesto uno ScriptBlock non vuoto per lo schema di autenticazione personalizzato. +oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme può essere solo uno tra Basic o Form, ma è stato ottenuto: {0} +sessionsRequiredForOAuth2WithPKCEExceptionMessage = Sono necessarie sessioni per utilizzare OAuth2 con PKCE +oauth2ClientSecretRequiredExceptionMessage = OAuth2 richiede un Client Secret quando non si utilizza PKCE. +authMethodAlreadyDefinedExceptionMessage = Metodo di autenticazione già definito: {0} +invalidSchemeForAuthValidatorExceptionMessage = Lo schema '{0}' fornito per il validatore di autenticazione '{1}' richiede uno ScriptBlock valido. +sessionsRequiredForSessionPersistentAuthExceptionMessage = Sono necessarie sessioni per utilizzare l'autenticazione persistente della sessione. +oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 richiede che venga fornita un'URL di autorizzazione +authMethodNotExistForMergingExceptionMessage = Il metodo di autenticazione non esiste per la fusione: {0} +mergeDefaultAuthNotInListExceptionMessage = L'autenticazione MergeDefault '{0}' non è nella lista di autenticazione fornita. +defaultAuthNotInListExceptionMessage = L'autenticazione predefinita '{0}' non è nella lista di autenticazione fornita. +scriptBlockRequiredForMergingUsersExceptionMessage = È richiesto uno ScriptBlock per unire più utenti autenticati in un unico oggetto quando Valid è All. +noDomainServerNameForWindowsAdAuthExceptionMessage = Non è stato fornito alcun nome di server di dominio per l'autenticazione AD di Windows +sessionsNotConfiguredExceptionMessage = Le sessioni non sono state configurate. +windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Il supporto per l'autenticazione locale di Windows è solo per Windows. +iisAuthSupportIsForWindowsOnlyExceptionMessage = Il supporto per l'autenticazione IIS è solo per Windows. +noAlgorithmInJwtHeaderExceptionMessage = Nessun algoritmo fornito nell'header JWT. +invalidJwtSuppliedExceptionMessage = JWT fornito non valido. +invalidJwtHeaderAlgorithmSuppliedExceptionMessage = Algoritmo dell'header JWT fornito non valido. +noJwtSignatureForAlgorithmExceptionMessage = Nessuna firma JWT fornita per {0}. +expectedNoJwtSignatureSuppliedExceptionMessage = Si prevedeva che non fosse fornita alcuna firma JWT. +invalidJwtSignatureSuppliedExceptionMessage = Firma JWT fornita non valida. +jwtExpiredExceptionMessage = JWT è scaduto. +jwtNotYetValidExceptionMessage = JWT non è ancora valido per l'uso. +snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Gli Snapin sono supportati solo su Windows PowerShell. +userFileDoesNotExistExceptionMessage = Il file utente non esiste: {0} +schemeRequiresValidScriptBlockExceptionMessage = Lo schema fornito per il validatore di autenticazione '{0}' richiede uno ScriptBlock valido. +oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = Il provider OAuth2 non supporta il tipo di risposta 'code'. +oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = Il provider OAuth2 non supporta il tipo di concessione 'password' richiesto dall'utilizzo di un InnerScheme. +eventAlreadyRegisteredExceptionMessage = Evento {0} già registrato: {1} +noEventRegisteredExceptionMessage = Nessun evento {0} registrato: {1} '@ + diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index 6204b57b5..fb35ec625 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -85,4 +85,35 @@ accessMethodNotExistForMergingExceptionMessage = マージするアクセス方 routeAlreadyContainsCustomAccessExceptionMessage = ルート '[{0}] {1}' はすでに名前 '{2}' のカスタムアクセスを含んでいます accessMethodNotExistExceptionMessage = アクセス方法が存在しません: {0} pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = PathItems機能はOpenAPI v3.0.xではサポートされていません。 -'@ \ No newline at end of file +nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = カスタム認証スキームには空でないScriptBlockが必要です。 +oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerSchemeはBasicまたはFormのいずれかでなければなりませんが、取得したのは:{0} +sessionsRequiredForOAuth2WithPKCEExceptionMessage = PKCEを使用するOAuth2にはセッションが必要です。 +oauth2ClientSecretRequiredExceptionMessage = PKCEを使用しない場合、OAuth2にはクライアントシークレットが必要です。 +authMethodAlreadyDefinedExceptionMessage = 認証方法はすでに定義されています:{0} +invalidSchemeForAuthValidatorExceptionMessage = '{1}'認証バリデーターのために提供された'{0}'スキームには有効なScriptBlockが必要です。 +sessionsRequiredForSessionPersistentAuthExceptionMessage = セッション持続認証を使用するにはセッションが必要です。 +oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2には認可URLの提供が必要です。 +authMethodNotExistForMergingExceptionMessage = マージするための認証方法は存在しません:{0} +mergeDefaultAuthNotInListExceptionMessage = MergeDefault認証'{0}'は提供された認証リストにありません。 +defaultAuthNotInListExceptionMessage = デフォルト認証'{0}'は提供された認証リストにありません。 +scriptBlockRequiredForMergingUsersExceptionMessage = ValidがAllの場合、複数の認証済みユーザーを1つのオブジェクトにマージするためのScriptBlockが必要です。 +noDomainServerNameForWindowsAdAuthExceptionMessage = Windows AD認証用のドメインサーバー名が提供されていません。 +sessionsNotConfiguredExceptionMessage = セッションが構成されていません。 +windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Windowsローカル認証のサポートはWindowsのみです。 +iisAuthSupportIsForWindowsOnlyExceptionMessage = IIS認証のサポートはWindowsのみです。 +noAlgorithmInJwtHeaderExceptionMessage = JWTヘッダーにアルゴリズムが提供されていません。 +invalidJwtSuppliedExceptionMessage = 無効なJWTが提供されました。 +invalidJwtHeaderAlgorithmSuppliedExceptionMessage = 無効なJWTヘッダーアルゴリズムが提供されました。 +noJwtSignatureForAlgorithmExceptionMessage = {0}のためのJWT署名が提供されていません。 +expectedNoJwtSignatureSuppliedExceptionMessage = 提供されるべきではないJWT署名が予期されました。 +invalidJwtSignatureSuppliedExceptionMessage = 無効なJWT署名が提供されました。 +jwtExpiredExceptionMessage = JWTの有効期限が切れています。 +jwtNotYetValidExceptionMessage = JWTはまだ有効ではありません。 +snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = SnapinsはWindows PowerShellのみでサポートされています。 +userFileDoesNotExistExceptionMessage = ユーザーファイルが存在しません:{0} +schemeRequiresValidScriptBlockExceptionMessage = '{0}'認証バリデーターのために提供されたスキームには有効なScriptBlockが必要です。 +oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = OAuth2プロバイダーは'code' response_typeをサポートしていません。 +oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = OAuth2プロバイダーはInnerSchemeを使用するために必要な'password' grant_typeをサポートしていません。 +eventAlreadyRegisteredExceptionMessage = {0}イベントはすでに登録されています:{1} +noEventRegisteredExceptionMessage = 登録された{0}イベントはありません:{1} +'@ diff --git a/src/Locales/kr/Pode.psd1 b/src/Locales/kr/Pode.psd1 new file mode 100644 index 000000000..f78551e2c --- /dev/null +++ b/src/Locales/kr/Pode.psd1 @@ -0,0 +1,119 @@ +ConvertFrom-StringData -StringData @' +adModuleWindowsOnlyExceptionMessage = Active Directory 모듈은 Windows에서만 사용할 수 있습니다. +adModuleNotInstalledExceptionMessage = Active Directory 모듈이 설치되지 않았습니다. +secretManagementModuleNotInstalledExceptionMessage = Microsoft.PowerShell.SecretManagement 모듈이 설치되지 않았습니다. +secretVaultAlreadyRegisteredExceptionMessage = 이름이 '{0}'인 비밀 금고가 이미 자동으로 가져오는 동안 등록되었습니다. +failedToOpenRunspacePoolExceptionMessage = RunspacePool을 여는 데 실패했습니다: {0} +cronExpressionInvalidExceptionMessage = Cron 표현식은 5개의 부분으로만 구성되어야 합니다: {0} +invalidAliasFoundExceptionMessage = 잘못된 {0} 별칭이 발견되었습니다: {1} +invalidAtomCharacterExceptionMessage = 잘못된 원자 문자: {0} +minValueGreaterThanMaxExceptionMessage = {0}의 최소 값은 최대 값보다 클 수 없습니다. +minValueInvalidExceptionMessage = {1}의 최소 값 '{0}'이(가) 유효하지 않습니다. {2} 이상이어야 합니다. +maxValueInvalidExceptionMessage = {1}의 최대 값 '{0}'이(가) 유효하지 않습니다. {2} 이하여야 합니다. +valueOutOfRangeExceptionMessage = {1}의 값 '{0}'이(가) 유효하지 않습니다. {2}와 {3} 사이여야 합니다. +daysInMonthExceededExceptionMessage = {0}에는 {1}일밖에 없지만 {2}일이 제공되었습니다. +nextTriggerCalculationErrorExceptionMessage = 다음 트리거 날짜 및 시간을 계산하는 중에 문제가 발생한 것 같습니다: {0} +incompatiblePodeDllExceptionMessage = 기존의 호환되지 않는 Pode.DLL 버전 {0}이 로드되었습니다. 버전 {1}이 필요합니다. 새로운 Powershell/pwsh 세션을 열고 다시 시도하세요. +endpointNotExistExceptionMessage = 프로토콜 '{0}' 및 주소 '{1}' 또는 로컬 주소 '{2}'가 있는 엔드포인트가 존재하지 않습니다. +endpointNameNotExistExceptionMessage = 이름이 '{0}'인 엔드포인트가 존재하지 않습니다. +failedToConnectToUrlExceptionMessage = URL에 연결하지 못했습니다: {0} +failedToParseAddressExceptionMessage = '{0}'을(를) 유효한 IP/호스트:포트 주소로 구문 분석하지 못했습니다. +invalidIpAddressExceptionMessage = 제공된 IP 주소가 유효하지 않습니다: {0} +invalidPortExceptionMessage = 포트는 음수일 수 없습니다: {0} +pathNotExistExceptionMessage = 경로가 존재하지 않습니다: {0} +noSecretForHmac256ExceptionMessage = HMAC256 해시를 위한 비밀이 제공되지 않았습니다. +noSecretForHmac384ExceptionMessage = HMAC384 해시를 위한 비밀이 제공되지 않았습니다. +noSecretForHmac512ExceptionMessage = HMAC512 해시를 위한 비밀이 제공되지 않았습니다. +noSecretForJwtSignatureExceptionMessage = JWT 서명을 위한 비밀이 제공되지 않았습니다. +noSecretExpectedForNoSignatureExceptionMessage = 서명이 없는 경우 비밀이 제공되지 않아야 합니다. +unsupportedJwtAlgorithmExceptionMessage = JWT 알고리즘은 현재 지원되지 않습니다: {0} +invalidBase64JwtExceptionMessage = JWT에서 잘못된 Base64 인코딩 값이 발견되었습니다. +invalidJsonJwtExceptionMessage = JWT에서 잘못된 JSON 값이 발견되었습니다. +unsupportedFunctionInServerlessContextExceptionMessage = {0} 함수는 서버리스 컨텍스트에서 지원되지 않습니다. +invalidPathWildcardOrDirectoryExceptionMessage = 제공된 경로는 와일드카드 또는 디렉터리가 될 수 없습니다: {0} +invalidExceptionTypeExceptionMessage = 예외가 잘못된 유형입니다. WebException 또는 HttpRequestException이어야 하지만, 얻은 것은: {0} +pathToLoadNotFoundExceptionMessage = 로드할 경로 {0}을(를) 찾을 수 없습니다: {1} +singleValueForIntervalExceptionMessage = 간격을 사용할 때는 단일 {0} 값을 제공할 수 있습니다. +scriptErrorExceptionMessage = 스크립트 {1} {2} (라인 {3}) 문자 {4}에서 {5}을(를) 실행하는 중에 스크립트 {0} 오류가 발생했습니다. 개체 '{7}' 클래스: {8} 기본 클래스: {9} +noScriptBlockSuppliedExceptionMessage = ScriptBlock이 제공되지 않았습니다. +iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN이 누락되었습니다. +invalidContentTypeForSchemaExceptionMessage = 스키마에 대해 잘못된 콘텐츠 유형이 발견되었습니다: {0} +propertiesParameterWithoutNameExceptionMessage = 속성에 이름이 없으면 Properties 매개변수를 사용할 수 없습니다. +multiTypePropertiesRequireOpenApi31ExceptionMessage = 다중 유형 속성은 OpenApi 버전 3.1 이상이 필요합니다. +openApiVersionPropertyMandatoryExceptionMessage = OpenApi 버전 속성은 필수입니다. +webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = Webhooks 기능은 OpenAPI v3.0.x에서 지원되지 않습니다. +authenticationMethodDoesNotExistExceptionMessage = 인증 방법이 존재하지 않습니다: {0} +unsupportedObjectExceptionMessage = 지원되지 않는 개체 +validationOfAnyOfSchemaNotSupportedExceptionMessage = 'anyof'을 포함하는 스키마의 유효성 검사는 지원되지 않습니다. +validationOfOneOfSchemaNotSupportedExceptionMessage = 'oneof'을 포함하는 스키마의 유효성 검사는 지원되지 않습니다. +cannotCreatePropertyWithoutTypeExceptionMessage = 유형이 정의되지 않았기 때문에 속성을 생성할 수 없습니다. +paramsNoAdditionalPropertiesExclusiveExceptionMessage = Params -NoAdditionalProperties와 -AdditionalProperties는 서로 배타적입니다. +headerMustHaveNameInEncodingContextExceptionMessage = 인코딩 컨텍스트에서 사용될 때 헤더는 이름이 있어야 합니다. +descriptionRequiredExceptionMessage = 설명이 필요합니다. +openApiDocumentNotCompliantExceptionMessage = OpenAPI 문서는 준수하지 않습니다. +noComponentInDefinitionExceptionMessage = {2} 정의에서 {0} 유형의 {1} 이름의 구성 요소가 없습니다. +methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: 이미 정의되었습니다. +methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: {2}에 대해 이미 정의되었습니다. +invalidMiddlewareTypeExceptionMessage = 제공된 미들웨어 중 하나가 잘못된 유형입니다. 예상된 유형은 ScriptBlock 또는 Hashtable이지만, 얻은 것은: {0} +hashtableMiddlewareNoLogicExceptionMessage = 제공된 Hashtable 미들웨어에는 정의된 논리가 없습니다. +invalidLogicTypeInHashtableMiddlewareExceptionMessage = 제공된 Hashtable 미들웨어에 잘못된 논리 유형이 있습니다. 예상된 유형은 ScriptBlock이지만, 얻은 것은: {0} +scopedVariableAlreadyDefinedExceptionMessage = 범위 지정 변수가 이미 정의되었습니다: {0} +valueForUsingVariableNotFoundExceptionMessage = `$using:{0}`에 대한 값을 찾을 수 없습니다. +unlockSecretRequiredExceptionMessage = Microsoft.PowerShell.SecretStore를 사용할 때 'UnlockSecret' 속성이 필요합니다. +unlockSecretButNoScriptBlockExceptionMessage = 사용자 정의 비밀 금고 유형에 대해 제공된 Unlock 비밀이지만, Unlock ScriptBlock이 제공되지 않았습니다. +noUnlockScriptBlockForVaultExceptionMessage = 금고 '{0}'을(를) 해제하는 Unlock ScriptBlock이 제공되지 않았습니다. +noSetScriptBlockForVaultExceptionMessage = 금고 '{0}'에서 비밀을 업데이트/생성하기 위한 Set ScriptBlock이 제공되지 않았습니다. +noRemoveScriptBlockForVaultExceptionMessage = 금고 '{0}'에서 비밀을 제거하기 위한 Remove ScriptBlock이 제공되지 않았습니다. +invalidSecretValueTypeExceptionMessage = 비밀 값이 잘못된 유형입니다. 예상되는 유형: String, SecureString, HashTable, Byte[] 또는 PSCredential. 그러나 얻은 것은: {0} +limitValueCannotBeZeroOrLessExceptionMessage = {0}에 대한 제한 값은 0 이하일 수 없습니다. +secondsValueCannotBeZeroOrLessExceptionMessage = {0}에 대한 초 값은 0 이하일 수 없습니다. +failedToCreateOpenSslCertExceptionMessage = openssl 인증서 생성 실패: {0} +certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 인증서 지문/이름은 Windows에서만 지원됩니다. +noCertificateFoundExceptionMessage = '{2}'에 대한 {0}\{1}에서 인증서를 찾을 수 없습니다. +runspacePoolFailedToLoadExceptionMessage = {0} RunspacePool 로드 실패. +noServiceHandlersDefinedExceptionMessage = 정의된 서비스 핸들러가 없습니다. +noSessionToSetOnResponseExceptionMessage = 응답에 설정할 세션이 없습니다. +noSessionToCalculateDataHashExceptionMessage = 데이터 해시를 계산할 세션이 없습니다. +moduleOrVersionNotFoundExceptionMessage = {0}에서 모듈 또는 버전을 찾을 수 없습니다: {1}@{2} +noSmtpHandlersDefinedExceptionMessage = 정의된 SMTP 핸들러가 없습니다. +taskTimedOutExceptionMessage = 작업이 {0}ms 후에 시간 초과되었습니다. +verbAlreadyDefinedExceptionMessage = [동사] {0}: 이미 정의되었습니다. +verbAlreadyDefinedForUrlExceptionMessage = [동사] {0}: {1}에 대해 이미 정의되었습니다. +pathOrScriptBlockRequiredExceptionMessage = 사용자 지정 액세스 값을 소싱하기 위해 경로 또는 ScriptBlock이 필요합니다. +accessMethodAlreadyDefinedExceptionMessage = 액세스 방법이 이미 정의되었습니다: {0} +accessMethodNotExistForMergingExceptionMessage = 병합을 위한 액세스 방법이 존재하지 않습니다: {0} +routeAlreadyContainsCustomAccessExceptionMessage = 경로 '[{0}] {1}'에 '{2}' 이름의 사용자 지정 액세스가 이미 포함되어 있습니다. +accessMethodNotExistExceptionMessage = 액세스 방법이 존재하지 않습니다: {0} +pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = PathItems 기능은 OpenAPI v3.0.x에서 지원되지 않습니다. +nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 사용자 정의 인증 스킴에는 비어 있지 않은 ScriptBlock이 필요합니다. +oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme은 Basic 또는 Form 인증 중 하나여야 합니다, 그러나 받은 값: {0} +sessionsRequiredForOAuth2WithPKCEExceptionMessage = PKCE를 사용하는 OAuth2에는 세션이 필요합니다. +oauth2ClientSecretRequiredExceptionMessage = PKCE를 사용하지 않을 때 OAuth2에는 클라이언트 비밀이 필요합니다. +authMethodAlreadyDefinedExceptionMessage = 인증 방법이 이미 정의되었습니다: {0} +invalidSchemeForAuthValidatorExceptionMessage = '{1}' 인증 검증기에 제공된 '{0}' 스킴에는 유효한 ScriptBlock이 필요합니다. +sessionsRequiredForSessionPersistentAuthExceptionMessage = 세션 지속 인증을 사용하려면 세션이 필요합니다. +oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2에는 권한 부여 URL이 필요합니다. +authMethodNotExistForMergingExceptionMessage = 병합을 위한 인증 방법이 존재하지 않습니다: {0} +mergeDefaultAuthNotInListExceptionMessage = 병합 기본 인증 '{0}'이(가) 제공된 인증 목록에 없습니다. +defaultAuthNotInListExceptionMessage = 기본 인증 '{0}'이(가) 제공된 인증 목록에 없습니다. +scriptBlockRequiredForMergingUsersExceptionMessage = Valid가 All일 때 여러 인증된 사용자를 하나의 객체로 병합하려면 ScriptBlock이 필요합니다. +noDomainServerNameForWindowsAdAuthExceptionMessage = Windows AD 인증을 위한 도메인 서버 이름이 제공되지 않았습니다. +sessionsNotConfiguredExceptionMessage = 세션이 구성되지 않았습니다. +windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Windows 로컬 인증 지원은 Windows 전용입니다. +iisAuthSupportIsForWindowsOnlyExceptionMessage = IIS 인증 지원은 Windows 전용입니다. +noAlgorithmInJwtHeaderExceptionMessage = JWT 헤더에 제공된 알고리즘이 없습니다. +invalidJwtSuppliedExceptionMessage = 제공된 JWT가 유효하지 않습니다. +invalidJwtHeaderAlgorithmSuppliedExceptionMessage = 제공된 JWT 헤더 알고리즘이 유효하지 않습니다. +noJwtSignatureForAlgorithmExceptionMessage = {0}에 대한 JWT 서명이 제공되지 않았습니다. +expectedNoJwtSignatureSuppliedExceptionMessage = JWT 서명이 제공되지 않을 것으로 예상되었습니다. +invalidJwtSignatureSuppliedExceptionMessage = 제공된 JWT 서명이 유효하지 않습니다. +jwtExpiredExceptionMessage = JWT가 만료되었습니다. +jwtNotYetValidExceptionMessage = JWT가 아직 유효하지 않습니다. +snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Snapins는 Windows PowerShell에서만 지원됩니다. +userFileDoesNotExistExceptionMessage = 사용자 파일이 존재하지 않습니다: {0} +schemeRequiresValidScriptBlockExceptionMessage = '{0}' 인증 검증기에 제공된 스킴에는 유효한 ScriptBlock이 필요합니다. +oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = OAuth2 공급자는 'code' 응답 유형을 지원하지 않습니다. +oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = OAuth2 공급자는 InnerScheme을 사용하는 데 필요한 'password' 부여 유형을 지원하지 않습니다. +eventAlreadyRegisteredExceptionMessage = {0} 이벤트가 이미 등록되었습니다: {1} +noEventRegisteredExceptionMessage = 등록된 {0} 이벤트가 없습니다: {1} +'@ diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index 3cb6a8034..3ff8acb85 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -42,7 +42,6 @@ propertiesParameterWithoutNameExceptionMessage = Parametry Properties nie mogą multiTypePropertiesRequireOpenApi31ExceptionMessage = Właściwości wielotypowe wymagają wersji OpenApi 3.1 lub wyższej. openApiVersionPropertyMandatoryExceptionMessage = Właściwość wersji OpenApi jest obowiązkowa. webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = Funkcja Webhooks nie jest obsługiwana w OpenAPI v3.0.x -pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = Funkcja PathItems nie jest obsługiwana w OpenAPI v3.0.x authenticationMethodDoesNotExistExceptionMessage = Metoda uwierzytelniania nie istnieje: {0} unsupportedObjectExceptionMessage = Obiekt nieobsługiwany validationOfAnyOfSchemaNotSupportedExceptionMessage = Walidacja schematu, który zawiera 'anyof', nie jest obsługiwana. @@ -85,4 +84,36 @@ accessMethodAlreadyDefinedExceptionMessage = Metoda dostępu już zdefiniowana: accessMethodNotExistForMergingExceptionMessage = Metoda dostępu nie istnieje do scalania: {0} routeAlreadyContainsCustomAccessExceptionMessage = Trasa '[{0}] {1}' już zawiera dostęp niestandardowy z nazwą '{2}' accessMethodNotExistExceptionMessage = Metoda dostępu nie istnieje: {0} +pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = Funkcja PathItems nie jest obsługiwana w OpenAPI v3.0.x +nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = Dla niestandardowego schematu uwierzytelniania wymagany jest niepusty ScriptBlock. +oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme może być tylko jednym z dwóch: Basic lub Form, ale otrzymano: {0} +sessionsRequiredForOAuth2WithPKCEExceptionMessage = Sesje są wymagane do używania OAuth2 z PKCE +oauth2ClientSecretRequiredExceptionMessage = OAuth2 wymaga tajemnicy klienta, gdy nie używa się PKCE. +authMethodAlreadyDefinedExceptionMessage = Metoda uwierzytelniania już zdefiniowana: {0} +invalidSchemeForAuthValidatorExceptionMessage = Dostarczony schemat '{0}' dla walidatora uwierzytelniania '{1}' wymaga ważnego ScriptBlock. +sessionsRequiredForSessionPersistentAuthExceptionMessage = Sesje są wymagane do używania trwałego uwierzytelniania sesji. +oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 wymaga podania URL autoryzacji +authMethodNotExistForMergingExceptionMessage = Metoda uwierzytelniania nie istnieje dla scalania: {0} +mergeDefaultAuthNotInListExceptionMessage = Uwierzytelnianie MergeDefault '{0}' nie znajduje się na dostarczonej liście uwierzytelniania. +defaultAuthNotInListExceptionMessage = Domyślne uwierzytelnianie '{0}' nie znajduje się na dostarczonej liście uwierzytelniania. +scriptBlockRequiredForMergingUsersExceptionMessage = Wymagany jest ScriptBlock do scalania wielu uwierzytelnionych użytkowników w jeden obiekt, gdy opcja Valid to All. +noDomainServerNameForWindowsAdAuthExceptionMessage = Nie podano nazwy serwera domeny dla uwierzytelniania Windows AD +sessionsNotConfiguredExceptionMessage = Sesje nie zostały skonfigurowane. +windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Wsparcie lokalnego uwierzytelniania Windows jest tylko dla Windows. +iisAuthSupportIsForWindowsOnlyExceptionMessage = Wsparcie uwierzytelniania IIS jest tylko dla Windows. +noAlgorithmInJwtHeaderExceptionMessage = Brak dostarczonego algorytmu w nagłówku JWT. +invalidJwtSuppliedExceptionMessage = Dostarczono nieprawidłowy JWT. +invalidJwtHeaderAlgorithmSuppliedExceptionMessage = Dostarczono nieprawidłowy algorytm nagłówka JWT. +noJwtSignatureForAlgorithmExceptionMessage = Nie dostarczono podpisu JWT dla {0}. +expectedNoJwtSignatureSuppliedExceptionMessage = Oczekiwano, że nie zostanie dostarczony żaden podpis JWT. +invalidJwtSignatureSuppliedExceptionMessage = Dostarczono nieprawidłowy podpis JWT. +jwtExpiredExceptionMessage = JWT wygasł. +jwtNotYetValidExceptionMessage = JWT jeszcze nie jest ważny. +snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Snapiny są obsługiwane tylko w Windows PowerShell. +userFileDoesNotExistExceptionMessage = Plik użytkownika nie istnieje: {0} +schemeRequiresValidScriptBlockExceptionMessage = Dostarczony schemat dla walidatora uwierzytelniania '{0}' wymaga ważnego ScriptBlock. +oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = Dostawca OAuth2 nie obsługuje typu odpowiedzi 'code'. +oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = Dostawca OAuth2 nie obsługuje typu 'password' wymaganego przez InnerScheme. +eventAlreadyRegisteredExceptionMessage = Wydarzenie {0} już zarejestrowane: {1} +noEventRegisteredExceptionMessage = Brak zarejestrowanego wydarzenia {0}: {1} '@ diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index 02866c758..280644726 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -42,7 +42,6 @@ propertiesParameterWithoutNameExceptionMessage = Os parâmetros Properties não multiTypePropertiesRequireOpenApi31ExceptionMessage = Propriedades de múltiplos tipos requerem a versão 3.1 ou superior do OpenApi. openApiVersionPropertyMandatoryExceptionMessage = A propriedade da versão do OpenApi é obrigatória. webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = O recurso Webhooks não é suportado no OpenAPI v3.0.x -pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = O recurso PathItems não é suportado no OpenAPI v3.0.x authenticationMethodDoesNotExistExceptionMessage = O método de autenticação não existe: {0} unsupportedObjectExceptionMessage = Objeto não suportado validationOfAnyOfSchemaNotSupportedExceptionMessage = A validação de um esquema que inclui 'anyof' não é suportada. @@ -85,4 +84,36 @@ accessMethodAlreadyDefinedExceptionMessage = Método de acesso já definido: {0} accessMethodNotExistForMergingExceptionMessage = O método de acesso não existe para a mesclagem: {0} routeAlreadyContainsCustomAccessExceptionMessage = A rota '[{0}] {1}' já contém Acesso Personalizado com o nome '{2}' accessMethodNotExistExceptionMessage = O método de acesso não existe: {0} +pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = O recurso PathItems não é suportado no OpenAPI v3.0.x +nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = É necessário um ScriptBlock não vazio para o esquema de autenticação personalizado. +oauth2InnerSchemeInvalidExceptionMessage = O OAuth2 InnerScheme só pode ser um de autenticação Basic ou Form, mas foi obtido: {0} +sessionsRequiredForOAuth2WithPKCEExceptionMessage = Sessões são necessárias para usar OAuth2 com PKCE +oauth2ClientSecretRequiredExceptionMessage = OAuth2 requer um Client Secret quando não se usa PKCE. +authMethodAlreadyDefinedExceptionMessage = Método de autenticação já definido: {0} +invalidSchemeForAuthValidatorExceptionMessage = O esquema '{0}' fornecido para o validador de autenticação '{1}' requer um ScriptBlock válido. +sessionsRequiredForSessionPersistentAuthExceptionMessage = Sessões são necessárias para usar a autenticação persistente por sessão. +oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 requer que seja fornecida uma URL de Autorização +authMethodNotExistForMergingExceptionMessage = O método de autenticação não existe para mesclagem: {0} +mergeDefaultAuthNotInListExceptionMessage = A Autenticação MergeDefault '{0}' não está na lista de Autenticação fornecida. +defaultAuthNotInListExceptionMessage = A Autenticação Default '{0}' não está na lista de Autenticação fornecida. +scriptBlockRequiredForMergingUsersExceptionMessage = É necessário um ScriptBlock para mesclar vários usuários autenticados em 1 objeto quando Valid é All. +noDomainServerNameForWindowsAdAuthExceptionMessage = Nenhum nome de servidor de domínio foi fornecido para a autenticação AD do Windows +sessionsNotConfiguredExceptionMessage = As sessões não foram configuradas. +windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = O suporte à Autenticação Local do Windows é apenas para Windows. +iisAuthSupportIsForWindowsOnlyExceptionMessage = O suporte à Autenticação IIS é apenas para Windows. +noAlgorithmInJwtHeaderExceptionMessage = Nenhum algoritmo fornecido no Cabeçalho JWT. +invalidJwtSuppliedExceptionMessage = JWT fornecido inválido. +invalidJwtHeaderAlgorithmSuppliedExceptionMessage = Algoritmo de cabeçalho JWT fornecido inválido. +noJwtSignatureForAlgorithmExceptionMessage = Nenhuma assinatura JWT fornecida para {0}. +expectedNoJwtSignatureSuppliedExceptionMessage = Esperava-se que nenhuma assinatura JWT fosse fornecida. +invalidJwtSignatureSuppliedExceptionMessage = Assinatura JWT fornecida inválida. +jwtExpiredExceptionMessage = O JWT expirou. +jwtNotYetValidExceptionMessage = O JWT ainda não é válido para uso. +snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Os Snapins são suportados apenas no Windows PowerShell. +userFileDoesNotExistExceptionMessage = O arquivo do usuário não existe: {0} +schemeRequiresValidScriptBlockExceptionMessage = O esquema fornecido para o validador de autenticação '{0}' requer um ScriptBlock válido. +oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = O provedor OAuth2 não suporta o response_type 'code'. +oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = O provedor OAuth2 não suporta o grant_type 'password' necessário ao usar um InnerScheme. +eventAlreadyRegisteredExceptionMessage = Evento {0} já registrado: {1} +noEventRegisteredExceptionMessage = Nenhum evento {0} registrado: {1} '@ diff --git a/src/Locales/zn/Pode.psd1 b/src/Locales/zn/Pode.psd1 index c6ebfb915..26456390f 100644 --- a/src/Locales/zn/Pode.psd1 +++ b/src/Locales/zn/Pode.psd1 @@ -85,4 +85,35 @@ accessMethodNotExistForMergingExceptionMessage = 合并时访问方法不存在: routeAlreadyContainsCustomAccessExceptionMessage = 路由 '[{0}] {1}' 已经包含名称为 '{2}' 的自定义访问。 accessMethodNotExistExceptionMessage = 访问方法不存在: {0} pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 在 OpenAPI v3.0.x 中不支持 PathItems 功能。 -'@ \ No newline at end of file +nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 自定义身份验证方案需要一个非空的 ScriptBlock。 +oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme 只能是 Basic 或 Form 身份验证,但得到:{0} +sessionsRequiredForOAuth2WithPKCEExceptionMessage = 使用 PKCE 时需要会话来使用 OAuth2 +oauth2ClientSecretRequiredExceptionMessage = 不使用 PKCE 时,OAuth2 需要一个客户端密钥。 +authMethodAlreadyDefinedExceptionMessage = 身份验证方法已定义:{0} +invalidSchemeForAuthValidatorExceptionMessage = 提供的 '{0}' 方案用于 '{1}' 身份验证验证器,需要一个有效的 ScriptBlock。 +sessionsRequiredForSessionPersistentAuthExceptionMessage = 使用会话持久性身份验证需要会话。 +oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 需要提供授权 URL +authMethodNotExistForMergingExceptionMessage = 合并时身份验证方法不存在:{0} +mergeDefaultAuthNotInListExceptionMessage = MergeDefault 身份验证 '{0}' 不在提供的身份验证列表中。 +defaultAuthNotInListExceptionMessage = 默认身份验证 '{0}' 不在提供的身份验证列表中。 +scriptBlockRequiredForMergingUsersExceptionMessage = 当 Valid 是 All 时,需要一个 ScriptBlock 来将多个经过身份验证的用户合并为一个对象。 +noDomainServerNameForWindowsAdAuthExceptionMessage = 没有为 Windows AD 身份验证提供域服务器名称 +sessionsNotConfiguredExceptionMessage = 会话尚未配置。 +windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Windows 本地身份验证支持仅适用于 Windows。 +iisAuthSupportIsForWindowsOnlyExceptionMessage = IIS 身份验证支持仅适用于 Windows。 +noAlgorithmInJwtHeaderExceptionMessage = JWT 头中未提供算法。 +invalidJwtSuppliedExceptionMessage = 提供的 JWT 无效。 +invalidJwtHeaderAlgorithmSuppliedExceptionMessage = 提供的 JWT 头算法无效。 +noJwtSignatureForAlgorithmExceptionMessage = 没有为 {0} 提供 JWT 签名。 +expectedNoJwtSignatureSuppliedExceptionMessage = 预期不提供 JWT 签名。 +invalidJwtSignatureSuppliedExceptionMessage = 提供的 JWT 签名无效。 +jwtExpiredExceptionMessage = JWT 已过期。 +jwtNotYetValidExceptionMessage = JWT 尚未有效。 +snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Snapins 仅支持 Windows PowerShell。 +userFileDoesNotExistExceptionMessage = 用户文件不存在:{0} +schemeRequiresValidScriptBlockExceptionMessage = 提供的方案用于 '{0}' 身份验证验证器,需要一个有效的 ScriptBlock。 +oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = OAuth2 提供程序不支持 'code' response_type。 +oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = OAuth2 提供程序不支持使用 InnerScheme 所需的 'password' grant_type。 +eventAlreadyRegisteredExceptionMessage = {0} 事件已注册:{1} +noEventRegisteredExceptionMessage = 没有注册的 {0} 事件:{1} +'@ diff --git a/src/Pode.psm1 b/src/Pode.psm1 index 72e91050b..ad21d2e0f 100644 --- a/src/Pode.psm1 +++ b/src/Pode.psm1 @@ -1,19 +1,69 @@ -[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')] -param() +<# +.SYNOPSIS + Pode PowerShell Module + +.DESCRIPTION + This module sets up the Pode environment, including + localization and loading necessary assemblies and functions. + +.PARAMETER UICulture + Specifies the culture to be used for localization. + +.EXAMPLE + Import-Module -Name "Pode" -ArgumentList @{ UICulture = 'ko-KR' } + Sets the culture to Korean. + +.EXAMPLE + Import-Module -Name "Pode" + Uses the default culture. + +.EXAMPLE + Import-Module -Name "Pode" -ArgumentList 'it-SM' + Uses the Italian San Marino region culture. + +.NOTES + This is the entry point for the Pode module. +#> + +param( + [string]$UICulture +) + # root path $root = Split-Path -Parent -Path $MyInvocation.MyCommand.Path # Import localized messages -$global:msgTable = Import-LocalizedData -BaseDirectory (Join-Path -Path $root -ChildPath 'Locales') +if ([string]::IsNullOrEmpty($UICulture)) { + $UICulture = $PsUICulture +} -# load assemblies -Add-Type -AssemblyName System.Web -Add-Type -AssemblyName System.Net.Http +#Culture list available here https://azuliadesigns.com/c-sharp-tutorials/list-net-culture-country-codes/ +Import-LocalizedData -BindingVariable tmpMsgtable -BaseDirectory (Join-Path -Path $root -ChildPath 'Locales') -UICulture $UICulture -ErrorAction:SilentlyContinue +if ($null -eq $tmpMsgtable) { + try { + Import-LocalizedData -BindingVariable tmpMsgtable -BaseDirectory (Join-Path -Path $root -ChildPath 'Locales') -UICulture 'en' -ErrorAction:Stop + } + catch { + throw + } +} + +try { + # Create the global msgTable read-only variable + New-Variable -Name 'msgTable' -Value $tmpMsgtable -Scope Global -Option ReadOnly -Force + + # load assemblies + Add-Type -AssemblyName System.Web -ErrorAction Stop + Add-Type -AssemblyName System.Net.Http -ErrorAction Stop -# Construct the path to the module manifest (.psd1 file) -$moduleManifestPath = Join-Path -Path $root -ChildPath 'Pode.psd1' + # Construct the path to the module manifest (.psd1 file) + $moduleManifestPath = Join-Path -Path $root -ChildPath 'Pode.psd1' -# Import the module manifest to access its properties -$moduleManifest = Import-PowerShellDataFile -Path $moduleManifestPath + # Import the module manifest to access its properties + $moduleManifest = Import-PowerShellDataFile -Path $moduleManifestPath -ErrorAction Stop +} +catch { + throw +} $podeDll = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq 'Pode' } @@ -26,14 +76,19 @@ if ($podeDll) { } } else { - if ($PSVersionTable.PSVersion -ge [version]'7.4.0') { - Add-Type -LiteralPath "$($root)/Libs/net8.0/Pode.dll" -ErrorAction Stop - } - elseif ($PSVersionTable.PSVersion -ge [version]'7.2.0') { - Add-Type -LiteralPath "$($root)/Libs/net6.0/Pode.dll" -ErrorAction Stop + try { + if ($PSVersionTable.PSVersion -ge [version]'7.4.0') { + Add-Type -LiteralPath "$($root)/Libs/net8.0/Pode.dll" -ErrorAction Stop + } + elseif ($PSVersionTable.PSVersion -ge [version]'7.2.0') { + Add-Type -LiteralPath "$($root)/Libs/net6.0/Pode.dll" -ErrorAction Stop + } + else { + Add-Type -LiteralPath "$($root)/Libs/netstandard2.0/Pode.dll" -ErrorAction Stop + } } - else { - Add-Type -LiteralPath "$($root)/Libs/netstandard2.0/Pode.dll" -ErrorAction Stop + catch { + throw } } diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index f22920830..e05e45835 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -2709,7 +2709,7 @@ function Read-PodeWebExceptionDetails { } default { - throw "Exception is of an invalid type, should be either WebException or HttpRequestException, but got: $($_.Exception.GetType().Name)" + throw ($msgTable.invalidExceptionTypeExceptionMessage -f ($_.Exception.GetType().Name))#"Exception is of an invalid type, should be either WebException or HttpRequestException, but got: $($_.Exception.GetType().Name)" } } diff --git a/src/Public/Authentication.ps1 b/src/Public/Authentication.ps1 index 8fbbd5e5c..681809522 100644 --- a/src/Public/Authentication.ps1 +++ b/src/Public/Authentication.ps1 @@ -159,7 +159,7 @@ function New-PodeAuthScheme { [Parameter(Mandatory = $true, ParameterSetName = 'Custom')] [ValidateScript({ if (Test-PodeIsEmpty $_) { - throw 'A non-empty ScriptBlock is required for the Custom authentication scheme' + throw $msgTable.nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage #'A non-empty ScriptBlock is required for the Custom authentication scheme' } return $true @@ -408,19 +408,19 @@ function New-PodeAuthScheme { 'oauth2' { if (($null -ne $InnerScheme) -and ($InnerScheme.Name -inotin @('basic', 'form'))) { - throw "OAuth2 InnerScheme can only be one of either Basic or Form authentication, but got: $($InnerScheme.Name)" + throw ($msgTable.oauth2InnerSchemeInvalidExceptionMessage -f $InnerScheme.Name) #"OAuth2 InnerScheme can only be one of either Basic or Form authentication, but got: $($InnerScheme.Name)" } if (($null -eq $InnerScheme) -and [string]::IsNullOrWhiteSpace($AuthoriseUrl)) { - throw 'OAuth2 requires an Authorise URL to be supplied' + throw $msgTable.oauth2RequiresAuthorizeUrlExceptionMessage #'OAuth2 requires an Authorise URL to be supplied' } if ($UsePKCE -and !(Test-PodeSessionsEnabled)) { - throw 'Sessions are required to use OAuth2 with PKCE' + throw $msgTable.sessionsRequiredForOAuth2WithPKCEExceptionMessage #'Sessions are required to use OAuth2 with PKCE' } if (!$UsePKCE -and [string]::IsNullOrEmpty($ClientSecret)) { - throw 'OAuth2 requires a Client Secret when not using PKCE' + throw $msgTable.oauth2ClientSecretRequiredExceptionMessage #'OAuth2 requires a Client Secret when not using PKCE' } return @{ Name = 'OAuth2' @@ -717,7 +717,7 @@ function Add-PodeAuth { [Parameter(Mandatory = $true)] [ValidateScript({ if (Test-PodeIsEmpty $_) { - throw 'A non-empty ScriptBlock is required for the authentication method' + throw $msgTable.nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage #'A non-empty ScriptBlock is required for the authentication method' } return $true @@ -750,17 +750,17 @@ function Add-PodeAuth { # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { - throw "Authentication method already defined: $($Name)" + throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) # "Authentication method already defined: $($Name)" } # ensure the Scheme contains a scriptblock if (Test-PodeIsEmpty $Scheme.ScriptBlock) { - throw "The supplied '$($Scheme.Name)' Scheme for the '$($Name)' authentication validator requires a valid ScriptBlock" + throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) # "The supplied '$($Scheme.Name)' Scheme for the '$($Name)' authentication validator requires a valid ScriptBlock" } # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { - throw 'Sessions are required to use session persistent authentication' + throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage # 'Sessions are required to use session persistent authentication' } # check for scoped vars @@ -902,24 +902,24 @@ function Merge-PodeAuth { # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { - throw "Authentication method already defined: $($Name)" + throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) # "Authentication method already defined: $($Name)" } # ensure all the auth methods exist foreach ($authName in $Authentication) { if (!(Test-PodeAuthExists -Name $authName)) { - throw "Authentication method does not exist for merging: $($authName)" + throw ($msgTable.authMethodNotExistForMergingExceptionMessage -f $authName) #"Authentication method does not exist for merging: $($authName)" } } # ensure the merge default is in the auth list if (![string]::IsNullOrEmpty($MergeDefault) -and ($MergeDefault -inotin @($Authentication))) { - throw "the MergeDefault Authentication '$($MergeDefault)' is not in the Authentication list supplied" + throw ($msgTable.mergeDefaultAuthNotInListExceptionMessage -f $MergeDefault) # "the MergeDefault Authentication '$($MergeDefault)' is not in the Authentication list supplied" } # ensure the default is in the auth list if (![string]::IsNullOrEmpty($Default) -and ($Default -inotin @($Authentication))) { - throw "the Default Authentication '$($Default)' is not in the Authentication list supplied" + throw ($msgTable.defaultAuthNotInListExceptionMessage -f $Default) # "the Default Authentication '$($Default)' is not in the Authentication list supplied" } # set default @@ -937,7 +937,7 @@ function Merge-PodeAuth { # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { - throw 'Sessions are required to use session persistent authentication' + throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage #'Sessions are required to use session persistent authentication' } # check failure url from default @@ -963,7 +963,7 @@ function Merge-PodeAuth { # deal with using vars in scriptblock if (($Valid -ieq 'all') -and [string]::IsNullOrEmpty($MergeDefault)) { if ($null -eq $ScriptBlock) { - throw 'A Scriptblock for merging multiple authenticated users into 1 object is required When Valid is All' + throw $msgTable.scriptBlockRequiredForMergingUsersExceptionMessage # 'A Scriptblock for merging multiple authenticated users into 1 object is required When Valid is All' } $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState @@ -1028,7 +1028,7 @@ function Get-PodeAuth { # ensure the name exists if (!(Test-PodeAuthExists -Name $Name)) { - throw "Authentication method not defined: $($Name)" + throw ($msgTable.authenticationMethodDoesNotExistExceptionMessage -f $Name) # "Authentication method not defined: $($Name)" } # get auth method @@ -1264,17 +1264,17 @@ function Add-PodeAuthWindowsAd { # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { - throw "Windows AD Authentication method already defined: $($Name)" + throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) # "Windows AD Authentication method already defined: $($Name)" } # ensure the Scheme contains a scriptblock if (Test-PodeIsEmpty $Scheme.ScriptBlock) { - throw "The supplied Scheme for the '$($Name)' Windows AD authentication validator requires a valid ScriptBlock" + throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) # "The supplied Scheme for the '$($Name)' Windows AD authentication validator requires a valid ScriptBlock" } # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { - throw 'Sessions are required to use session persistent authentication' + throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage #'Sessions are required to use session persistent authentication' } # if AD module set, ensure we're on windows and the module is available, then import/export it @@ -1287,7 +1287,7 @@ function Add-PodeAuthWindowsAd { $Fqdn = Get-PodeAuthDomainName if ([string]::IsNullOrWhiteSpace($Fqdn)) { - throw 'No domain server name has been supplied for Windows AD authentication' + throw $msgTable.noDomainServerNameForWindowsAdAuthExceptionMessage #'No domain server name has been supplied for Windows AD authentication' } } @@ -1400,12 +1400,12 @@ function Add-PodeAuthSession { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { - throw 'Sessions have not been configured' + throw $msgTable.sessionsNotConfiguredExceptionMessage #'Sessions have not been configured' } # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { - throw "Authentication method already defined: $($Name)" + throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) # "Authentication method already defined: $($Name)" } # if we have a scriptblock, deal with using vars @@ -1559,7 +1559,7 @@ function Add-PodeAuthMiddleware { $DefinitionTag = Test-PodeOADefinitionTag -Tag $OADefinitionTag if (!(Test-PodeAuthExists -Name $Authentication)) { - throw "Authentication method does not exist: $($Authentication)" + throw ($msgTable.authenticationMethodDoesNotExistExceptionMessage -f $Authentication) # "Authentication method does not exist: $($Authentication)" } Get-PodeAuthMiddlewareScript | @@ -1685,12 +1685,12 @@ function Add-PodeAuthIIS { # ensure we're on Windows! if (!(Test-PodeIsWindows)) { - throw 'IIS Authentication support is for Windows only' + throw $msgTable.iisAuthSupportIsForWindowsOnlyExceptionMessage # 'IIS Authentication support is for Windows only' } # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { - throw "IIS Authentication method already defined: $($Name)" + throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) # "IIS Authentication method already defined: $($Name)" } # if AD module set, ensure we're on windows and the module is available, then import/export it @@ -1848,17 +1848,17 @@ function Add-PodeAuthUserFile { # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { - throw "User File Authentication method already defined: $($Name)" + throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) # "User File Authentication method already defined: $($Name)" } # ensure the Scheme contains a scriptblock if (Test-PodeIsEmpty $Scheme.ScriptBlock) { - throw "The supplied Scheme for the '$($Name)' User File authentication validator requires a valid ScriptBlock" + throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) #"The supplied Scheme for the '$($Name)' User File authentication validator requires a valid ScriptBlock" } # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { - throw 'Sessions are required to use session persistent authentication' + throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage #'Sessions are required to use session persistent authentication' } # set the file path if not passed @@ -1871,7 +1871,7 @@ function Add-PodeAuthUserFile { # ensure the user file exists if (!(Test-PodePath -Path $FilePath -NoStatus -FailOnDirectory)) { - throw "The user file does not exist: $($FilePath)" + throw ($msgTable.userFileDoesNotExistExceptionMessage -f $FilePath) # "The user file does not exist: $($FilePath)" } # if we have a scriptblock, deal with using vars @@ -2006,22 +2006,22 @@ function Add-PodeAuthWindowsLocal { # ensure we're on Windows! if (!(Test-PodeIsWindows)) { - throw 'Windows Local Authentication support is for Windows only' + throw $msgTable.windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage #'Windows Local Authentication support is for Windows only' } # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { - throw "Windows Local Authentication method already defined: $($Name)" + throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) # "Windows Local Authentication method already defined: $($Name)" } # ensure the Scheme contains a scriptblock if (Test-PodeIsEmpty $Scheme.ScriptBlock) { - throw "The supplied Scheme for the '$($Name)' Windows Local authentication validator requires a valid ScriptBlock" + throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) # "The supplied Scheme for the '$($Name)' Windows Local authentication validator requires a valid ScriptBlock" } # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { - throw 'Sessions are required to use session persistent authentication' + throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage #'Sessions are required to use session persistent authentication' } # if we have a scriptblock, deal with using vars @@ -2097,7 +2097,7 @@ function ConvertTo-PodeJwt { # validate header if ([string]::IsNullOrWhiteSpace($Header.alg)) { - throw 'No algorithm supplied in JWT Header' + throw $msgTable.noAlgorithmInJwtHeaderExceptionMessage #'No algorithm supplied in JWT Header' } # convert the header @@ -2161,13 +2161,13 @@ function ConvertFrom-PodeJwt { # check number of parts (should be 3) if ($parts.Length -ne 3) { - throw 'Invalid JWT supplied' + throw $msgTable.invalidJwtSuppliedExceptionMessage #'Invalid JWT supplied' } # convert to header $header = ConvertFrom-PodeJwtBase64Value -Value $parts[0] if ([string]::IsNullOrWhiteSpace($header.alg)) { - throw 'Invalid JWT header algorithm supplied' + throw $msgTable.invalidJwtHeaderAlgorithmSuppliedExceptionMessage # Invalid JWT header algorithm supplied' } # convert to payload @@ -2184,15 +2184,15 @@ function ConvertFrom-PodeJwt { $isNoneAlg = ($header.alg -ieq 'none') if ([string]::IsNullOrWhiteSpace($signature) -and !$isNoneAlg) { - throw "No JWT signature supplied for $($header.alg)" + throw ($msgTable.noJwtSignatureForAlgorithmExceptionMessage -f $header.alg) # "No JWT signature supplied for $($header.alg)" } if (![string]::IsNullOrWhiteSpace($signature) -and $isNoneAlg) { - throw 'Expected no JWT signature to be supplied' + throw $msgTable.expectedNoJwtSignatureSuppliedExceptionMessage # 'Expected no JWT signature to be supplied' } if ($isNoneAlg -and ($null -ne $Secret) -and ($Secret.Length -gt 0)) { - throw "Expected a signed JWT, 'none' algorithm is not allowed" + throw $msgTable.expectedNoJwtSignatureSuppliedExceptionMessage # 'Expected no JWT signature to be supplied' } if ($isNoneAlg) { @@ -2208,7 +2208,7 @@ function ConvertFrom-PodeJwt { $sig = New-PodeJwtSignature -Algorithm $header.alg -Token $sig -SecretBytes $Secret if ($sig -ne $parts[2]) { - throw 'Invalid JWT signature supplied' + throw $msgTable.invalidJwtSignatureSuppliedExceptionMessage # 'Invalid JWT signature supplied' } # it's valid return the payload! @@ -2247,14 +2247,14 @@ function Test-PodeJwt { # validate expiry if (![string]::IsNullOrWhiteSpace($Payload.exp)) { if ($now -gt $unixStart.AddSeconds($Payload.exp)) { - throw 'The JWT has expired' + throw $msgTable.jwtExpiredExceptionMessage # 'The JWT has expired' } } # validate not-before if (![string]::IsNullOrWhiteSpace($Payload.nbf)) { if ($now -lt $unixStart.AddSeconds($Payload.nbf)) { - throw 'The JWT is not yet valid for use' + throw $msgTable.jwtNotYetValidExceptionMessage #'The JWT is not yet valid for use' } } } @@ -2367,12 +2367,12 @@ function ConvertFrom-PodeOIDCDiscovery { # check it supports the code response_type if ($config.response_types_supported -inotcontains 'code') { - throw "The OAuth2 provider does not support the 'code' response_type" + throw $msgTable.oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage # "The OAuth2 provider does not support the 'code' response_type" } # can we have an InnerScheme? if (($null -ne $InnerScheme) -and ($config.grant_types_supported -inotcontains 'password')) { - throw "The OAuth2 provider does not support the 'password' grant_type required by using an InnerScheme" + throw $msgTable.oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage # "The OAuth2 provider does not support the 'password' grant_type required by using an InnerScheme" } # scopes diff --git a/src/Public/AutoImport.ps1 b/src/Public/AutoImport.ps1 index 4421700c1..fb9c21b0e 100644 --- a/src/Public/AutoImport.ps1 +++ b/src/Public/AutoImport.ps1 @@ -46,7 +46,7 @@ function Export-PodeSnapin { # if non-windows or core, fail if ((Test-PodeIsPSCore) -or (Test-PodeIsUnix)) { - throw 'Snapins are only supported on Windows PowerShell' + throw $msgTable.snapinsSupportedOnWindowsPowershellOnlyExceptionMessage # 'Snapins are only supported on Windows PowerShell' } $PodeContext.Server.AutoImport.Snapins.ExportList += @($Name) diff --git a/src/Public/Events.ps1 b/src/Public/Events.ps1 index fe03becab..6d509e92c 100644 --- a/src/Public/Events.ps1 +++ b/src/Public/Events.ps1 @@ -43,7 +43,7 @@ function Register-PodeEvent { # error if already registered if (Test-PodeEvent -Type $Type -Name $Name) { - throw "$($Type) event already registered: $($Name)" + throw ($msgTable.eventAlreadyRegisteredExceptionMessage -f $Type, $Name) # "$($Type) event already registered: $($Name)" } # check for scoped vars @@ -89,7 +89,7 @@ function Unregister-PodeEvent { # error if not registered if (!(Test-PodeEvent -Type $Type -Name $Name)) { - throw "No $($Type) event registered: $($Name)" + throw ($msgTable.noEventRegisteredExceptionMessage -f $Type, $Name) # "No $($Type) event registered: $($Name)" } # remove event diff --git a/tests/unit/Authentication.Tests.ps1 b/tests/unit/Authentication.Tests.ps1 index 5af266048..298d9b9ff 100644 --- a/tests/unit/Authentication.Tests.ps1 +++ b/tests/unit/Authentication.Tests.ps1 @@ -139,12 +139,12 @@ Describe 'Test-PodeJwt' { It 'Throws exception - the JWT has expired' { # "exp" (Expiration Time) Claim - { Test-PodeJwt @{exp = 1 } } | Should -Throw -ExceptionType ([System.Exception]) -ExpectedMessage 'The JWT has expired' + { Test-PodeJwt @{exp = 1 } } | Should -Throw -ExceptionType ([System.Exception]) -ExpectedMessage $msgTable.jwtExpiredExceptionMessage } It 'Throws exception - the JWT is not yet valid for use' { # "nbf" (Not Before) Claim - { Test-PodeJwt @{nbf = 99999999999 } } | Should -Throw -ExceptionType ([System.Exception]) -ExpectedMessage 'The JWT is not yet valid for use' + { Test-PodeJwt @{nbf = 99999999999 } } | Should -Throw -ExceptionType ([System.Exception]) -ExpectedMessage $msgTable.jwtNotYetValidExceptionMessage } } From 44ebb9da1f2af75183db6d893c40f75c5b7e3205 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 31 May 2024 15:50:08 -0700 Subject: [PATCH 019/177] fix outputType for some functions --- src/Private/Cryptography.ps1 | 2 +- src/Private/Middleware.ps1 | 4 +- src/Private/ScopedVariables.ps1 | 22 +++---- src/Private/UnusedHelper.ps1 | 97 ------------------------------ src/Public/Authentication.ps1 | 3 +- tests/unit/UnusedHelpers.Tests.ps1 | 62 ------------------- 6 files changed, 15 insertions(+), 175 deletions(-) delete mode 100644 src/Private/UnusedHelper.ps1 delete mode 100644 tests/unit/UnusedHelpers.Tests.ps1 diff --git a/src/Private/Cryptography.ps1 b/src/Private/Cryptography.ps1 index cbccbf3e0..11efa2362 100644 --- a/src/Private/Cryptography.ps1 +++ b/src/Private/Cryptography.ps1 @@ -511,7 +511,7 @@ function ConvertTo-PodeBase64UrlValue { function ConvertFrom-PodeJwtBase64Value { [CmdletBinding()] - [OutputType([string])] + [OutputType([pscustomobject])] param( [Parameter(Mandatory = $true)] [string] diff --git a/src/Private/Middleware.ps1 b/src/Private/Middleware.ps1 index 9de0a68a2..5b8e37d92 100644 --- a/src/Private/Middleware.ps1 +++ b/src/Private/Middleware.ps1 @@ -166,7 +166,7 @@ This is an internal function and may change in future releases of Pode. #> function Get-PodeLimitMiddleware { [CmdletBinding()] - [OutputType([ScriptBlock])] + [OutputType([hashtable])] param() return (Get-PodeInbuiltMiddleware -Name '__pode_mw_rate_limit__' -ScriptBlock { # are there any rules? @@ -213,7 +213,7 @@ function Get-PodeLimitMiddleware { #> function Get-PodePublicMiddleware { [CmdletBinding()] - [OutputType([bool])] + [OutputType([hashtable])] param() return (Get-PodeInbuiltMiddleware -Name '__pode_mw_static_content__' -ScriptBlock { # only find public static content here diff --git a/src/Private/ScopedVariables.ps1 b/src/Private/ScopedVariables.ps1 index 1bdcd1b40..a94a48d4c 100644 --- a/src/Private/ScopedVariables.ps1 +++ b/src/Private/ScopedVariables.ps1 @@ -118,20 +118,20 @@ function Convert-PodeScopedVariableInbuiltUsing { $ScriptBlock = [scriptblock]::Create($strScriptBlock) } - # get any using variables - $usingVars = Get-PodeScopedVariableUsingVariable -ScriptBlock $ScriptBlock - if (($null -eq $usingVars) -or ($usingVars.Count -eq 0)) { - return $ScriptBlock, $null - } + # get any using variables + $usingVars = Get-PodeScopedVariableUsingVariable -ScriptBlock $ScriptBlock + if (($null -eq $usingVars) -or ($usingVars.Count -eq 0)) { + return $ScriptBlock, $null + } - # convert any using vars to use new names - $usingVars = Find-PodeScopedVariableUsingVariableValue -UsingVariable $usingVars -PSSession $PSSession + # convert any using vars to use new names + $usingVars = Find-PodeScopedVariableUsingVariableValue -UsingVariable $usingVars -PSSession $PSSession - # now convert the script - $newScriptBlock = Convert-PodeScopedVariableUsingVariable -ScriptBlock $ScriptBlock -UsingVariables $usingVars + # now convert the script + $newScriptBlock = Convert-PodeScopedVariableUsingVariable -ScriptBlock $ScriptBlock -UsingVariables $usingVars - # return converted script - return $newScriptBlock, $usingVars + # return converted script + return $newScriptBlock, $usingVars } <# diff --git a/src/Private/UnusedHelper.ps1 b/src/Private/UnusedHelper.ps1 deleted file mode 100644 index 0540130ca..000000000 --- a/src/Private/UnusedHelper.ps1 +++ /dev/null @@ -1,97 +0,0 @@ - -function Get-PodeDotSourcedFile { - param( - [Parameter(Mandatory = $true)] - [System.Management.Automation.Language.Ast] - $Ast, - - [Parameter()] - [string] - $RootPath - ) - - # set default root path - if ([string]::IsNullOrWhiteSpace($RootPath)) { - $RootPath = $PodeContext.Server.Root - } - - # get all dot-sourced files - $cmdTypes = @('dot', 'ampersand') - $files = ($Ast.FindAll({ - ($args[0] -is [System.Management.Automation.Language.CommandAst]) -and - ($args[0].InvocationOperator -iin $cmdTypes) -and - ($args[0].CommandElements.StaticType.Name -ieq 'string') - }, $false)).CommandElements.Value - - $fileOrder = @() - - # no files found - if (($null -eq $files) -or ($files.Length -eq 0)) { - return $fileOrder - } - - # get any sub sourced files - foreach ($file in $files) { - $file = Get-PodeRelativePath -Path $file -RootPath $RootPath -JoinRoot - $fileOrder += $file - - $ast = Get-PodeAstFromFile -FilePath $file - - $result = Get-PodeDotSourcedFile -Ast $ast -RootPath (Split-Path -Parent -Path $file) - if (($null -ne $result) -and ($result.Length -gt 0)) { - $fileOrder += $result - } - } - - # return all found files - return $fileOrder -} - - -# Convert-PodePathSeparators -function Convert-PodePathSeparator { - param( - [Parameter()] - $Paths - ) - - return @($Paths | ForEach-Object { - if (![string]::IsNullOrWhiteSpace($_)) { - $_ -ireplace '[\\/]', [System.IO.Path]::DirectorySeparatorChar - } - }) -} - -<# -.SYNOPSIS -Tests if the Pode module is from the development branch. - -.DESCRIPTION -The Test-PodeVersionDev function checks if the Pode module's version matches the placeholder value ('$version$'), which is used to indicate the development branch of the module. It returns $true if the version matches, indicating the module is from the development branch, and $false otherwise. - -.PARAMETER None -This function does not accept any parameters. - -.OUTPUTS -System.Boolean -Returns $true if the Pode module version is '$version$', indicating the development branch. Returns $false for any other version. - -.EXAMPLE -PS> $moduleManifest = @{ ModuleVersion = '$version$' } -PS> Test-PodeVersionDev - -Returns $true, indicating the development branch. - -.EXAMPLE -PS> $moduleManifest = @{ ModuleVersion = '1.2.3' } -PS> Test-PodeVersionDev - -Returns $false, indicating a specific release version. - -.NOTES -This function assumes that $moduleManifest is a hashtable representing the loaded module manifest, with a key of ModuleVersion. - -#> -function Test-PodeVersionDev { - return (Get-PodeModuleManifest).ModuleVersion -eq '$version$' -} diff --git a/src/Public/Authentication.ps1 b/src/Public/Authentication.ps1 index f737e2114..74771b605 100644 --- a/src/Public/Authentication.ps1 +++ b/src/Public/Authentication.ps1 @@ -1374,7 +1374,6 @@ Add-PodeAuthSession -Name 'SessionAuth' -FailureUrl '/login' #> function Add-PodeAuthSession { [CmdletBinding(DefaultParameterSetName = 'Groups')] - [OutputType([hashtable])] param( [Parameter(Mandatory = $true)] [string] @@ -2150,7 +2149,7 @@ ConvertFrom-PodeJwt -Token "eyJ0eXAiOiJKV1QiLCJhbGciOiJoczI1NiJ9.eyJleHAiOjE2MjI #> function ConvertFrom-PodeJwt { [CmdletBinding(DefaultParameterSetName = 'Secret')] - [OutputType([string])] + [OutputType([pscustomobject])] param( [Parameter(Mandatory = $true)] [string] diff --git a/tests/unit/UnusedHelpers.Tests.ps1 b/tests/unit/UnusedHelpers.Tests.ps1 deleted file mode 100644 index cd2cb53a9..000000000 --- a/tests/unit/UnusedHelpers.Tests.ps1 +++ /dev/null @@ -1,62 +0,0 @@ -[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] -param() -BeforeAll { - $path = $PSCommandPath - $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' - Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } -} - - -Describe 'Convert-PodePathSeparator' { - Context 'Null' { - It 'Null' { - Convert-PodePathSeparator -Path $null | Should -Be $null - } - } - - Context 'String' { - It 'Empty' { - Convert-PodePathSeparator -Path '' | Should -Be $null - Convert-PodePathSeparator -Path ' ' | Should -Be $null - } - - It 'Value' { - Convert-PodePathSeparator -Path 'anyValue' | Should -Be 'anyValue' - Convert-PodePathSeparator -Path 1 | Should -Be 1 - } - - It 'Path' { - Convert-PodePathSeparator -Path 'one/Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)Seperators" - Convert-PodePathSeparator -Path 'one\Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)Seperators" - - Convert-PodePathSeparator -Path 'one/two/Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)two$([System.IO.Path]::DirectorySeparatorChar)Seperators" - Convert-PodePathSeparator -Path 'one\two\Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)two$([System.IO.Path]::DirectorySeparatorChar)Seperators" - Convert-PodePathSeparator -Path 'one/two\Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)two$([System.IO.Path]::DirectorySeparatorChar)Seperators" - Convert-PodePathSeparator -Path 'one\two/Seperators' | Should -Be "one$([System.IO.Path]::DirectorySeparatorChar)two$([System.IO.Path]::DirectorySeparatorChar)Seperators" - } - } - - Context 'Array' { - It 'Null' { - Convert-PodePathSeparator -Path @($null) | Should -Be $null - Convert-PodePathSeparator -Path @($null, $null) | Should -Be $null - } - - It 'Single' { - Convert-PodePathSeparator -Path @('noSeperators') | Should -Be @('noSeperators') - Convert-PodePathSeparator -Path @('some/Seperators') | Should -Be @("some$([System.IO.Path]::DirectorySeparatorChar)Seperators") - Convert-PodePathSeparator -Path @('some\Seperators') | Should -Be @("some$([System.IO.Path]::DirectorySeparatorChar)Seperators") - - Convert-PodePathSeparator -Path @('') | Should -Be $null - Convert-PodePathSeparator -Path @(' ') | Should -Be $null - } - - It 'Double' { - Convert-PodePathSeparator -Path @('noSeperators1', 'noSeperators2') | Should -Be @('noSeperators1', 'noSeperators2') - Convert-PodePathSeparator -Path @('some/Seperators', 'some\Seperators') | Should -Be @("some$([System.IO.Path]::DirectorySeparatorChar)Seperators", "some$([System.IO.Path]::DirectorySeparatorChar)Seperators") - - Convert-PodePathSeparator -Path @('', ' ') | Should -Be $null - Convert-PodePathSeparator -Path @(' ', '') | Should -Be $null - } - } -} From 472a8a52270a1875b61e520820c10781fa04e6b1 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sat, 1 Jun 2024 11:23:24 -0700 Subject: [PATCH 020/177] Additional messages --- src/Locales/ar/Pode.psd1 | 53 +++++++++++++- src/Locales/de/Pode.psd1 | 52 ++++++++++++- src/Locales/en/Pode.psd1 | 52 ++++++++++++- src/Locales/es/Pode.psd1 | 52 ++++++++++++- src/Locales/fr/Pode.psd1 | 52 ++++++++++++- src/Locales/it/Pode.psd1 | 53 +++++++++++++- src/Locales/ja/Pode.psd1 | 52 ++++++++++++- src/Locales/kr/Pode.psd1 | 52 ++++++++++++- src/Locales/pl/Pode.psd1 | 52 ++++++++++++- src/Locales/pt/Pode.psd1 | 52 ++++++++++++- src/Locales/zn/Pode.psd1 | 60 +++++++++++++-- src/Private/Authentication.ps1 | 6 +- src/Private/AutoImport.ps1 | 3 +- src/Private/Cryptography.ps1 | 21 ++++-- src/Private/Middleware.ps1 | 6 +- src/Private/OpenApi.ps1 | 39 ++++++---- src/Private/Routes.ps1 | 6 +- src/Private/Secrets.ps1 | 6 +- src/Private/Security.ps1 | 3 +- src/Private/ServiceServer.ps1 | 3 +- src/Private/Sessions.ps1 | 6 +- src/Private/SmtpServer.ps1 | 3 +- src/Public/Access.ps1 | 3 +- src/Public/Authentication.ps1 | 117 ++++++++++++++++++++---------- src/Public/AutoImport.ps1 | 3 +- src/Public/Core.ps1 | 24 ++++-- src/Public/Flash.ps1 | 18 +++-- src/Public/Logging.ps1 | 21 ++++-- src/Public/Middleware.ps1 | 12 ++- src/Public/OAComponents.ps1 | 9 ++- src/Public/OAProperties.ps1 | 21 ++++-- src/Public/Responses.ps1 | 3 +- src/Public/Routes.ps1 | 39 ++++++---- src/Public/SSE.ps1 | 9 ++- src/Public/Sessions.ps1 | 27 ++++--- src/Public/State.ps1 | 21 ++++-- src/Public/Tasks.ps1 | 3 +- src/Public/Threading.ps1 | 15 ++-- src/Public/Utilities.ps1 | 12 ++- tests/unit/Helpers.Tests.ps1 | 6 +- tests/unit/Localization.Tests.ps1 | 4 +- tests/unit/OpenApi.Tests.ps1 | 4 +- tests/unit/Routes.Tests.ps1 | 2 +- tests/unit/Security.Tests.ps1 | 2 +- tests/unit/Sessions.Tests.ps1 | 6 +- tests/unit/State.Tests.ps1 | 12 +-- 46 files changed, 878 insertions(+), 199 deletions(-) diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 840103194..93b0e07c5 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -58,7 +58,7 @@ invalidMiddlewareTypeExceptionMessage = أحد مكونات Middleware المق hashtableMiddlewareNoLogicExceptionMessage = مكون Middleware من نوع Hashtable المقدم لا يحتوي على منطق معرف. invalidLogicTypeInHashtableMiddlewareExceptionMessage = مكون Middleware من نوع Hashtable المقدم يحتوي على نوع منطق غير صالح. كان المتوقع ScriptBlock، ولكن تم الحصول عليه: {0} scopedVariableAlreadyDefinedExceptionMessage = المتغير المحدد بالفعل معرف: {0} -valueForUsingVariableNotFoundExceptionMessage = لم يتم العثور على قيمة لـ `$using:{0}`. +valueForUsingVariableNotFoundExceptionMessage = لم يتم العثور على قيمة لـ '$using:{0}'. unlockSecretRequiredExceptionMessage = خاصية 'UnlockSecret' مطلوبة عند استخدام Microsoft.PowerShell.SecretStore unlockSecretButNoScriptBlockExceptionMessage = تم تقديم سر الفتح لنوع خزنة سرية مخصصة، ولكن لم يتم تقديم ScriptBlock الفتح. noUnlockScriptBlockForVaultExceptionMessage = لم يتم تقديم ScriptBlock الفتح لفتح الخزنة '{0}' @@ -116,5 +116,52 @@ oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = مزود OAuth2 oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = مزود OAuth2 لا يدعم نوع المنحة 'password' المطلوبة لاستخدام InnerScheme. eventAlreadyRegisteredExceptionMessage = الحدث {0} مسجل بالفعل: {1} noEventRegisteredExceptionMessage = لا يوجد حدث {0} مسجل: {1} -'@ - +sessionsRequiredForFlashMessagesExceptionMessage = الجلسات مطلوبة لاستخدام رسائل الفلاش. +eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = تسجيل عارض الأحداث مدعوم فقط على Windows. +nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = مطلوب ScriptBlock غير فارغ لطريقة إخراج السجل المخصصة. +requestLoggingAlreadyEnabledExceptionMessage = تم تمكين تسجيل الطلبات بالفعل. +outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = طريقة الإخراج المقدمة لتسجيل الطلبات تتطلب ScriptBlock صالح. +errorLoggingAlreadyEnabledExceptionMessage = تم تمكين تسجيل الأخطاء بالفعل. +nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = مطلوب ScriptBlock غير فارغ لطريقة التسجيل. +csrfMiddlewareNotInitializedExceptionMessage = لم يتم تهيئة CSRF Middleware. +sessionsRequiredForCsrfExceptionMessage = الجلسات مطلوبة لاستخدام CSRF إلا إذا كنت ترغب في استخدام ملفات تعريف الارتباط. +middlewareNoLogicSuppliedExceptionMessage = [Middleware]: لم يتم توفير أي منطق في ScriptBlock. +parameterHasNoNameExceptionMessage = لا يحتوي المعامل على اسم. يرجى إعطاء هذا المكون اسمًا باستخدام معامل 'Name'. +reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = ميزة المكون القابل لإعادة الاستخدام 'pathItems' غير متوفرة في OpenAPI v3.0. +noPropertiesMutuallyExclusiveExceptionMessage = المعامل 'NoProperties' يتعارض مع 'Properties' و 'MinProperties' و 'MaxProperties'. +discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = يمكن استخدام المعامل 'DiscriminatorMapping' فقط عندما تكون خاصية 'DiscriminatorProperty' موجودة. +discriminatorIncompatibleWithAllOfExceptionMessage = المعامل 'Discriminator' غير متوافق مع 'allOf'. +typeCanOnlyBeAssociatedWithObjectExceptionMessage = النوع {0} يمكن ربطه فقط بجسم. +showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui متاح حاليًا فقط لـ Windows PowerShell و PowerShell 7+ على Windows. +nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = مطلوب اسم لنقطة النهاية إذا تم توفير معامل RedirectTo. +clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = الشهادات العميلة مدعومة فقط على نقاط النهاية HTTPS. +explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = وضع TLS الصريح مدعوم فقط على نقاط النهاية SMTPS و TCPS. +acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = رسالة الإقرار مدعومة فقط على نقاط النهاية SMTP و TCP. +crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = فحص نهاية الرسالة CRLF مدعوم فقط على نقاط النهاية TCP. +mustBeRunningWithAdminPrivilegesExceptionMessage = يجب التشغيل بامتيازات المسؤول للاستماع إلى العناوين غير المحلية. +certificateSuppliedForNonHttpsWssEndpointExceptionMessage = تم توفير شهادة لنقطة نهاية غير HTTPS/WSS. +websocketsNotConfiguredForSignalMessagesExceptionMessage = لم يتم تهيئة WebSockets لإرسال رسائل الإشارة. +noPathSuppliedForRouteExceptionMessage = لم يتم توفير مسار للطريق. +accessRequiresAuthenticationOnRoutesExceptionMessage = يتطلب الوصول توفير المصادقة على الطرق. +accessMethodDoesNotExistExceptionMessage = طريقة الوصول غير موجودة: {0}. +routeParameterNeedsValidScriptblockExceptionMessage = المعامل Route يتطلب ScriptBlock صالح وغير فارغ. +noCommandsSuppliedToConvertToRoutesExceptionMessage = لم يتم توفير أي أوامر لتحويلها إلى طرق. +nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = مطلوب ScriptBlock غير فارغ لإنشاء مسار الصفحة. +sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = يمكن تكوين SSE فقط على الطلبات التي تحتوي على قيمة رأس Accept النص/تيار الأحداث. +sseConnectionNameRequiredExceptionMessage = مطلوب اسم اتصال SSE، إما من -Name أو $WebEvent.Sse.Name +sseFailedToBroadcastExceptionMessage = فشل بث SSE بسبب مستوى البث SSE المحدد لـ {0}: {1} +podeNotInitializedExceptionMessage = لم يتم تهيئة Pode. +invalidTaskTypeExceptionMessage = نوع المهمة غير صالح، المتوقع إما [System.Threading.Tasks.Task] أو [hashtable]. +cannotLockValueTypeExceptionMessage = لا يمكن قفل [ValueTypes]. +cannotLockNullObjectExceptionMessage = لا يمكن قفل كائن فارغ. +failedToAcquireLockExceptionMessage = فشل في الحصول على قفل على الكائن. +cannotUnlockValueTypeExceptionMessage = لا يمكن فتح [ValueTypes]. +cannotUnlockNullObjectExceptionMessage = لا يمكن فتح كائن فارغ. +sessionMiddlewareAlreadyInitializedExceptionMessage = تم تهيئة Session Middleware بالفعل. +customSessionStorageMethodNotImplementedExceptionMessage = تخزين الجلسة المخصص لا ينفذ الطريقة المطلوبة '{0}()'. +secretRequiredForCustomSessionStorageExceptionMessage = مطلوب سر عند استخدام تخزين الجلسة المخصص. +noSessionAvailableToSaveExceptionMessage = لا توجد جلسة متاحة للحفظ. +cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = لا يمكن توفير فترة زمنية عندما يكون المعامل 'Every' مضبوطًا على None. +cannotSupplyIntervalForQuarterExceptionMessage = لا يمكن توفير قيمة الفاصل الزمني لكل ربع. +cannotSupplyIntervalForYearExceptionMessage = لا يمكن توفير قيمة الفاصل الزمني لكل سنة. +'@ \ No newline at end of file diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index ab5cca0e3..7f6fa0086 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -58,7 +58,7 @@ invalidMiddlewareTypeExceptionMessage = Eines der angegebenen Middleware-Objekte hashtableMiddlewareNoLogicExceptionMessage = Eine angegebene Hashtable-Middleware enthält keine definierte Logik. invalidLogicTypeInHashtableMiddlewareExceptionMessage = Eine angegebene Hashtable-Middleware enthält einen ungültigen Logik-Typ. Erwartet wurde ein ScriptBlock, aber erhalten wurde: {0}. scopedVariableAlreadyDefinedExceptionMessage = Die Bereichsvariable ist bereits definiert: {0}. -valueForUsingVariableNotFoundExceptionMessage = Der Wert für `$using:{0}` konnte nicht gefunden werden. +valueForUsingVariableNotFoundExceptionMessage = Der Wert für '$using:{0}' konnte nicht gefunden werden. unlockSecretRequiredExceptionMessage = Eine 'UnlockSecret'-Eigenschaft ist erforderlich, wenn Microsoft.PowerShell.SecretStore verwendet wird. unlockSecretButNoScriptBlockExceptionMessage = Unlock secret für benutzerdefinierten Secret Vault-Typ angegeben, aber kein Unlock ScriptBlock bereitgestellt. noUnlockScriptBlockForVaultExceptionMessage = Kein Unlock ScriptBlock für das Entsperren des Tresors '{0}' bereitgestellt. @@ -116,4 +116,52 @@ oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = Der OAuth2-Anbiet oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = Der OAuth2-Anbieter unterstützt den für die Verwendung eines InnerScheme erforderlichen 'password'-Grant-Typ nicht. eventAlreadyRegisteredExceptionMessage = Ereignis {0} bereits registriert: {1} noEventRegisteredExceptionMessage = Kein Ereignis {0} registriert: {1} -'@ +sessionsRequiredForFlashMessagesExceptionMessage = Sitzungen sind erforderlich, um Flash-Nachrichten zu verwenden. +eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = Das Protokollieren im Ereignisanzeige wird nur auf Windows unterstützt. +nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = Ein nicht leerer ScriptBlock ist für die benutzerdefinierte Protokollierungsmethode erforderlich. +requestLoggingAlreadyEnabledExceptionMessage = Die Anforderungsprotokollierung wurde bereits aktiviert. +outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = Die angegebene Ausgabemethode für die Anforderungsprotokollierung erfordert einen gültigen ScriptBlock. +errorLoggingAlreadyEnabledExceptionMessage = Die Fehlerprotokollierung wurde bereits aktiviert. +nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = Ein nicht leerer ScriptBlock ist für die Protokollierungsmethode erforderlich. +csrfMiddlewareNotInitializedExceptionMessage = CSRF Middleware wurde nicht initialisiert. +sessionsRequiredForCsrfExceptionMessage = Sitzungen sind erforderlich, um CSRF zu verwenden, es sei denn, Sie möchten Cookies verwenden. +middlewareNoLogicSuppliedExceptionMessage = [Middleware]: Kein Logik-ScriptBlock bereitgestellt. +parameterHasNoNameExceptionMessage = Der Parameter hat keinen Namen. Bitte geben Sie dieser Komponente einen Namen mit dem 'Name'-Parameter. +reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = Die wiederverwendbare Komponente 'pathItems' ist in OpenAPI v3.0 nicht verfügbar. +noPropertiesMutuallyExclusiveExceptionMessage = Der Parameter 'NoProperties' schließt 'Properties', 'MinProperties' und 'MaxProperties' gegenseitig aus. +discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = Der Parameter 'DiscriminatorMapping' kann nur verwendet werden, wenn 'DiscriminatorProperty' vorhanden ist. +discriminatorIncompatibleWithAllOfExceptionMessage = Der Parameter 'Discriminator' ist nicht mit 'allOf' kompatibel. +typeCanOnlyBeAssociatedWithObjectExceptionMessage = Der Typ {0} kann nur einem Objekt zugeordnet werden. +showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui ist derzeit nur für Windows PowerShell und PowerShell 7+ unter Windows verfügbar. +nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = Ein Name ist für den Endpunkt erforderlich, wenn der RedirectTo-Parameter angegeben ist. +clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = Clientzertifikate werden nur auf HTTPS-Endpunkten unterstützt. +explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = Der explizite TLS-Modus wird nur auf SMTPS- und TCPS-Endpunkten unterstützt. +acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = Die Bestätigungsnachricht wird nur auf SMTP- und TCP-Endpunkten unterstützt. +crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = Die CRLF-Nachrichtenendprüfung wird nur auf TCP-Endpunkten unterstützt. +mustBeRunningWithAdminPrivilegesExceptionMessage = Muss mit Administratorrechten ausgeführt werden, um auf Nicht-Localhost-Adressen zu lauschen. +certificateSuppliedForNonHttpsWssEndpointExceptionMessage = Zertifikat für Nicht-HTTPS/WSS-Endpunkt bereitgestellt. +websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSockets wurden nicht konfiguriert, um Signalnachrichten zu senden. +noPathSuppliedForRouteExceptionMessage = Kein Pfad für die Route bereitgestellt. +accessRequiresAuthenticationOnRoutesExceptionMessage = Der Zugriff erfordert eine Authentifizierung auf den Routen. +accessMethodDoesNotExistExceptionMessage = Zugriffsmethode existiert nicht: {0}. +routeParameterNeedsValidScriptblockExceptionMessage = Der Route-Parameter benötigt einen gültigen, nicht leeren ScriptBlock. +noCommandsSuppliedToConvertToRoutesExceptionMessage = Keine Befehle zur Umwandlung in Routen bereitgestellt. +nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Ein nicht leerer ScriptBlock ist erforderlich, um eine Seitenroute zu erstellen. +sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE kann nur auf Anfragen mit einem Accept-Header-Wert von text/event-stream konfiguriert werden. +sseConnectionNameRequiredExceptionMessage = Ein SSE-Verbindungsname ist erforderlich, entweder von -Name oder $WebEvent.Sse.Name +sseFailedToBroadcastExceptionMessage = SSE konnte aufgrund des definierten SSE-Broadcast-Levels für {0}: {1} nicht übertragen werden. +podeNotInitializedExceptionMessage = Pode wurde nicht initialisiert. +invalidTaskTypeExceptionMessage = Aufgabentyp ist ungültig, erwartet entweder [System.Threading.Tasks.Task] oder [hashtable] +cannotLockValueTypeExceptionMessage = Kann [ValueTypes] nicht sperren. +cannotLockNullObjectExceptionMessage = Kann ein null-Objekt nicht sperren. +failedToAcquireLockExceptionMessage = Sperre des Objekts konnte nicht erworben werden. +cannotUnlockValueTypeExceptionMessage = Kann [ValueTypes] nicht entsperren. +cannotUnlockNullObjectExceptionMessage = Kann ein null-Objekt nicht entsperren. +sessionMiddlewareAlreadyInitializedExceptionMessage = Session Middleware wurde bereits initialisiert. +customSessionStorageMethodNotImplementedExceptionMessage = Der benutzerdefinierte Sitzungspeicher implementiert die erforderliche Methode '{0}()' nicht. +secretRequiredForCustomSessionStorageExceptionMessage = Ein Geheimnis ist erforderlich, wenn benutzerdefinierter Sitzungspeicher verwendet wird. +noSessionAvailableToSaveExceptionMessage = Keine Sitzung verfügbar zum Speichern. +cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Ein Intervall kann nicht angegeben werden, wenn der Parameter 'Every' auf None gesetzt ist. +cannotSupplyIntervalForQuarterExceptionMessage = Ein Intervallwert kann nicht für jedes Quartal angegeben werden. +cannotSupplyIntervalForYearExceptionMessage = Ein Intervallwert kann nicht für jedes Jahr angegeben werden. +'@ \ No newline at end of file diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index d2df449f0..1e1785393 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -47,7 +47,7 @@ unsupportedObjectExceptionMessage = Unsupported object validationOfAnyOfSchemaNotSupportedExceptionMessage = Validation of a schema that includes 'anyof' is not supported. validationOfOneOfSchemaNotSupportedExceptionMessage = Validation of a schema that includes 'oneof' is not supported. cannotCreatePropertyWithoutTypeExceptionMessage = Cannot create the property because no type is defined. -paramsNoAdditionalPropertiesExclusiveExceptionMessage = Params -NoAdditionalProperties and -AdditionalProperties are mutually exclusive. +paramsNoAdditionalPropertiesExclusiveExceptionMessage = Params 'NoAdditionalProperties' and 'AdditionalProperties' are mutually exclusive. headerMustHaveNameInEncodingContextExceptionMessage = Header must have a name when used in an encoding context. descriptionRequiredExceptionMessage = A Description is required. openApiDocumentNotCompliantExceptionMessage = OpenAPI document is not compliant. @@ -58,7 +58,7 @@ invalidMiddlewareTypeExceptionMessage = One of the Middlewares supplied is an in hashtableMiddlewareNoLogicExceptionMessage = A Hashtable Middleware supplied has no Logic defined. invalidLogicTypeInHashtableMiddlewareExceptionMessage = A Hashtable Middleware supplied has an invalid Logic type. Expected ScriptBlock, but got: {0} scopedVariableAlreadyDefinedExceptionMessage = Scoped Variable already defined: {0} -valueForUsingVariableNotFoundExceptionMessage = Value for `$using:{0}` could not be found. +valueForUsingVariableNotFoundExceptionMessage = Value for '$using:{0}' could not be found. unlockSecretRequiredExceptionMessage = An 'UnlockSecret' property is required when using Microsoft.PowerShell.SecretStore unlockSecretButNoScriptBlockExceptionMessage = Unlock secret supplied for custom Secret Vault type, but not Unlock ScriptBlock supplied. noUnlockScriptBlockForVaultExceptionMessage = No Unlock ScriptBlock supplied for unlocking the vault '{0}' @@ -116,4 +116,52 @@ oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = The OAuth2 provid oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = The OAuth2 provider does not support the 'password' grant_type required by using an InnerScheme. eventAlreadyRegisteredExceptionMessage = {0} event already registered: {1} noEventRegisteredExceptionMessage = No {0} event registered: {1} +sessionsRequiredForFlashMessagesExceptionMessage = Sessions are required to use Flash messages. +eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = Event Viewer logging only supported on Windows. +nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = A non-empty ScriptBlock is required for the Custom logging output method. +requestLoggingAlreadyEnabledExceptionMessage = Request Logging has already been enabled. +outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = The supplied output Method for Request Logging requires a valid ScriptBlock. +errorLoggingAlreadyEnabledExceptionMessage = Error Logging has already been enabled. +nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = A non-empty ScriptBlock is required for the logging method. +csrfMiddlewareNotInitializedExceptionMessage = CSRF Middleware has not been initialized. +sessionsRequiredForCsrfExceptionMessage = Sessions are required to use CSRF unless you want to use cookies. +middlewareNoLogicSuppliedExceptionMessage = [Middleware]: No logic supplied in ScriptBlock. +parameterHasNoNameExceptionMessage = The Parameter has no name. Please give this component a name using the 'Name' parameter. +reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = The 'pathItems' reusable component feature is not available in OpenAPI v3.0. +noPropertiesMutuallyExclusiveExceptionMessage = The parameter 'NoProperties' is mutually exclusive with 'Properties', 'MinProperties' and 'MaxProperties' +discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = The parameter 'DiscriminatorMapping' can only be used when 'DiscriminatorProperty' is present. +discriminatorIncompatibleWithAllOfExceptionMessage = The parameter 'Discriminator' is incompatible with 'allOf'. +typeCanOnlyBeAssociatedWithObjectExceptionMessage = Type {0} can only be associated with an Object. +showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui is currently only available for Windows PowerShell and PowerShell 7+ on Windows. +nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = A Name is required for the endpoint if the RedirectTo parameter is supplied. +clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = Client certificates are only supported on HTTPS endpoints. +explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = The Explicit TLS mode is only supported on SMTPS and TCPS endpoints. +acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = The Acknowledge message is only supported on SMTP and TCP endpoints. +crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = The CRLF message end check is only supported on TCP endpoints. +mustBeRunningWithAdminPrivilegesExceptionMessage = Must be running with administrator privileges to listen on non-localhost addresses. +certificateSuppliedForNonHttpsWssEndpointExceptionMessage = Certificate supplied for non-HTTPS/WSS endpoint. +websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSockets have not been configured to send signal messages. +noPathSuppliedForRouteExceptionMessage = No Path supplied for the Route. +accessRequiresAuthenticationOnRoutesExceptionMessage = Access requires Authentication to be supplied on Routes. +accessMethodDoesNotExistExceptionMessage = Access method does not exist: {0}. +routeParameterNeedsValidScriptblockExceptionMessage = The Route parameter needs a valid, not empty, scriptblock. +noCommandsSuppliedToConvertToRoutesExceptionMessage = No commands supplied to convert to Routes. +nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = A non-empty ScriptBlock is required to create a Page Route. +sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE can only be configured on requests with an Accept header value of text/event-stream +sseConnectionNameRequiredExceptionMessage = An SSE connection Name is required, either from -Name or $WebEvent.Sse.Name +sseFailedToBroadcastExceptionMessage = SSE failed to broadcast due to defined SSE broadcast level for {0}: {1} +podeNotInitializedExceptionMessage = Pode has not been initialized. +invalidTaskTypeExceptionMessage = Task type is invalid, expected either [System.Threading.Tasks.Task] or [hashtable] +cannotLockValueTypeExceptionMessage = Cannot lock a [ValueTypes] +cannotLockNullObjectExceptionMessage = Cannot lock an object that is null. +failedToAcquireLockExceptionMessage = Failed to acquire a lock on the object. +cannotUnlockValueTypeExceptionMessage = Cannot unlock a [ValueTypes] +cannotUnlockNullObjectExceptionMessage = Cannot unlock an object that is null. +sessionMiddlewareAlreadyInitializedExceptionMessage = Session Middleware has already been initialized. +customSessionStorageMethodNotImplementedExceptionMessage = The custom session storage does not implement the required '{0}()' method. +secretRequiredForCustomSessionStorageExceptionMessage = A Secret is required when using custom session storage. +noSessionAvailableToSaveExceptionMessage = There is no session available to save. +cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Cannot supply an interval when the parameter 'Every' is set to None. +cannotSupplyIntervalForQuarterExceptionMessage = Cannot supply interval value for every quarter. +cannotSupplyIntervalForYearExceptionMessage = Cannot supply interval value for every year. '@ \ No newline at end of file diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 237fec72f..5468df945 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -58,7 +58,7 @@ invalidMiddlewareTypeExceptionMessage = Uno de los Middlewares suministrados es hashtableMiddlewareNoLogicExceptionMessage = Un Middleware Hashtable suministrado no tiene lógica definida. invalidLogicTypeInHashtableMiddlewareExceptionMessage = Un Middleware Hashtable suministrado tiene un tipo de lógica no válido. Se esperaba ScriptBlock, pero se obtuvo: {0} scopedVariableAlreadyDefinedExceptionMessage = La variable con alcance ya está definida: {0} -valueForUsingVariableNotFoundExceptionMessage = No se pudo encontrar el valor para `$using:{0}`. +valueForUsingVariableNotFoundExceptionMessage = No se pudo encontrar el valor para '$using:{0}'. unlockSecretRequiredExceptionMessage = Se requiere una propiedad 'UnlockSecret' al usar Microsoft.PowerShell.SecretStore unlockSecretButNoScriptBlockExceptionMessage = Se suministró un secreto de desbloqueo para el tipo de bóveda secreta personalizada, pero no se suministró ningún ScriptBlock de desbloqueo. noUnlockScriptBlockForVaultExceptionMessage = No se suministró ningún ScriptBlock de desbloqueo para desbloquear la bóveda '{0}' @@ -116,4 +116,52 @@ oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = El proveedor de O oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = El proveedor de OAuth2 no admite el tipo de concesión 'password' requerido al usar un InnerScheme. eventAlreadyRegisteredExceptionMessage = Evento {0} ya registrado: {1} noEventRegisteredExceptionMessage = No hay evento {0} registrado: {1} -'@ +sessionsRequiredForFlashMessagesExceptionMessage = Se requieren sesiones para usar mensajes Flash. +eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = El registro en el Visor de Eventos solo se admite en Windows. +nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = Se requiere un ScriptBlock no vacío para el método de salida de registro personalizado. +requestLoggingAlreadyEnabledExceptionMessage = El registro de solicitudes ya está habilitado. +outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = El método de salida proporcionado para el registro de solicitudes requiere un ScriptBlock válido. +errorLoggingAlreadyEnabledExceptionMessage = El registro de errores ya está habilitado. +nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = Se requiere un ScriptBlock no vacío para el método de registro. +csrfMiddlewareNotInitializedExceptionMessage = El Middleware CSRF no se ha inicializado. +sessionsRequiredForCsrfExceptionMessage = Se requieren sesiones para usar CSRF a menos que desee usar cookies. +middlewareNoLogicSuppliedExceptionMessage = [Middleware]: No se suministró lógica en el ScriptBlock. +parameterHasNoNameExceptionMessage = El parámetro no tiene nombre. Asigne un nombre a este componente usando el parámetro 'Name'. +reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = La característica del componente reutilizable 'pathItems' no está disponible en OpenAPI v3.0. +noPropertiesMutuallyExclusiveExceptionMessage = El parámetro 'NoProperties' es mutuamente excluyente con 'Properties', 'MinProperties' y 'MaxProperties'. +discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = El parámetro 'DiscriminatorMapping' solo se puede usar cuando está presente la propiedad 'DiscriminatorProperty'. +discriminatorIncompatibleWithAllOfExceptionMessage = El parámetro 'Discriminator' es incompatible con 'allOf'. +typeCanOnlyBeAssociatedWithObjectExceptionMessage = El tipo {0} solo se puede asociar con un Objeto. +showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui actualmente solo está disponible para Windows PowerShell y PowerShell 7+ en Windows. +nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = Se requiere un nombre para el endpoint si se proporciona el parámetro RedirectTo. +clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = Los certificados de cliente solo son compatibles con endpoints HTTPS. +explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = El modo TLS explícito solo es compatible con endpoints SMTPS y TCPS. +acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = El mensaje de reconocimiento solo es compatible con endpoints SMTP y TCP. +crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = La verificación de final de mensaje CRLF solo es compatible con endpoints TCP. +mustBeRunningWithAdminPrivilegesExceptionMessage = Debe estar ejecutándose con privilegios de administrador para escuchar en direcciones que no sean localhost. +certificateSuppliedForNonHttpsWssEndpointExceptionMessage = Certificado proporcionado para un endpoint que no es HTTPS/WSS. +websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSockets no están configurados para enviar mensajes de señal. +noPathSuppliedForRouteExceptionMessage = No se proporcionó una ruta para la Ruta. +accessRequiresAuthenticationOnRoutesExceptionMessage = El acceso requiere autenticación en las rutas. +accessMethodDoesNotExistExceptionMessage = El método de acceso no existe: {0}. +routeParameterNeedsValidScriptblockExceptionMessage = El parámetro Route necesita un ScriptBlock válido y no vacío. +noCommandsSuppliedToConvertToRoutesExceptionMessage = No se proporcionaron comandos para convertir a Rutas. +nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Se requiere un ScriptBlock no vacío para crear una Ruta de Página. +sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE solo se puede configurar en solicitudes con un valor de encabezado Accept de text/event-stream. +sseConnectionNameRequiredExceptionMessage = Se requiere un nombre de conexión SSE, ya sea de -Name o $WebEvent.Sse.Name. +sseFailedToBroadcastExceptionMessage = SSE no pudo transmitir debido al nivel de transmisión SSE definido para {0}: {1}. +podeNotInitializedExceptionMessage = Pode no se ha inicializado. +invalidTaskTypeExceptionMessage = El tipo de tarea no es válido, se esperaba [System.Threading.Tasks.Task] o [hashtable]. +cannotLockValueTypeExceptionMessage = No se puede bloquear un [ValueTypes]. +cannotLockNullObjectExceptionMessage = No se puede bloquear un objeto nulo. +failedToAcquireLockExceptionMessage = No se pudo adquirir un bloqueo en el objeto. +cannotUnlockValueTypeExceptionMessage = No se puede desbloquear un [ValueTypes]. +cannotUnlockNullObjectExceptionMessage = No se puede desbloquear un objeto nulo. +sessionMiddlewareAlreadyInitializedExceptionMessage = El Middleware de Sesión ya se ha inicializado. +customSessionStorageMethodNotImplementedExceptionMessage = El almacenamiento de sesión personalizado no implementa el método requerido '{0}()'. +secretRequiredForCustomSessionStorageExceptionMessage = Se requiere un secreto cuando se utiliza el almacenamiento de sesión personalizado. +noSessionAvailableToSaveExceptionMessage = No hay sesión disponible para guardar. +cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = No se puede proporcionar un intervalo cuando el parámetro 'Every' está configurado en None. +cannotSupplyIntervalForQuarterExceptionMessage = No se puede proporcionar un valor de intervalo para cada trimestre. +cannotSupplyIntervalForYearExceptionMessage = No se puede proporcionar un valor de intervalo para cada año. +'@ \ No newline at end of file diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index b3da880c2..8e620534e 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -58,7 +58,7 @@ invalidMiddlewareTypeExceptionMessage = Un des Middlewares fournis est d'un type hashtableMiddlewareNoLogicExceptionMessage = Un Middleware Hashtable fourni n'a aucune logique définie. invalidLogicTypeInHashtableMiddlewareExceptionMessage = Un Middleware Hashtable fourni a un type de logique non valide. Attendu ScriptBlock, mais a obtenu : {0} scopedVariableAlreadyDefinedExceptionMessage = La variable à portée est déjà définie : {0} -valueForUsingVariableNotFoundExceptionMessage = Valeur pour `$using:{0}` introuvable. +valueForUsingVariableNotFoundExceptionMessage = Valeur pour '$using:{0}' introuvable. unlockSecretRequiredExceptionMessage = Une propriété 'UnlockSecret' est requise lors de l'utilisation de Microsoft.PowerShell.SecretStore unlockSecretButNoScriptBlockExceptionMessage = Secret de déverrouillage fourni pour le type de coffre-fort personnalisé, mais aucun ScriptBlock de déverrouillage fourni. noUnlockScriptBlockForVaultExceptionMessage = Aucun ScriptBlock de déverrouillage fourni pour déverrouiller le coffre '{0}' @@ -116,4 +116,52 @@ oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = Le fournisseur OA oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = Le fournisseur OAuth2 ne supporte pas le type de subvention 'password' requis par l'utilisation d'un InnerScheme. eventAlreadyRegisteredExceptionMessage = Événement {0} déjà enregistré : {1} noEventRegisteredExceptionMessage = Aucun événement {0} enregistré : {1} -'@ +sessionsRequiredForFlashMessagesExceptionMessage = Des sessions sont nécessaires pour utiliser les messages Flash. +eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = La journalisation dans le Visualisateur d'événements n'est prise en charge que sous Windows. +nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = Un ScriptBlock non vide est requis pour la méthode de journalisation personnalisée. +requestLoggingAlreadyEnabledExceptionMessage = La journalisation des requêtes est déjà activée. +outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = La méthode de sortie fournie pour la journalisation des requêtes nécessite un ScriptBlock valide. +errorLoggingAlreadyEnabledExceptionMessage = La journalisation des erreurs est déjà activée. +nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = Un ScriptBlock non vide est requis pour la méthode de journalisation. +csrfMiddlewareNotInitializedExceptionMessage = Le Middleware CSRF n'a pas été initialisé. +sessionsRequiredForCsrfExceptionMessage = Des sessions sont nécessaires pour utiliser CSRF sauf si vous souhaitez utiliser des cookies. +middlewareNoLogicSuppliedExceptionMessage = [Middleware] : Aucune logique fournie dans le ScriptBlock. +parameterHasNoNameExceptionMessage = Le paramètre n'a pas de nom. Veuillez donner un nom à ce composant en utilisant le paramètre 'Name'. +reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = La fonctionnalité du composant réutilisable 'pathItems' n'est pas disponible dans OpenAPI v3.0. +noPropertiesMutuallyExclusiveExceptionMessage = Le paramètre 'NoProperties' est mutuellement exclusif avec 'Properties', 'MinProperties' et 'MaxProperties'. +discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = Le paramètre 'DiscriminatorMapping' ne peut être utilisé que lorsque 'DiscriminatorProperty' est présent. +discriminatorIncompatibleWithAllOfExceptionMessage = Le paramètre 'Discriminator' est incompatible avec 'allOf'. +typeCanOnlyBeAssociatedWithObjectExceptionMessage = Le type {0} ne peut être associé qu'à un Objet. +showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui est actuellement disponible uniquement pour Windows PowerShell et PowerShell 7+ sur Windows. +nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = Un nom est requis pour le point de terminaison si le paramètre RedirectTo est fourni. +clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = Les certificats client ne sont pris en charge que sur les points de terminaison HTTPS. +explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = Le mode TLS explicite n'est pris en charge que sur les points de terminaison SMTPS et TCPS. +acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = Le message de reconnaissance n'est pris en charge que sur les points de terminaison SMTP et TCP. +crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = La vérification de fin de message CRLF n'est prise en charge que sur les points de terminaison TCP. +mustBeRunningWithAdminPrivilegesExceptionMessage = Doit être exécuté avec des privilèges administratifs pour écouter sur des adresses autres que localhost. +certificateSuppliedForNonHttpsWssEndpointExceptionMessage = Certificat fourni pour un point de terminaison non HTTPS/WSS. +websocketsNotConfiguredForSignalMessagesExceptionMessage = Les WebSockets ne sont pas configurés pour envoyer des messages de signal. +noPathSuppliedForRouteExceptionMessage = Aucun chemin fourni pour la route. +accessRequiresAuthenticationOnRoutesExceptionMessage = L'accès nécessite une authentification sur les routes. +accessMethodDoesNotExistExceptionMessage = La méthode d'accès n'existe pas : {0}. +routeParameterNeedsValidScriptblockExceptionMessage = Le paramètre de la route nécessite un ScriptBlock valide et non vide. +noCommandsSuppliedToConvertToRoutesExceptionMessage = Aucune commande fournie pour convertir en routes. +nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Un ScriptBlock non vide est requis pour créer une route de page. +sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE ne peut être configuré que sur les requêtes avec une valeur d'en-tête Accept de text/event-stream. +sseConnectionNameRequiredExceptionMessage = Un nom de connexion SSE est requis, soit de -Name soit de $WebEvent.Sse.Name. +sseFailedToBroadcastExceptionMessage = SSE a échoué à diffuser en raison du niveau de diffusion SSE défini pour {0} : {1}. +podeNotInitializedExceptionMessage = Pode n'a pas été initialisé. +invalidTaskTypeExceptionMessage = Le type de tâche n'est pas valide, attendu [System.Threading.Tasks.Task] ou [hashtable]. +cannotLockValueTypeExceptionMessage = Impossible de verrouiller un [ValueTypes]. +cannotLockNullObjectExceptionMessage = Impossible de verrouiller un objet nul. +failedToAcquireLockExceptionMessage = Impossible d'acquérir un verrou sur l'objet. +cannotUnlockValueTypeExceptionMessage = Impossible de déverrouiller un [ValueTypes]. +cannotUnlockNullObjectExceptionMessage = Impossible de déverrouiller un objet nul. +sessionMiddlewareAlreadyInitializedExceptionMessage = Le Middleware de session a déjà été initialisé. +customSessionStorageMethodNotImplementedExceptionMessage = Le stockage de session personnalisé n'implémente pas la méthode requise '{0}()'. +secretRequiredForCustomSessionStorageExceptionMessage = Un secret est requis lors de l'utilisation d'un stockage de session personnalisé. +noSessionAvailableToSaveExceptionMessage = Aucune session disponible pour sauvegarder. +cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Impossible de fournir un intervalle lorsque le paramètre 'Every' est défini sur None. +cannotSupplyIntervalForQuarterExceptionMessage = Impossible de fournir une valeur d'intervalle pour chaque trimestre. +cannotSupplyIntervalForYearExceptionMessage = Impossible de fournir une valeur d'intervalle pour chaque année. +'@ \ No newline at end of file diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index 32ecfe5ff..8d7c8ab58 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -58,7 +58,7 @@ invalidMiddlewareTypeExceptionMessage = Uno dei Middleware forniti è di un tipo hashtableMiddlewareNoLogicExceptionMessage = Un Middleware di tipo Hashtable fornito non ha una logica definita. invalidLogicTypeInHashtableMiddlewareExceptionMessage = Un Middleware di tipo Hashtable fornito ha un tipo di logica non valido. Previsto ScriptBlock, ma ottenuto: {0} scopedVariableAlreadyDefinedExceptionMessage = Variabile con ambito già definita: {0} -valueForUsingVariableNotFoundExceptionMessage = Impossibile trovare il valore per `$using:{0}`. +valueForUsingVariableNotFoundExceptionMessage = Impossibile trovare il valore per '$using:{0}'. unlockSecretRequiredExceptionMessage = È necessaria una proprietà 'UnlockSecret' quando si utilizza Microsoft.PowerShell.SecretStore unlockSecretButNoScriptBlockExceptionMessage = Segreto di sblocco fornito per tipo di cassaforte segreta personalizzata, ma nessun ScriptBlock di sblocco fornito. noUnlockScriptBlockForVaultExceptionMessage = Nessun ScriptBlock di sblocco fornito per sbloccare la cassaforte '{0}' @@ -116,5 +116,52 @@ oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = Il provider OAuth oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = Il provider OAuth2 non supporta il tipo di concessione 'password' richiesto dall'utilizzo di un InnerScheme. eventAlreadyRegisteredExceptionMessage = Evento {0} già registrato: {1} noEventRegisteredExceptionMessage = Nessun evento {0} registrato: {1} -'@ - +sessionsRequiredForFlashMessagesExceptionMessage = Le sessioni sono necessarie per utilizzare i messaggi Flash. +eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = La registrazione nel Visualizzatore eventi è supportata solo su Windows. +nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = È richiesto uno ScriptBlock non vuoto per il metodo di registrazione personalizzato. +requestLoggingAlreadyEnabledExceptionMessage = La registrazione delle richieste è già abilitata. +outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = Il metodo di output fornito per la registrazione delle richieste richiede uno ScriptBlock valido. +errorLoggingAlreadyEnabledExceptionMessage = La registrazione degli errori è già abilitata. +nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = È richiesto uno ScriptBlock non vuoto per il metodo di registrazione. +csrfMiddlewareNotInitializedExceptionMessage = Il Middleware CSRF non è stato inizializzato. +sessionsRequiredForCsrfExceptionMessage = Le sessioni sono necessarie per utilizzare CSRF a meno che non si vogliano usare i cookie. +middlewareNoLogicSuppliedExceptionMessage = [Middleware]: Nessuna logica fornita nello ScriptBlock. +parameterHasNoNameExceptionMessage = Il parametro non ha un nome. Assegna un nome a questo componente usando il parametro 'Name'. +reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = La funzione del componente riutilizzabile 'pathItems' non è disponibile in OpenAPI v3.0. +noPropertiesMutuallyExclusiveExceptionMessage = Il parametro 'NoProperties' è mutuamente esclusivo con 'Properties', 'MinProperties' e 'MaxProperties'. +discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = Il parametro 'DiscriminatorMapping' può essere utilizzato solo quando è presente 'DiscriminatorProperty'. +discriminatorIncompatibleWithAllOfExceptionMessage = Il parametro 'Discriminator' è incompatibile con 'allOf'. +typeCanOnlyBeAssociatedWithObjectExceptionMessage = Il tipo {0} può essere associato solo a un oggetto. +showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui è attualmente disponibile solo per Windows PowerShell e PowerShell 7+ su Windows. +nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = È richiesto un nome per l'endpoint se viene fornito il parametro RedirectTo. +clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = I certificati client sono supportati solo sugli endpoint HTTPS. +explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = La modalità TLS esplicita è supportata solo sugli endpoint SMTPS e TCPS. +acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = Il messaggio di conferma è supportato solo sugli endpoint SMTP e TCP. +crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = Il controllo di fine messaggio CRLF è supportato solo sugli endpoint TCP. +mustBeRunningWithAdminPrivilegesExceptionMessage = Deve essere eseguito con privilegi di amministratore per ascoltare gli indirizzi non locali. +certificateSuppliedForNonHttpsWssEndpointExceptionMessage = Certificato fornito per un endpoint non HTTPS/WSS. +websocketsNotConfiguredForSignalMessagesExceptionMessage = I WebSockets non sono configurati per inviare messaggi di segnale. +noPathSuppliedForRouteExceptionMessage = Nessun percorso fornito per la rotta. +accessRequiresAuthenticationOnRoutesExceptionMessage = L'accesso richiede l'autenticazione sulle rotte. +accessMethodDoesNotExistExceptionMessage = Il metodo di accesso non esiste: {0}. +routeParameterNeedsValidScriptblockExceptionMessage = Il parametro della rotta richiede uno ScriptBlock valido e non vuoto. +noCommandsSuppliedToConvertToRoutesExceptionMessage = Nessun comando fornito per convertirlo in rotte. +nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = È richiesto uno ScriptBlock non vuoto per creare una rotta di pagina. +sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE può essere configurato solo su richieste con un valore di intestazione Accept di text/event-stream. +sseConnectionNameRequiredExceptionMessage = È richiesto un nome di connessione SSE, sia da -Name che da $WebEvent.Sse.Name. +sseFailedToBroadcastExceptionMessage = SSE non è riuscito a trasmettere a causa del livello di trasmissione SSE definito per {0}: {1}. +podeNotInitializedExceptionMessage = Pode non è stato inizializzato. +invalidTaskTypeExceptionMessage = Il tipo di attività non è valido, previsto [System.Threading.Tasks.Task] o [hashtable]. +cannotLockValueTypeExceptionMessage = Non è possibile bloccare un [ValueTypes]. +cannotLockNullObjectExceptionMessage = Non è possibile bloccare un oggetto nullo. +failedToAcquireLockExceptionMessage = Impossibile acquisire un blocco sull'oggetto. +cannotUnlockValueTypeExceptionMessage = Non è possibile sbloccare un [ValueTypes]. +cannotUnlockNullObjectExceptionMessage = Non è possibile sbloccare un oggetto nullo. +sessionMiddlewareAlreadyInitializedExceptionMessage = Il Middleware della sessione è già stato inizializzato. +customSessionStorageMethodNotImplementedExceptionMessage = L'archiviazione delle sessioni personalizzata non implementa il metodo richiesto '{0}()'. +secretRequiredForCustomSessionStorageExceptionMessage = È necessario un segreto quando si utilizza l'archiviazione delle sessioni personalizzata. +noSessionAvailableToSaveExceptionMessage = Nessuna sessione disponibile per il salvataggio. +cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Impossibile fornire un intervallo quando il parametro 'Every' è impostato su None. +cannotSupplyIntervalForQuarterExceptionMessage = Impossibile fornire un valore di intervallo per ogni trimestre. +cannotSupplyIntervalForYearExceptionMessage = Impossibile fornire un valore di intervallo per ogni anno. +'@ \ No newline at end of file diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index fb35ec625..ef6a43934 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -58,7 +58,7 @@ invalidMiddlewareTypeExceptionMessage = 提供されたMiddlewaresの1つが無 hashtableMiddlewareNoLogicExceptionMessage = 提供されたHashtableミドルウェアにロジックが定義されていません。 invalidLogicTypeInHashtableMiddlewareExceptionMessage = 提供されたHashtableミドルウェアに無効なロジック型があります。ScriptBlockを期待しましたが、次を取得しました: {0} scopedVariableAlreadyDefinedExceptionMessage = スコープ付き変数が既に定義されています: {0} -valueForUsingVariableNotFoundExceptionMessage = `$using:{0}`の値が見つかりませんでした。 +valueForUsingVariableNotFoundExceptionMessage = '$using:{0}'の値が見つかりませんでした。 unlockSecretRequiredExceptionMessage = Microsoft.PowerShell.SecretStoreを使用する場合、'UnlockSecret'プロパティが必要です。 unlockSecretButNoScriptBlockExceptionMessage = カスタムシークレットボールトタイプに対してアンロックシークレットが提供されましたが、アンロックスクリプトブロックが提供されていません。 noUnlockScriptBlockForVaultExceptionMessage = ボールト'{0}'のロック解除に必要なスクリプトブロックが提供されていません。 @@ -86,7 +86,7 @@ routeAlreadyContainsCustomAccessExceptionMessage = ルート '[{0}] {1}' はす accessMethodNotExistExceptionMessage = アクセス方法が存在しません: {0} pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = PathItems機能はOpenAPI v3.0.xではサポートされていません。 nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = カスタム認証スキームには空でないScriptBlockが必要です。 -oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerSchemeはBasicまたはFormのいずれかでなければなりませんが、取得したのは:{0} +oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerSchemeはBasicまたはFormのいずれかでなければなりませんが、取得したのは: {0} sessionsRequiredForOAuth2WithPKCEExceptionMessage = PKCEを使用するOAuth2にはセッションが必要です。 oauth2ClientSecretRequiredExceptionMessage = PKCEを使用しない場合、OAuth2にはクライアントシークレットが必要です。 authMethodAlreadyDefinedExceptionMessage = 認証方法はすでに定義されています:{0} @@ -116,4 +116,52 @@ oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = OAuth2プロバ oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = OAuth2プロバイダーはInnerSchemeを使用するために必要な'password' grant_typeをサポートしていません。 eventAlreadyRegisteredExceptionMessage = {0}イベントはすでに登録されています:{1} noEventRegisteredExceptionMessage = 登録された{0}イベントはありません:{1} +sessionsRequiredForFlashMessagesExceptionMessage = フラッシュメッセージを使用するにはセッションが必要です。 +eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = イベントビューアーロギングはWindowsでのみサポートされています。 +nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = カスタムロギング出力メソッドには空でないScriptBlockが必要です。 +requestLoggingAlreadyEnabledExceptionMessage = リクエストロギングは既に有効になっています。 +outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = リクエストロギングのために提供された出力メソッドには有効なScriptBlockが必要です。 +errorLoggingAlreadyEnabledExceptionMessage = エラーロギングは既に有効になっています。 +nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = ロギングメソッドには空でないScriptBlockが必要です。 +csrfMiddlewareNotInitializedExceptionMessage = CSRFミドルウェアが初期化されていません。 +sessionsRequiredForCsrfExceptionMessage = クッキーを使用しない場合は、CSRFを使用するためにセッションが必要です。 +middlewareNoLogicSuppliedExceptionMessage = [ミドルウェア]: ScriptBlockにロジックが提供されていません。 +parameterHasNoNameExceptionMessage = パラメーターに名前がありません。このコンポーネントに'Name'パラメーターを使用して名前を付けてください。 +reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = OpenAPI v3.0では再利用可能なコンポーネント機能'pathItems'は使用できません。 +noPropertiesMutuallyExclusiveExceptionMessage = パラメーター'NoProperties'は'Properties'、'MinProperties'、および'MaxProperties'と相互排他的です。 +discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = パラメーター'DiscriminatorMapping'は'DiscriminatorProperty'が存在する場合にのみ使用できます。 +discriminatorIncompatibleWithAllOfExceptionMessage = パラメーター'Discriminator'は'allOf'と互換性がありません。 +typeCanOnlyBeAssociatedWithObjectExceptionMessage = タイプ{0}はオブジェクトにのみ関連付けることができます。 +showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGuiは現在、Windows PowerShellおよびWindows上のPowerShell 7+でのみ利用可能です。 +nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = RedirectToパラメーターが提供されている場合、エンドポイントには名前が必要です。 +clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = クライアント証明書はHTTPSエンドポイントでのみサポートされています。 +explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 明示的なTLSモードはSMTPSおよびTCPSエンドポイントでのみサポートされています。 +acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 確認メッセージはSMTPおよびTCPエンドポイントでのみサポートされています。 +crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = CRLFメッセージ終了チェックはTCPエンドポイントでのみサポートされています。 +mustBeRunningWithAdminPrivilegesExceptionMessage = ローカルホスト以外のアドレスでリッスンするには管理者権限で実行する必要があります。 +certificateSuppliedForNonHttpsWssEndpointExceptionMessage = HTTPS/WSS以外のエンドポイントに提供された証明書。 +websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSocketsはシグナルメッセージを送信するように構成されていません。 +noPathSuppliedForRouteExceptionMessage = ルートのパスが提供されていません。 +accessRequiresAuthenticationOnRoutesExceptionMessage = アクセスにはルート上の認証が必要です。 +accessMethodDoesNotExistExceptionMessage = アクセスメソッドが存在しません:{0}。 +routeParameterNeedsValidScriptblockExceptionMessage = ルートパラメーターには有効で空でないScriptBlockが必要です。 +noCommandsSuppliedToConvertToRoutesExceptionMessage = ルートに変換するためのコマンドが提供されていません。 +nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = ページルートを作成するには空でないScriptBlockが必要です。 +sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSEはAcceptヘッダー値がtext/event-streamのリクエストでのみ構成できます。 +sseConnectionNameRequiredExceptionMessage = -Nameまたは$WebEvent.Sse.NameからSSE接続名が必要です。 +sseFailedToBroadcastExceptionMessage = {0}のSSEブロードキャストレベルが定義されているため、SSEのブロードキャストに失敗しました: {1} +podeNotInitializedExceptionMessage = Podeが初期化されていません。 +invalidTaskTypeExceptionMessage = タスクタイプが無効です。予期されるタイプ:[System.Threading.Tasks.Task]または[hashtable] +cannotLockValueTypeExceptionMessage = [ValueTypes]をロックできません。 +cannotLockNullObjectExceptionMessage = nullオブジェクトをロックできません。 +failedToAcquireLockExceptionMessage = オブジェクトのロックを取得できませんでした。 +cannotUnlockValueTypeExceptionMessage = [ValueTypes]のロックを解除できません。 +cannotUnlockNullObjectExceptionMessage = nullオブジェクトのロックを解除できません。 +sessionMiddlewareAlreadyInitializedExceptionMessage = セッションミドルウェアは既に初期化されています。 +customSessionStorageMethodNotImplementedExceptionMessage = カスタムセッションストレージは必要なメソッド'{0}()'を実装していません。 +secretRequiredForCustomSessionStorageExceptionMessage = カスタムセッションストレージを使用する場合、シークレットが必要です。 +noSessionAvailableToSaveExceptionMessage = 保存するためのセッションが利用できません。 +cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = パラメーター'Every'がNoneに設定されている場合、間隔を提供できません。 +cannotSupplyIntervalForQuarterExceptionMessage = 四半期ごとの間隔値を提供できません。 +cannotSupplyIntervalForYearExceptionMessage = 毎年の間隔値を提供できません。 '@ diff --git a/src/Locales/kr/Pode.psd1 b/src/Locales/kr/Pode.psd1 index f78551e2c..d75ec5c19 100644 --- a/src/Locales/kr/Pode.psd1 +++ b/src/Locales/kr/Pode.psd1 @@ -58,7 +58,7 @@ invalidMiddlewareTypeExceptionMessage = 제공된 미들웨어 중 하나가 잘 hashtableMiddlewareNoLogicExceptionMessage = 제공된 Hashtable 미들웨어에는 정의된 논리가 없습니다. invalidLogicTypeInHashtableMiddlewareExceptionMessage = 제공된 Hashtable 미들웨어에 잘못된 논리 유형이 있습니다. 예상된 유형은 ScriptBlock이지만, 얻은 것은: {0} scopedVariableAlreadyDefinedExceptionMessage = 범위 지정 변수가 이미 정의되었습니다: {0} -valueForUsingVariableNotFoundExceptionMessage = `$using:{0}`에 대한 값을 찾을 수 없습니다. +valueForUsingVariableNotFoundExceptionMessage = '$using:{0}'에 대한 값을 찾을 수 없습니다. unlockSecretRequiredExceptionMessage = Microsoft.PowerShell.SecretStore를 사용할 때 'UnlockSecret' 속성이 필요합니다. unlockSecretButNoScriptBlockExceptionMessage = 사용자 정의 비밀 금고 유형에 대해 제공된 Unlock 비밀이지만, Unlock ScriptBlock이 제공되지 않았습니다. noUnlockScriptBlockForVaultExceptionMessage = 금고 '{0}'을(를) 해제하는 Unlock ScriptBlock이 제공되지 않았습니다. @@ -116,4 +116,52 @@ oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = OAuth2 공급자 oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = OAuth2 공급자는 InnerScheme을 사용하는 데 필요한 'password' 부여 유형을 지원하지 않습니다. eventAlreadyRegisteredExceptionMessage = {0} 이벤트가 이미 등록되었습니다: {1} noEventRegisteredExceptionMessage = 등록된 {0} 이벤트가 없습니다: {1} -'@ +sessionsRequiredForFlashMessagesExceptionMessage = 플래시 메시지를 사용하려면 세션이 필요합니다. +eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = 이벤트 뷰어 로깅은 Windows에서만 지원됩니다. +nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 사용자 정의 로깅 출력 방법에는 비어 있지 않은 ScriptBlock이 필요합니다. +requestLoggingAlreadyEnabledExceptionMessage = 요청 로깅이 이미 활성화되었습니다. +outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = 요청 로깅에 제공된 출력 방법에는 유효한 ScriptBlock이 필요합니다. +errorLoggingAlreadyEnabledExceptionMessage = 오류 로깅이 이미 활성화되었습니다. +nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 로깅 방법에는 비어 있지 않은 ScriptBlock이 필요합니다. +csrfMiddlewareNotInitializedExceptionMessage = CSRF 미들웨어가 초기화되지 않았습니다. +sessionsRequiredForCsrfExceptionMessage = 쿠키를 사용하지 않으려면 CSRF 사용을 위해 세션이 필요합니다. +middlewareNoLogicSuppliedExceptionMessage = [미들웨어]: ScriptBlock에 로직이 제공되지 않았습니다. +parameterHasNoNameExceptionMessage = 매개변수에 이름이 없습니다. 'Name' 매개변수를 사용하여 이 구성 요소에 이름을 지정하십시오. +reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = OpenAPI v3.0에서는 재사용 가능한 구성 요소 기능 'pathItems'를 사용할 수 없습니다. +noPropertiesMutuallyExclusiveExceptionMessage = 매개변수 'NoProperties'는 'Properties', 'MinProperties' 및 'MaxProperties'와 상호 배타적입니다. +discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = 매개변수 'DiscriminatorMapping'은 'DiscriminatorProperty'가 있을 때만 사용할 수 있습니다. +discriminatorIncompatibleWithAllOfExceptionMessage = 매개변수 'Discriminator'는 'allOf'와 호환되지 않습니다. +typeCanOnlyBeAssociatedWithObjectExceptionMessage = 유형 {0}는 객체와만 연관될 수 있습니다. +showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui는 현재 Windows PowerShell 및 Windows의 PowerShell 7+에서만 사용할 수 있습니다. +nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = RedirectTo 매개변수가 제공된 경우 엔드포인트에 이름이 필요합니다. +clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 클라이언트 인증서는 HTTPS 엔드포인트에서만 지원됩니다. +explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 명시적 TLS 모드는 SMTPS 및 TCPS 엔드포인트에서만 지원됩니다. +acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 확인 메시지는 SMTP 및 TCP 엔드포인트에서만 지원됩니다. +crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = CRLF 메시지 끝 검사는 TCP 엔드포인트에서만 지원됩니다. +mustBeRunningWithAdminPrivilegesExceptionMessage = 관리자 권한으로 실행되어야 비로소 로컬호스트 주소가 아닌 주소를 청취할 수 있습니다. +certificateSuppliedForNonHttpsWssEndpointExceptionMessage = HTTPS/WSS가 아닌 엔드포인트에 제공된 인증서입니다. +websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSockets가 신호 메시지를 보내도록 구성되지 않았습니다. +noPathSuppliedForRouteExceptionMessage = 경로에 대해 제공된 경로가 없습니다. +accessRequiresAuthenticationOnRoutesExceptionMessage = 경로에 대한 접근은 인증이 필요합니다. +accessMethodDoesNotExistExceptionMessage = 접근 방법이 존재하지 않습니다: {0}. +routeParameterNeedsValidScriptblockExceptionMessage = 경로 매개변수에는 유효하고 비어 있지 않은 ScriptBlock이 필요합니다. +noCommandsSuppliedToConvertToRoutesExceptionMessage = 경로로 변환할 명령이 제공되지 않았습니다. +nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 페이지 경로를 생성하려면 비어 있지 않은 ScriptBlock이 필요합니다. +sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE는 Accept 헤더 값이 text/event-stream인 요청에서만 구성할 수 있습니다. +sseConnectionNameRequiredExceptionMessage = -Name 또는 $WebEvent.Sse.Name에서 SSE 연결 이름이 필요합니다. +sseFailedToBroadcastExceptionMessage = {0}에 대해 정의된 SSE 브로드캐스트 수준으로 인해 SSE 브로드캐스트에 실패했습니다: {1} +podeNotInitializedExceptionMessage = Pode가 초기화되지 않았습니다. +invalidTaskTypeExceptionMessage = 작업 유형이 유효하지 않습니다. 예상된 유형: [System.Threading.Tasks.Task] 또는 [hashtable] +cannotLockValueTypeExceptionMessage = [ValueTypes]를 잠글 수 없습니다. +cannotLockNullObjectExceptionMessage = null 개체를 잠글 수 없습니다. +failedToAcquireLockExceptionMessage = 개체에 대한 잠금을 획득하지 못했습니다. +cannotUnlockValueTypeExceptionMessage = [ValueTypes]를 잠금 해제할 수 없습니다. +cannotUnlockNullObjectExceptionMessage = null 개체를 잠금 해제할 수 없습니다. +sessionMiddlewareAlreadyInitializedExceptionMessage = 세션 미들웨어가 이미 초기화되었습니다. +customSessionStorageMethodNotImplementedExceptionMessage = 사용자 정의 세션 저장소가 필요한 메서드 '{0}()'를 구현하지 않았습니다. +secretRequiredForCustomSessionStorageExceptionMessage = 사용자 정의 세션 저장소를 사용할 때는 비밀이 필요합니다. +noSessionAvailableToSaveExceptionMessage = 저장할 수 있는 세션이 없습니다. +cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = 매개변수 'Every'가 None으로 설정된 경우 간격을 제공할 수 없습니다. +cannotSupplyIntervalForQuarterExceptionMessage = 분기별 간격 값을 제공할 수 없습니다. +cannotSupplyIntervalForYearExceptionMessage = 매년 간격 값을 제공할 수 없습니다. +'@ \ No newline at end of file diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index 3ff8acb85..08b432c82 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -58,7 +58,7 @@ invalidMiddlewareTypeExceptionMessage = Jeden z dostarczonych Middleware jest ni hashtableMiddlewareNoLogicExceptionMessage = Dostarczone Middleware typu Hashtable nie ma zdefiniowanej logiki. invalidLogicTypeInHashtableMiddlewareExceptionMessage = Dostarczone Middleware typu Hashtable ma nieprawidłowy typ logiki. Oczekiwano ScriptBlock, ale otrzymano: {0} scopedVariableAlreadyDefinedExceptionMessage = Zmienna z zakresem już zdefiniowana: {0} -valueForUsingVariableNotFoundExceptionMessage = Nie można znaleźć wartości dla `$using:{0}`. +valueForUsingVariableNotFoundExceptionMessage = Nie można znaleźć wartości dla '$using:{0}'. unlockSecretRequiredExceptionMessage = Właściwość 'UnlockSecret' jest wymagana przy używaniu Microsoft.PowerShell.SecretStore unlockSecretButNoScriptBlockExceptionMessage = Podano tajemnicę odblokowania dla niestandardowego typu skarbca, ale nie podano ScriptBlock odblokowania. noUnlockScriptBlockForVaultExceptionMessage = Nie podano ScriptBlock odblokowania dla odblokowania skarbca '{0}' @@ -116,4 +116,52 @@ oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = Dostawca OAuth2 n oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = Dostawca OAuth2 nie obsługuje typu 'password' wymaganego przez InnerScheme. eventAlreadyRegisteredExceptionMessage = Wydarzenie {0} już zarejestrowane: {1} noEventRegisteredExceptionMessage = Brak zarejestrowanego wydarzenia {0}: {1} -'@ +sessionsRequiredForFlashMessagesExceptionMessage = Sesje są wymagane do używania wiadomości Flash. +eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = Rejestrowanie w Podglądzie zdarzeń jest obsługiwane tylko w systemie Windows. +nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = Metoda niestandardowego rejestrowania wymaga niepustego ScriptBlock. +requestLoggingAlreadyEnabledExceptionMessage = Rejestrowanie żądań jest już włączone. +outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = Podana metoda wyjściowa do rejestrowania żądań wymaga prawidłowego ScriptBlock. +errorLoggingAlreadyEnabledExceptionMessage = Rejestrowanie błędów jest już włączone. +nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = Metoda rejestrowania wymaga niepustego ScriptBlock. +csrfMiddlewareNotInitializedExceptionMessage = Middleware CSRF nie został zainicjowany. +sessionsRequiredForCsrfExceptionMessage = Sesje są wymagane do używania CSRF, chyba że chcesz używać ciasteczek. +middlewareNoLogicSuppliedExceptionMessage = [Middleware]: Nie dostarczono logiki w ScriptBlock. +parameterHasNoNameExceptionMessage = Parametr nie ma nazwy. Proszę nadać tej części nazwę za pomocą parametru 'Name'. +reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = Funkcja wielokrotnego użytku 'pathItems' nie jest dostępna w OpenAPI v3.0. +noPropertiesMutuallyExclusiveExceptionMessage = Parametr 'NoProperties' jest wzajemnie wykluczający się z 'Properties', 'MinProperties' i 'MaxProperties'. +discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = Parametr 'DiscriminatorMapping' może być używany tylko wtedy, gdy jest obecna właściwość 'DiscriminatorProperty'. +discriminatorIncompatibleWithAllOfExceptionMessage = Parametr 'Discriminator' jest niezgodny z 'allOf'. +typeCanOnlyBeAssociatedWithObjectExceptionMessage = Typ {0} może być powiązany tylko z obiektem. +showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui jest obecnie dostępne tylko dla Windows PowerShell i PowerShell 7+ w Windows. +nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = Nazwa jest wymagana dla punktu końcowego, jeśli podano parametr RedirectTo. +clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = Certyfikaty klienta są obsługiwane tylko na punktach końcowych HTTPS. +explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = Tryb TLS Explicity jest obsługiwany tylko na punktach końcowych SMTPS i TCPS. +acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = Komunikat potwierdzenia jest obsługiwany tylko na punktach końcowych SMTP i TCP. +crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = Sprawdzanie końca wiadomości CRLF jest obsługiwane tylko na punktach końcowych TCP. +mustBeRunningWithAdminPrivilegesExceptionMessage = Musisz mieć uprawnienia administratora, aby nasłuchiwać na adresach innych niż localhost. +certificateSuppliedForNonHttpsWssEndpointExceptionMessage = Certyfikat dostarczony dla punktu końcowego innego niż HTTPS/WSS. +websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSockets nie zostały skonfigurowane do wysyłania wiadomości sygnałowych. +noPathSuppliedForRouteExceptionMessage = Nie podano ścieżki dla trasy. +accessRequiresAuthenticationOnRoutesExceptionMessage = Dostęp wymaga uwierzytelnienia na trasach. +accessMethodDoesNotExistExceptionMessage = Metoda dostępu nie istnieje: {0}. +routeParameterNeedsValidScriptblockExceptionMessage = Parametr trasy wymaga prawidłowego, niepustego ScriptBlock. +noCommandsSuppliedToConvertToRoutesExceptionMessage = Nie dostarczono żadnych poleceń do konwersji na trasy. +nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Aby utworzyć trasę strony, wymagany jest niepusty ScriptBlock. +sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE można skonfigurować tylko na żądaniach z wartością nagłówka Accept równą text/event-stream. +sseConnectionNameRequiredExceptionMessage = Wymagana jest nazwa połączenia SSE, z -Name lub $WebEvent.Sse.Name. +sseFailedToBroadcastExceptionMessage = SSE nie udało się przesłać z powodu zdefiniowanego poziomu przesyłania SSE dla {0}: {1} +podeNotInitializedExceptionMessage = Pode nie został zainicjowany. +invalidTaskTypeExceptionMessage = Typ zadania jest nieprawidłowy, oczekiwano [System.Threading.Tasks.Task] lub [hashtable] +cannotLockValueTypeExceptionMessage = Nie można zablokować [ValueTypes]. +cannotLockNullObjectExceptionMessage = Nie można zablokować pustego obiektu. +failedToAcquireLockExceptionMessage = Nie udało się uzyskać blokady na obiekcie. +cannotUnlockValueTypeExceptionMessage = Nie można odblokować [ValueTypes]. +cannotUnlockNullObjectExceptionMessage = Nie można odblokować pustego obiektu. +sessionMiddlewareAlreadyInitializedExceptionMessage = Middleware sesji został już zainicjowany. +customSessionStorageMethodNotImplementedExceptionMessage = Niestandardowe przechowywanie sesji nie implementuje wymaganego ''{0}()'' sposobu. +secretRequiredForCustomSessionStorageExceptionMessage = Podczas korzystania z niestandardowego przechowywania sesji wymagany jest sekret. +noSessionAvailableToSaveExceptionMessage = Brak dostępnej sesji do zapisania. +cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Nie można dostarczyć interwału, gdy parametr 'Every' jest ustawiony na None. +cannotSupplyIntervalForQuarterExceptionMessage = Nie można dostarczyć wartości interwału dla każdego kwartału. +cannotSupplyIntervalForYearExceptionMessage = Nie można dostarczyć wartości interwału dla każdego roku. +'@ \ No newline at end of file diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index 280644726..9f1e5f315 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -58,7 +58,7 @@ invalidMiddlewareTypeExceptionMessage = Um dos Middlewares fornecidos é de um t hashtableMiddlewareNoLogicExceptionMessage = Um Middleware do tipo Hashtable fornecido não tem lógica definida. invalidLogicTypeInHashtableMiddlewareExceptionMessage = Um Middleware do tipo Hashtable fornecido tem um tipo de lógica inválido. Esperado ScriptBlock, mas obtido: {0} scopedVariableAlreadyDefinedExceptionMessage = Variável de escopo já definida: {0} -valueForUsingVariableNotFoundExceptionMessage = Valor para `$using:{0}` não pôde ser encontrado. +valueForUsingVariableNotFoundExceptionMessage = Valor para '$using:{0}' não pôde ser encontrado. unlockSecretRequiredExceptionMessage = É necessária uma propriedade 'UnlockSecret' ao usar Microsoft.PowerShell.SecretStore unlockSecretButNoScriptBlockExceptionMessage = Segredo de desbloqueio fornecido para tipo de Cofre Secreto personalizado, mas nenhum ScriptBlock de desbloqueio fornecido. noUnlockScriptBlockForVaultExceptionMessage = Nenhum ScriptBlock de desbloqueio fornecido para desbloquear o cofre '{0}' @@ -116,4 +116,52 @@ oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = O provedor OAuth2 oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = O provedor OAuth2 não suporta o grant_type 'password' necessário ao usar um InnerScheme. eventAlreadyRegisteredExceptionMessage = Evento {0} já registrado: {1} noEventRegisteredExceptionMessage = Nenhum evento {0} registrado: {1} -'@ +sessionsRequiredForFlashMessagesExceptionMessage = Sessões são necessárias para usar mensagens Flash. +eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = O registro no Visualizador de Eventos é suportado apenas no Windows. +nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = Um ScriptBlock não vazio é necessário para o método de registro personalizado. +requestLoggingAlreadyEnabledExceptionMessage = O registro de solicitações já está habilitado. +outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = O método de saída fornecido para o registro de solicitações requer um ScriptBlock válido. +errorLoggingAlreadyEnabledExceptionMessage = O registro de erros já está habilitado. +nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = Um ScriptBlock não vazio é necessário para o método de registro. +csrfMiddlewareNotInitializedExceptionMessage = O Middleware CSRF não foi inicializado. +sessionsRequiredForCsrfExceptionMessage = Sessões são necessárias para usar CSRF, a menos que você queira usar cookies. +middlewareNoLogicSuppliedExceptionMessage = [Middleware]: Nenhuma lógica fornecida no ScriptBlock. +parameterHasNoNameExceptionMessage = O parâmetro não tem nome. Dê um nome a este componente usando o parâmetro 'Name'. +reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = O recurso de componente reutilizável 'pathItems' não está disponível no OpenAPI v3.0. +noPropertiesMutuallyExclusiveExceptionMessage = O parâmetro 'NoProperties' é mutuamente exclusivo com 'Properties', 'MinProperties' e 'MaxProperties'. +discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = O parâmetro 'DiscriminatorMapping' só pode ser usado quando 'DiscriminatorProperty' está presente. +discriminatorIncompatibleWithAllOfExceptionMessage = O parâmetro 'Discriminator' é incompatível com 'allOf'. +typeCanOnlyBeAssociatedWithObjectExceptionMessage = O tipo {0} só pode ser associado a um Objeto. +showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui está atualmente disponível apenas para Windows PowerShell e PowerShell 7+ no Windows. +nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = Um nome é necessário para o endpoint se o parâmetro RedirectTo for fornecido. +clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = Certificados de cliente são suportados apenas em endpoints HTTPS. +explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = O modo TLS explícito é suportado apenas em endpoints SMTPS e TCPS. +acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = A mensagem de reconhecimento é suportada apenas em endpoints SMTP e TCP. +crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = A verificação de fim de mensagem CRLF é suportada apenas em endpoints TCP. +mustBeRunningWithAdminPrivilegesExceptionMessage = Deve estar sendo executado com privilégios de administrador para escutar endereços que não sejam localhost. +certificateSuppliedForNonHttpsWssEndpointExceptionMessage = Certificado fornecido para endpoint que não é HTTPS/WSS. +websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSockets não estão configurados para enviar mensagens de sinal. +noPathSuppliedForRouteExceptionMessage = Nenhum caminho fornecido para a Rota. +accessRequiresAuthenticationOnRoutesExceptionMessage = O acesso requer autenticação nas rotas. +accessMethodDoesNotExistExceptionMessage = O método de acesso não existe: {0}. +routeParameterNeedsValidScriptblockExceptionMessage = O parâmetro da Rota precisa de um ScriptBlock válido e não vazio. +noCommandsSuppliedToConvertToRoutesExceptionMessage = Nenhum comando fornecido para converter em Rotas. +nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Um ScriptBlock não vazio é necessário para criar uma Rota de Página. +sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE só pode ser configurado em solicitações com um valor de cabeçalho Accept de text/event-stream. +sseConnectionNameRequiredExceptionMessage = Um nome de conexão SSE é necessário, seja de -Name ou $WebEvent.Sse.Name. +sseFailedToBroadcastExceptionMessage = SSE falhou em transmitir devido ao nível de transmissão SSE definido para {0}: {1}. +podeNotInitializedExceptionMessage = Pode não foi inicializado. +invalidTaskTypeExceptionMessage = O tipo de tarefa é inválido, esperado [System.Threading.Tasks.Task] ou [hashtable]. +cannotLockValueTypeExceptionMessage = Não é possível bloquear um [ValueTypes]. +cannotLockNullObjectExceptionMessage = Não é possível bloquear um objeto nulo. +failedToAcquireLockExceptionMessage = Falha ao adquirir um bloqueio no objeto. +cannotUnlockValueTypeExceptionMessage = Não é possível desbloquear um [ValueTypes]. +cannotUnlockNullObjectExceptionMessage = Não é possível desbloquear um objeto nulo. +sessionMiddlewareAlreadyInitializedExceptionMessage = O Middleware de Sessão já foi inicializado. +customSessionStorageMethodNotImplementedExceptionMessage = O armazenamento de sessão personalizado não implementa o método requerido '{0}()'. +secretRequiredForCustomSessionStorageExceptionMessage = Um segredo é necessário ao usar armazenamento de sessão personalizado. +noSessionAvailableToSaveExceptionMessage = Não há sessão disponível para salvar. +cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Não é possível fornecer um intervalo quando o parâmetro 'Every' está definido como None. +cannotSupplyIntervalForQuarterExceptionMessage = Não é possível fornecer um valor de intervalo para cada trimestre. +cannotSupplyIntervalForYearExceptionMessage = Não é possível fornecer um valor de intervalo para cada ano. +'@ \ No newline at end of file diff --git a/src/Locales/zn/Pode.psd1 b/src/Locales/zn/Pode.psd1 index 26456390f..8d22b0ab4 100644 --- a/src/Locales/zn/Pode.psd1 +++ b/src/Locales/zn/Pode.psd1 @@ -31,7 +31,7 @@ invalidBase64JwtExceptionMessage = 在 JWT 中找到无效的 Base64 编码值 invalidJsonJwtExceptionMessage = 在 JWT 中找到无效的 JSON 值 unsupportedFunctionInServerlessContextExceptionMessage = 不支持在无服务器上下文中使用 {0} 函数。 invalidPathWildcardOrDirectoryExceptionMessage = 提供的路径不能是通配符或目录: {0} -invalidExceptionTypeExceptionMessage = 异常类型无效,应为 WebException 或 HttpRequestException,但得到了: {0} +invalidExceptionTypeExceptionMessage = 异常类型无效,应为 WebException 或 HttpRequestException, 但得到了: {0} pathToLoadNotFoundExceptionMessage = 未找到要加载的路径 {0}: {1} singleValueForIntervalExceptionMessage = 当使用间隔时,只能提供单个 {0} 值。 scriptErrorExceptionMessage = 脚本 '{0}' 在 {1} {2} (第 {3} 行) 第 {4} 个字符处执行 {5} 对象 '{7}' 的错误。类: {8} 基类: {9} @@ -54,11 +54,11 @@ openApiDocumentNotCompliantExceptionMessage = OpenAPI 文档不符合规范。 noComponentInDefinitionExceptionMessage = 定义中没有类型为 {0} 名称为 {1} 的组件。 methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: 已经定义。 methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: 已经为 {2} 定义。 -invalidMiddlewareTypeExceptionMessage = 提供的中间件之一是无效的类型。期望是 ScriptBlock 或 Hashtable,但得到了: {0} +invalidMiddlewareTypeExceptionMessage = 提供的中间件之一是无效的类型。期望是 ScriptBlock 或 Hashtable, 但得到了: {0} hashtableMiddlewareNoLogicExceptionMessage = 提供的 Hashtable 中间件没有定义逻辑。 -invalidLogicTypeInHashtableMiddlewareExceptionMessage = 提供的 Hashtable 中间件具有无效的逻辑类型。期望是 ScriptBlock,但得到了: {0} +invalidLogicTypeInHashtableMiddlewareExceptionMessage = 提供的 Hashtable 中间件具有无效的逻辑类型。期望是 ScriptBlockm, 但得到了: {0} scopedVariableAlreadyDefinedExceptionMessage = 已经定义了作用域变量: {0} -valueForUsingVariableNotFoundExceptionMessage = 未找到 `$using:{0}` 的值。 +valueForUsingVariableNotFoundExceptionMessage = 未找到 '$using:{0}' 的值。 unlockSecretRequiredExceptionMessage = 使用 Microsoft.PowerShell.SecretStore 时需要 'UnlockSecret' 属性。 unlockSecretButNoScriptBlockExceptionMessage = 为自定义秘密保险库类型提供了解锁密钥,但未提供解锁 ScriptBlock。 noUnlockScriptBlockForVaultExceptionMessage = 未为解锁保险库 '{0}' 提供解锁 ScriptBlock。 @@ -88,7 +88,7 @@ pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 在 OpenAPI v3.0.x 中 nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 自定义身份验证方案需要一个非空的 ScriptBlock。 oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme 只能是 Basic 或 Form 身份验证,但得到:{0} sessionsRequiredForOAuth2WithPKCEExceptionMessage = 使用 PKCE 时需要会话来使用 OAuth2 -oauth2ClientSecretRequiredExceptionMessage = 不使用 PKCE 时,OAuth2 需要一个客户端密钥。 +oauth2ClientSecretRequiredExceptionMessage = 不使用 PKCE 时, OAuth2 需要一个客户端密钥。 authMethodAlreadyDefinedExceptionMessage = 身份验证方法已定义:{0} invalidSchemeForAuthValidatorExceptionMessage = 提供的 '{0}' 方案用于 '{1}' 身份验证验证器,需要一个有效的 ScriptBlock。 sessionsRequiredForSessionPersistentAuthExceptionMessage = 使用会话持久性身份验证需要会话。 @@ -116,4 +116,52 @@ oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = OAuth2 提供程 oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = OAuth2 提供程序不支持使用 InnerScheme 所需的 'password' grant_type。 eventAlreadyRegisteredExceptionMessage = {0} 事件已注册:{1} noEventRegisteredExceptionMessage = 没有注册的 {0} 事件:{1} -'@ +sessionsRequiredForFlashMessagesExceptionMessage = 使用闪存消息需要会话。 +eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = 事件查看器日志记录仅支持Windows。 +nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 自定义日志输出方法需要非空的ScriptBlock。 +requestLoggingAlreadyEnabledExceptionMessage = 请求日志记录已启用。 +outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = 请求日志记录提供的输出方法需要有效的ScriptBlock。 +errorLoggingAlreadyEnabledExceptionMessage = 错误日志记录已启用。 +nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 日志记录方法需要非空的ScriptBlock。 +csrfMiddlewareNotInitializedExceptionMessage = CSRF中间件未初始化。 +sessionsRequiredForCsrfExceptionMessage = 使用CSRF需要会话, 除非您想使用Cookie。 +middlewareNoLogicSuppliedExceptionMessage = [中间件]: ScriptBlock中未提供逻辑。 +parameterHasNoNameExceptionMessage = 参数没有名称。请使用'Name'参数为此组件命名。 +reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = OpenAPI v3.0中不支持可重用组件功能'pathItems'。 +noPropertiesMutuallyExclusiveExceptionMessage = 参数'NoProperties'与'Properties'、'MinProperties'和'MaxProperties'互斥。 +discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = 参数'DiscriminatorMapping'只能在存在'DiscriminatorProperty'时使用。 +discriminatorIncompatibleWithAllOfExceptionMessage = 参数'Discriminator'与'allOf'不兼容。 +typeCanOnlyBeAssociatedWithObjectExceptionMessage = 类型{0}只能与对象关联。 +showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui目前仅适用于Windows PowerShell和Windows上的PowerShell 7+。 +nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = 如果提供了RedirectTo参数, 则需要为端点指定名称。 +clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 客户端证书仅支持HTTPS端点。 +explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 显式TLS模式仅支持SMTPS和TCPS端点。 +acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 确认消息仅支持SMTP和TCP端点。 +crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = CRLF消息结束检查仅支持TCP端点。 +mustBeRunningWithAdminPrivilegesExceptionMessage = 必须以管理员权限运行才能监听非本地主机地址。 +certificateSuppliedForNonHttpsWssEndpointExceptionMessage = 为非HTTPS/WSS端点提供的证书。 +websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSockets未配置为发送信号消息。 +noPathSuppliedForRouteExceptionMessage = 未为路由提供路径。 +accessRequiresAuthenticationOnRoutesExceptionMessage = 访问需要在路由上进行身份验证。 +accessMethodDoesNotExistExceptionMessage = 访问方法不存在:{0}。 +routeParameterNeedsValidScriptblockExceptionMessage = 路由参数需要有效且非空的ScriptBlock。 +noCommandsSuppliedToConvertToRoutesExceptionMessage = 未提供要转换为路由的命令。 +nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 创建页面路由需要非空的ScriptBlock。 +sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE只能在Accept标头值为text/event-stream的请求上配置。 +sseConnectionNameRequiredExceptionMessage = 需要SSE连接名称, 可以从-Name或$WebEvent.Sse.Name获取。 +sseFailedToBroadcastExceptionMessage = 由于为{0}定义的SSE广播级别, SSE广播失败: {1} +podeNotInitializedExceptionMessage = Pode未初始化。 +invalidTaskTypeExceptionMessage = 任务类型无效,预期类型为[System.Threading.Tasks.Task]或[hashtable]。 +cannotLockValueTypeExceptionMessage = 无法锁定[ValueTypes]。 +cannotLockNullObjectExceptionMessage = 无法锁定空对象。 +failedToAcquireLockExceptionMessage = 未能获取对象的锁。 +cannotUnlockValueTypeExceptionMessage = 无法解锁[ValueTypes]。 +cannotUnlockNullObjectExceptionMessage = 无法解锁空对象。 +sessionMiddlewareAlreadyInitializedExceptionMessage = 会话中间件已初始化。 +customSessionStorageMethodNotImplementedExceptionMessage = 自定义会话存储未实现所需的方法'{0}()'。 +secretRequiredForCustomSessionStorageExceptionMessage = 使用自定义会话存储时需要一个密钥。 +noSessionAvailableToSaveExceptionMessage = 没有可保存的会话。 +cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = 当参数'Every'设置为None时, 无法提供间隔。 +cannotSupplyIntervalForQuarterExceptionMessage = 无法为每季度提供间隔值。 +cannotSupplyIntervalForYearExceptionMessage = 无法为每年提供间隔值。 +'@ \ No newline at end of file diff --git a/src/Private/Authentication.ps1 b/src/Private/Authentication.ps1 index 97a812b21..6acaa91c4 100644 --- a/src/Private/Authentication.ps1 +++ b/src/Private/Authentication.ps1 @@ -2194,11 +2194,13 @@ function Expand-PodeAuthMerge { function Import-PodeAuthADModule { if (!(Test-PodeIsWindows)) { - throw $msgTable.adModuleWindowsOnlyExceptionMessage #'Active Directory module only available on Windows' + # Active Directory module only available on Windows + throw $msgTable.adModuleWindowsOnlyExceptionMessage } if (!(Test-PodeModuleInstalled -Name ActiveDirectory)) { - throw $msgTable.adModuleNotInstalledExceptionMessage #'Active Directory module is not installed' + # Active Directory module is not installed + throw $msgTable.adModuleNotInstalledExceptionMessage } Import-Module -Name ActiveDirectory -Force -ErrorAction Stop diff --git a/src/Private/AutoImport.ps1 b/src/Private/AutoImport.ps1 index 65f1f0b9e..3bf5f0828 100644 --- a/src/Private/AutoImport.ps1 +++ b/src/Private/AutoImport.ps1 @@ -177,7 +177,8 @@ function Import-PodeSecretManagementVaultsIntoRegistry { # error if SecretManagement module not installed if (!(Test-PodeModuleInstalled -Name Microsoft.PowerShell.SecretManagement)) { - throw $msgTable.secretManagementModuleNotInstalledExceptionMessage #'Microsoft.PowerShell.SecretManagement module not installed' + # Microsoft.PowerShell.SecretManagement module not installed + throw $msgTable.secretManagementModuleNotInstalledExceptionMessage } # import the module diff --git a/src/Private/Cryptography.ps1 b/src/Private/Cryptography.ps1 index c0f76de02..d77012fe2 100644 --- a/src/Private/Cryptography.ps1 +++ b/src/Private/Cryptography.ps1 @@ -19,7 +19,8 @@ function Invoke-PodeHMACSHA256Hash { } if ($SecretBytes.Length -eq 0) { - throw $msgTable.noSecretForHmac256ExceptionMessage #'No secret supplied for HMAC256 hash' + # No secret supplied for HMAC256 hash + throw $msgTable.noSecretForHmac256ExceptionMessage } $crypto = [System.Security.Cryptography.HMACSHA256]::new($SecretBytes) @@ -47,7 +48,8 @@ function Invoke-PodeHMACSHA384Hash { } if ($SecretBytes.Length -eq 0) { - throw $msgTable.noSecretForHmac384ExceptionMessage #'No secret supplied for HMAC384 hash' + # No secret supplied for HMAC384 hash + throw $msgTable.noSecretForHmac384ExceptionMessage } $crypto = [System.Security.Cryptography.HMACSHA384]::new($SecretBytes) @@ -75,7 +77,8 @@ function Invoke-PodeHMACSHA512Hash { } if ($SecretBytes.Length -eq 0) { - throw $msgTable.noSecretForHmac512ExceptionMessage #'No secret supplied for HMAC512 hash' + # No secret supplied for HMAC512 hash + throw $msgTable.noSecretForHmac512ExceptionMessage } $crypto = [System.Security.Cryptography.HMACSHA512]::new($SecretBytes) @@ -304,11 +307,13 @@ function New-PodeJwtSignature { ) if (($Algorithm -ine 'none') -and (($null -eq $SecretBytes) -or ($SecretBytes.Length -eq 0))) { - throw $msgTable.noSecretForJwtSignatureExceptionMessage #'No Secret supplied for JWT signature' + # No secret supplied for JWT signature + throw $msgTable.noSecretForJwtSignatureExceptionMessage } if (($Algorithm -ieq 'none') -and (($null -ne $secretBytes) -and ($SecretBytes.Length -gt 0))) { - throw $msgTable.noSecretExpectedForNoSignatureExceptionMessage #'Expected no secret to be supplied for no signature' + # Expected no secret to be supplied for no signature + throw $msgTable.noSecretExpectedForNoSignatureExceptionMessage } $sig = $null @@ -393,7 +398,8 @@ function ConvertFrom-PodeJwtBase64Value { $Value = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Value)) } catch { - throw $msgTable.invalidBase64JwtExceptionMessage #'Invalid Base64 encoded value found in JWT' + # Invalid Base64 encoded value found in JWT + throw $msgTable.invalidBase64JwtExceptionMessage } # return json @@ -401,6 +407,7 @@ function ConvertFrom-PodeJwtBase64Value { return ($Value | ConvertFrom-Json) } catch { - throw $msgTable.invalidJsonJwtExceptionMessage #'Invalid JSON value found in JWT' + # Invalid JSON value found in JWT + throw $msgTable.invalidJsonJwtExceptionMessage } } \ No newline at end of file diff --git a/src/Private/Middleware.ps1 b/src/Private/Middleware.ps1 index 8d621dcd1..182f38339 100644 --- a/src/Private/Middleware.ps1 +++ b/src/Private/Middleware.ps1 @@ -78,7 +78,8 @@ function New-PodeMiddlewareInternal { ) if (Test-PodeIsEmpty $ScriptBlock) { - throw $msgTable.noScriptBlockSuppliedExceptionMessage #'No ScriptBlock supplied' + # No ScriptBlock supplied + throw $msgTable.noScriptBlockSuppliedExceptionMessage } # if route is empty, set it to root @@ -392,7 +393,8 @@ function Initialize-PodeIISMiddleware { # fail if no iis token - because there should be! if ([string]::IsNullOrWhiteSpace($PodeContext.Server.IIS.Token)) { - throw $msgTable.iisAspnetcoreTokenMissingExceptionMessage #'IIS ASPNETCORE_TOKEN is missing' + # IIS ASPNETCORE_TOKEN is missing + throw $msgTable.iisAspnetcoreTokenMissingExceptionMessage } # add middleware to check every request has the token diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index d3e56cf8a..69c708a92 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -181,7 +181,8 @@ function ConvertTo-PodeOAObjectSchema { } } else { - Throw $msgTable.propertiesParameterWithoutNameExceptionMessage #'The Properties parameters cannot be used if the Property has no name' + # The Properties parameters cannot be used if the Property has no name + Throw $msgTable.propertiesParameterWithoutNameExceptionMessage } } else { @@ -373,7 +374,8 @@ function ConvertTo-PodeOASchemaProperty { $schema = [ordered]@{ } if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag ) { if ($Property.type -is [string[]]) { - throw $msgTable.multiTypePropertiesRequireOpenApi31ExceptionMessage#'Multi type properties requeired OpenApi Version 3.1 or above' + # Multi type properties requeired OpenApi Version 3.1 or above + throw $msgTable.multiTypePropertiesRequireOpenApi31ExceptionMessage } $schema['type'] = $Property.type.ToLower() } @@ -806,7 +808,8 @@ function Get-PodeOpenApiDefinitionInternal { $Definition = $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag] if (!$Definition.Version) { - throw $msgTable.openApiVersionPropertyMandatoryExceptionMessage#'OpenApi Version property is mandatory' + # OpenApi Version property is mandatory + throw $msgTable.openApiVersionPropertyMandatoryExceptionMessage } $localEndpoint = $null # set the openapi version @@ -862,7 +865,8 @@ function Get-PodeOpenApiDefinitionInternal { $def['paths'] = [ordered]@{} if ($Definition.webhooks.count -gt 0) { if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag) { - throw $msgTable.webhooksFeatureNotSupportedInOpenApi30ExceptionMessage #'Webhooks feature is unsupported in OpenAPI v3.0.x' + # Webhooks feature is unsupported in OpenAPI v3.0.x + throw $msgTable.webhooksFeatureNotSupportedInOpenApi30ExceptionMessage } else { $keys = [string[]]$Definition.webhooks.Keys @@ -909,7 +913,8 @@ function Get-PodeOpenApiDefinitionInternal { } if ($components.pathItems.count -gt 0) { if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag) { - throw $msgTable.pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage #'Feature pathItems is unsupported in OpenAPI v3.0.x' + # Feature pathItems is unsupported in OpenAPI v3.0.x + throw $msgTable.pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage } else { $keys = [string[]]$components.pathItems.Keys @@ -1457,7 +1462,8 @@ function Resolve-PodeOAReference { $tmpProp += Resolve-PodeOAReference -DefinitionTag $DefinitionTag -ComponentSchema$comp } else { - throw $msgTable.unsupportedObjectExceptionMessage #'Unsupported object' + # Unsupported object + throw $msgTable.unsupportedObjectExceptionMessage } } } @@ -1472,10 +1478,12 @@ function Resolve-PodeOAReference { } elseif ($key -ieq 'oneof') { - throw $msgTable.validationOfOneOfSchemaNotSupportedExceptionMessage #'Validation of schema with oneof is not supported' + # Validation of schema with oneof is not supported + throw $msgTable.validationOfOneOfSchemaNotSupportedExceptionMessage } elseif ($key -ieq 'anyof') { - throw $msgTable.validationOfAnyOfSchemaNotSupportedExceptionMessage #'Validation of schema with anyof is not supported' + # Validation of schema with anyof is not supported + throw $msgTable.validationOfAnyOfSchemaNotSupportedExceptionMessage } } elseif ($ComponentSchema.properties[$key].type -eq 'object') { @@ -1557,7 +1565,8 @@ function New-PodeOAPropertyInternal { $param.type = $Params.type } else { - throw $msgTable.cannotCreatePropertyWithoutTypeExceptionMessage #'Cannot create the property no type is defined' + # Cannot create the property no type is defined + throw $msgTable.cannotCreatePropertyWithoutTypeExceptionMessage } } @@ -1639,7 +1648,8 @@ function New-PodeOAPropertyInternal { if ($Params.ExternalDocs) { $param.externalDocs = $Params.ExternalDocs } if ($Params.NoAdditionalProperties.IsPresent -and $Params.AdditionalProperties) { - throw $msgTable.paramsNoAdditionalPropertiesExclusiveExceptionMessage #'Params -NoAdditionalProperties and -AdditionalProperties are mutually exclusive' + # Params -NoAdditionalProperties and -AdditionalProperties are mutually exclusive + throw $msgTable.paramsNoAdditionalPropertiesExclusiveExceptionMessage } else { if ($Params.NoAdditionalProperties.IsPresent) { $param.additionalProperties = $false } @@ -1699,7 +1709,8 @@ function ConvertTo-PodeOAHeaderProperty { } } else { - throw $msgTable.headerMustHaveNameInEncodingContextExceptionMessage #'Header requires a name when used in an encoding context' + # Header requires a name when used in an encoding context + throw $msgTable.headerMustHaveNameInEncodingContextExceptionMessage } } @@ -1814,7 +1825,8 @@ function New-PodeOResponseInternal { $Description = Get-PodeStatusDescription -StatusCode $Params.StatusCode } else { - throw $msgTable.descriptionRequiredExceptionMessage #'A Description is required' + # A Description is required + throw $msgTable.descriptionRequiredExceptionMessage } } else { @@ -1984,7 +1996,8 @@ function Test-PodeOADefinitionInternal { } # Throw an error indicating non-compliance with OpenAPI standards - throw $msgTable.openApiDocumentNotCompliantExceptionMessage #'OpenAPI document compliance issues' + # OpenAPI document compliance issues + throw $msgTable.openApiDocumentNotCompliantExceptionMessage } } diff --git a/src/Private/Routes.ps1 b/src/Private/Routes.ps1 index 37501e82c..af7008fde 100644 --- a/src/Private/Routes.ps1 +++ b/src/Private/Routes.ps1 @@ -658,11 +658,13 @@ function ConvertTo-PodeMiddleware { # if middleware is hashtable, ensure the keys are valid (logic is a scriptblock) if ($mid -is [hashtable]) { if ($null -eq $mid.Logic) { - throw $msgTable.hashtableMiddlewareNoLogicExceptionMessage#'A Hashtable Middleware supplied has no Logic defined' + # A Hashtable Middleware supplied has no Logic defined + throw $msgTable.hashtableMiddlewareNoLogicExceptionMessage } if ($mid.Logic -isnot [scriptblock]) { - throw ($msgTable.invalidLogicTypeInHashtableMiddlewareExceptionMessage -f $mid.Logic.GetType().Name)#"A Hashtable Middleware supplied has an invalid Logic type. Expected ScriptBlock, but got: $($mid.Logic.GetType().Name)" + # A Hashtable Middleware supplied has an invalid Logic type. Expected ScriptBlock, but got: {0} + throw ($msgTable.invalidLogicTypeInHashtableMiddlewareExceptionMessage -f $mid.Logic.GetType().Name) } } } diff --git a/src/Private/Secrets.ps1 b/src/Private/Secrets.ps1 index 1f80e137f..7fa49851c 100644 --- a/src/Private/Secrets.ps1 +++ b/src/Private/Secrets.ps1 @@ -45,7 +45,8 @@ function Register-PodeSecretManagementVault { # check if we have an unlock password for local secret store if ($isSecretStore) { if ([string]::IsNullOrEmpty($VaultConfig.Unlock.Secret)) { - throw $msgTable.unlockSecretRequiredExceptionMessage#'An "-UnlockSecret" is required when using Microsoft.PowerShell.SecretStore' + # An 'UnlockSecret' is required when using Microsoft.PowerShell.SecretStore + throw $msgTable.unlockSecretRequiredExceptionMessage } } @@ -145,7 +146,8 @@ function Register-PodeSecretCustomVault { # unlock secret with no script? if ($VaultConfig.Unlock.Enabled -and (Test-PodeIsEmpty $UnlockScriptBlock)) { - throw $msgTable.unlockSecretButNoScriptBlockExceptionMessage #'Unlock secret supplied for custom Secret Vault type, but not Unlock ScriptBlock supplied' + # Unlock secret supplied for custom Secret Vault type, but not Unlock ScriptBlock supplied + throw $msgTable.unlockSecretButNoScriptBlockExceptionMessage } # all is good, so set the config diff --git a/src/Private/Security.ps1 b/src/Private/Security.ps1 index f5691f6bb..bd74f585d 100644 --- a/src/Private/Security.ps1 +++ b/src/Private/Security.ps1 @@ -850,7 +850,8 @@ function Find-PodeCertificateInCertStore { # fail if not windows if (!(Test-PodeIsWindows)) { - throw $msgTable.certificateThumbprintsNameSupportedOnWindowsExceptionMessage #'Certificate Thumbprints/Name are only supported on Windows' + # Certificate Thumbprints/Name are only supported on Windows + throw $msgTable.certificateThumbprintsNameSupportedOnWindowsExceptionMessage } # open the currentuser\my store diff --git a/src/Private/ServiceServer.ps1 b/src/Private/ServiceServer.ps1 index e1e66491e..d0058d83c 100644 --- a/src/Private/ServiceServer.ps1 +++ b/src/Private/ServiceServer.ps1 @@ -1,7 +1,8 @@ function Start-PodeServiceServer { # ensure we have service handlers if (Test-PodeIsEmpty (Get-PodeHandler -Type Service)) { - throw $msgTable.noServiceHandlersDefinedExceptionMessage #'No Service handlers have been defined' + # No Service handlers have been defined + throw $msgTable.noServiceHandlersDefinedExceptionMessage } # state we're running diff --git a/src/Private/Sessions.ps1 b/src/Private/Sessions.ps1 index 43074e223..496ed1820 100644 --- a/src/Private/Sessions.ps1 +++ b/src/Private/Sessions.ps1 @@ -40,7 +40,8 @@ function Get-PodeSessionFullId { function Set-PodeSession { if ($null -eq $WebEvent.Session) { - throw $msgTable.noSessionToSetOnResponseExceptionMessage #'there is no session available to set on the response' + # There is no session available to set on the response + throw $msgTable.noSessionToSetOnResponseExceptionMessage } # convert secret to strict mode @@ -137,7 +138,8 @@ function Revoke-PodeSession { function Set-PodeSessionDataHash { if ($null -eq $WebEvent.Session) { - throw $msgTable.noSessionToCalculateDataHashExceptionMessage #'No session available to calculate data hash' + # No session available to calculate data hash + throw $msgTable.noSessionToCalculateDataHashExceptionMessage } if (($null -eq $WebEvent.Session.Data) -or ($WebEvent.Session.Data.Count -eq 0)) { diff --git a/src/Private/SmtpServer.ps1 b/src/Private/SmtpServer.ps1 index e434504c1..43f7d702b 100644 --- a/src/Private/SmtpServer.ps1 +++ b/src/Private/SmtpServer.ps1 @@ -3,7 +3,8 @@ using namespace Pode function Start-PodeSmtpServer { # ensure we have smtp handlers if (Test-PodeIsEmpty (Get-PodeHandler -Type Smtp)) { - throw $msgTable.noSmtpHandlersDefinedExceptionMessage #'No SMTP handlers have been defined' + # No SMTP handlers have been defined + throw $msgTable.noSmtpHandlersDefinedExceptionMessage } # work out which endpoints to listen on diff --git a/src/Public/Access.ps1 b/src/Public/Access.ps1 index 4a949031b..2e942aa29 100644 --- a/src/Public/Access.ps1 +++ b/src/Public/Access.ps1 @@ -69,7 +69,8 @@ function New-PodeAccessScheme { # for custom access a validator is mandatory if ($Custom) { if ([string]::IsNullOrWhiteSpace($Path) -and (Test-PodeIsEmpty $ScriptBlock)) { - throw $msgTable.pathOrScriptBlockRequiredExceptionMessage #'A Path or ScriptBlock is required for sourcing the Custom access values' + # A Path or ScriptBlock is required for sourcing the Custom access values + throw $msgTable.pathOrScriptBlockRequiredExceptionMessage } } diff --git a/src/Public/Authentication.ps1 b/src/Public/Authentication.ps1 index 681809522..fdfa0f8af 100644 --- a/src/Public/Authentication.ps1 +++ b/src/Public/Authentication.ps1 @@ -159,7 +159,8 @@ function New-PodeAuthScheme { [Parameter(Mandatory = $true, ParameterSetName = 'Custom')] [ValidateScript({ if (Test-PodeIsEmpty $_) { - throw $msgTable.nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage #'A non-empty ScriptBlock is required for the Custom authentication scheme' + # A non-empty ScriptBlock is required for the Custom authentication scheme + throw $msgTable.nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage } return $true @@ -408,19 +409,23 @@ function New-PodeAuthScheme { 'oauth2' { if (($null -ne $InnerScheme) -and ($InnerScheme.Name -inotin @('basic', 'form'))) { - throw ($msgTable.oauth2InnerSchemeInvalidExceptionMessage -f $InnerScheme.Name) #"OAuth2 InnerScheme can only be one of either Basic or Form authentication, but got: $($InnerScheme.Name)" + # OAuth2 InnerScheme can only be one of either Basic or Form authentication, but got: {0} + throw ($msgTable.oauth2InnerSchemeInvalidExceptionMessage -f $InnerScheme.Name) } if (($null -eq $InnerScheme) -and [string]::IsNullOrWhiteSpace($AuthoriseUrl)) { - throw $msgTable.oauth2RequiresAuthorizeUrlExceptionMessage #'OAuth2 requires an Authorise URL to be supplied' + #OAuth2 requires an Authorise URL to be supplied + throw $msgTable.oauth2RequiresAuthorizeUrlExceptionMessage } if ($UsePKCE -and !(Test-PodeSessionsEnabled)) { - throw $msgTable.sessionsRequiredForOAuth2WithPKCEExceptionMessage #'Sessions are required to use OAuth2 with PKCE' + # Sessions are required to use OAuth2 with PKCE + throw $msgTable.sessionsRequiredForOAuth2WithPKCEExceptionMessage } if (!$UsePKCE -and [string]::IsNullOrEmpty($ClientSecret)) { - throw $msgTable.oauth2ClientSecretRequiredExceptionMessage #'OAuth2 requires a Client Secret when not using PKCE' + # OAuth2 requires a Client Secret when not using PKCE + throw $msgTable.oauth2ClientSecretRequiredExceptionMessage } return @{ Name = 'OAuth2' @@ -717,7 +722,8 @@ function Add-PodeAuth { [Parameter(Mandatory = $true)] [ValidateScript({ if (Test-PodeIsEmpty $_) { - throw $msgTable.nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage #'A non-empty ScriptBlock is required for the authentication method' + # A non-empty ScriptBlock is required for the authentication method + throw $msgTable.nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage } return $true @@ -750,17 +756,20 @@ function Add-PodeAuth { # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { - throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) # "Authentication method already defined: $($Name)" + # Authentication method already defined: {0} + throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) } # ensure the Scheme contains a scriptblock if (Test-PodeIsEmpty $Scheme.ScriptBlock) { - throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) # "The supplied '$($Scheme.Name)' Scheme for the '$($Name)' authentication validator requires a valid ScriptBlock" + # The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock + throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) } # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { - throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage # 'Sessions are required to use session persistent authentication' + # Sessions are required to use session persistent authentication + throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage } # check for scoped vars @@ -902,7 +911,8 @@ function Merge-PodeAuth { # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { - throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) # "Authentication method already defined: $($Name)" + # Authentication method already defined: { 0 } + throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) } # ensure all the auth methods exist @@ -937,7 +947,8 @@ function Merge-PodeAuth { # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { - throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage #'Sessions are required to use session persistent authentication' + # Sessions are required to use session persistent authentication + throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage } # check failure url from default @@ -963,7 +974,8 @@ function Merge-PodeAuth { # deal with using vars in scriptblock if (($Valid -ieq 'all') -and [string]::IsNullOrEmpty($MergeDefault)) { if ($null -eq $ScriptBlock) { - throw $msgTable.scriptBlockRequiredForMergingUsersExceptionMessage # 'A Scriptblock for merging multiple authenticated users into 1 object is required When Valid is All' + # A Scriptblock for merging multiple authenticated users into 1 object is required When Valid is All + throw $msgTable.scriptBlockRequiredForMergingUsersExceptionMessage } $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState @@ -1264,17 +1276,20 @@ function Add-PodeAuthWindowsAd { # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { - throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) # "Windows AD Authentication method already defined: $($Name)" + # Authentication method already defined: {0} + throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) } # ensure the Scheme contains a scriptblock if (Test-PodeIsEmpty $Scheme.ScriptBlock) { - throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) # "The supplied Scheme for the '$($Name)' Windows AD authentication validator requires a valid ScriptBlock" + # The supplied Scheme for the '$($Name)' Windows AD authentication validator requires a valid ScriptBlock + throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) } # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { - throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage #'Sessions are required to use session persistent authentication' + # Sessions are required to use session persistent authentication + throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage } # if AD module set, ensure we're on windows and the module is available, then import/export it @@ -1287,7 +1302,8 @@ function Add-PodeAuthWindowsAd { $Fqdn = Get-PodeAuthDomainName if ([string]::IsNullOrWhiteSpace($Fqdn)) { - throw $msgTable.noDomainServerNameForWindowsAdAuthExceptionMessage #'No domain server name has been supplied for Windows AD authentication' + # No domain server name has been supplied for Windows AD authentication + throw $msgTable.noDomainServerNameForWindowsAdAuthExceptionMessage } } @@ -1400,12 +1416,14 @@ function Add-PodeAuthSession { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { - throw $msgTable.sessionsNotConfiguredExceptionMessage #'Sessions have not been configured' + # Sessions have not been configured + throw $msgTable.sessionsNotConfiguredExceptionMessage } # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { - throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) # "Authentication method already defined: $($Name)" + # Authentication method already defined: { 0 } + throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) } # if we have a scriptblock, deal with using vars @@ -1685,12 +1703,14 @@ function Add-PodeAuthIIS { # ensure we're on Windows! if (!(Test-PodeIsWindows)) { - throw $msgTable.iisAuthSupportIsForWindowsOnlyExceptionMessage # 'IIS Authentication support is for Windows only' + # IIS Authentication support is for Windows only + throw $msgTable.iisAuthSupportIsForWindowsOnlyExceptionMessage } # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { - throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) # "IIS Authentication method already defined: $($Name)" + # Authentication method already defined: {0} + throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) } # if AD module set, ensure we're on windows and the module is available, then import/export it @@ -1848,17 +1868,20 @@ function Add-PodeAuthUserFile { # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { - throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) # "User File Authentication method already defined: $($Name)" + # Authentication method already defined: {0} + throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) } # ensure the Scheme contains a scriptblock if (Test-PodeIsEmpty $Scheme.ScriptBlock) { - throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) #"The supplied Scheme for the '$($Name)' User File authentication validator requires a valid ScriptBlock" + # The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock. + throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) } # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { - throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage #'Sessions are required to use session persistent authentication' + # Sessions are required to use session persistent authentication + throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage } # set the file path if not passed @@ -1871,7 +1894,8 @@ function Add-PodeAuthUserFile { # ensure the user file exists if (!(Test-PodePath -Path $FilePath -NoStatus -FailOnDirectory)) { - throw ($msgTable.userFileDoesNotExistExceptionMessage -f $FilePath) # "The user file does not exist: $($FilePath)" + # The user file does not exist: {0} + throw ($msgTable.userFileDoesNotExistExceptionMessage -f $FilePath) } # if we have a scriptblock, deal with using vars @@ -2006,22 +2030,26 @@ function Add-PodeAuthWindowsLocal { # ensure we're on Windows! if (!(Test-PodeIsWindows)) { - throw $msgTable.windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage #'Windows Local Authentication support is for Windows only' + # Windows Local Authentication support is for Windows only + throw $msgTable.windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage } # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { - throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) # "Windows Local Authentication method already defined: $($Name)" + # Authentication method already defined: {0} + throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) } # ensure the Scheme contains a scriptblock if (Test-PodeIsEmpty $Scheme.ScriptBlock) { - throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) # "The supplied Scheme for the '$($Name)' Windows Local authentication validator requires a valid ScriptBlock" + # The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock. + throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) } # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { - throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage #'Sessions are required to use session persistent authentication' + # Sessions are required to use session persistent authentication + throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage } # if we have a scriptblock, deal with using vars @@ -2097,7 +2125,8 @@ function ConvertTo-PodeJwt { # validate header if ([string]::IsNullOrWhiteSpace($Header.alg)) { - throw $msgTable.noAlgorithmInJwtHeaderExceptionMessage #'No algorithm supplied in JWT Header' + # No algorithm supplied in JWT Header + throw $msgTable.noAlgorithmInJwtHeaderExceptionMessage } # convert the header @@ -2161,13 +2190,15 @@ function ConvertFrom-PodeJwt { # check number of parts (should be 3) if ($parts.Length -ne 3) { - throw $msgTable.invalidJwtSuppliedExceptionMessage #'Invalid JWT supplied' + # Invalid JWT supplied + throw $msgTable.invalidJwtSuppliedExceptionMessage } # convert to header $header = ConvertFrom-PodeJwtBase64Value -Value $parts[0] if ([string]::IsNullOrWhiteSpace($header.alg)) { - throw $msgTable.invalidJwtHeaderAlgorithmSuppliedExceptionMessage # Invalid JWT header algorithm supplied' + # Invalid JWT header algorithm supplied + throw $msgTable.invalidJwtHeaderAlgorithmSuppliedExceptionMessage } # convert to payload @@ -2184,15 +2215,18 @@ function ConvertFrom-PodeJwt { $isNoneAlg = ($header.alg -ieq 'none') if ([string]::IsNullOrWhiteSpace($signature) -and !$isNoneAlg) { - throw ($msgTable.noJwtSignatureForAlgorithmExceptionMessage -f $header.alg) # "No JWT signature supplied for $($header.alg)" + # No JWT signature supplied for {0} + throw ($msgTable.noJwtSignatureForAlgorithmExceptionMessage -f $header.alg) } if (![string]::IsNullOrWhiteSpace($signature) -and $isNoneAlg) { - throw $msgTable.expectedNoJwtSignatureSuppliedExceptionMessage # 'Expected no JWT signature to be supplied' + # Expected no JWT signature to be supplied + throw $msgTable.expectedNoJwtSignatureSuppliedExceptionMessage } if ($isNoneAlg -and ($null -ne $Secret) -and ($Secret.Length -gt 0)) { - throw $msgTable.expectedNoJwtSignatureSuppliedExceptionMessage # 'Expected no JWT signature to be supplied' + # Expected no JWT signature to be supplied + throw $msgTable.expectedNoJwtSignatureSuppliedExceptionMessage } if ($isNoneAlg) { @@ -2208,7 +2242,8 @@ function ConvertFrom-PodeJwt { $sig = New-PodeJwtSignature -Algorithm $header.alg -Token $sig -SecretBytes $Secret if ($sig -ne $parts[2]) { - throw $msgTable.invalidJwtSignatureSuppliedExceptionMessage # 'Invalid JWT signature supplied' + # Invalid JWT signature supplied + throw $msgTable.invalidJwtSignatureSuppliedExceptionMessage } # it's valid return the payload! @@ -2247,14 +2282,16 @@ function Test-PodeJwt { # validate expiry if (![string]::IsNullOrWhiteSpace($Payload.exp)) { if ($now -gt $unixStart.AddSeconds($Payload.exp)) { - throw $msgTable.jwtExpiredExceptionMessage # 'The JWT has expired' + # The JWT has expired + throw $msgTable.jwtExpiredExceptionMessage } } # validate not-before if (![string]::IsNullOrWhiteSpace($Payload.nbf)) { if ($now -lt $unixStart.AddSeconds($Payload.nbf)) { - throw $msgTable.jwtNotYetValidExceptionMessage #'The JWT is not yet valid for use' + # The JWT is not yet valid for use + throw $msgTable.jwtNotYetValidExceptionMessage } } } @@ -2367,12 +2404,14 @@ function ConvertFrom-PodeOIDCDiscovery { # check it supports the code response_type if ($config.response_types_supported -inotcontains 'code') { - throw $msgTable.oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage # "The OAuth2 provider does not support the 'code' response_type" + # The OAuth2 provider does not support the 'code' response_type + throw $msgTable.oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage } # can we have an InnerScheme? if (($null -ne $InnerScheme) -and ($config.grant_types_supported -inotcontains 'password')) { - throw $msgTable.oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage # "The OAuth2 provider does not support the 'password' grant_type required by using an InnerScheme" + # The OAuth2 provider does not support the 'password' grant_type required by using an InnerScheme + throw $msgTable.oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage } # scopes diff --git a/src/Public/AutoImport.ps1 b/src/Public/AutoImport.ps1 index fb9c21b0e..ee8c965f5 100644 --- a/src/Public/AutoImport.ps1 +++ b/src/Public/AutoImport.ps1 @@ -46,7 +46,8 @@ function Export-PodeSnapin { # if non-windows or core, fail if ((Test-PodeIsPSCore) -or (Test-PodeIsUnix)) { - throw $msgTable.snapinsSupportedOnWindowsPowershellOnlyExceptionMessage # 'Snapins are only supported on Windows PowerShell' + # Snapins are only supported on Windows PowerShell + throw $msgTable.snapinsSupportedOnWindowsPowershellOnlyExceptionMessage } $PodeContext.Server.AutoImport.Snapins.ExportList += @($Name) diff --git a/src/Public/Core.ps1 b/src/Public/Core.ps1 index 0b121bd25..3c99f339e 100644 --- a/src/Public/Core.ps1 +++ b/src/Public/Core.ps1 @@ -642,7 +642,8 @@ function Show-PodeGui { # only valid for Windows PowerShell if ((Test-PodeIsPSCore) -and ($PSVersionTable.PSVersion.Major -eq 6)) { - throw 'Show-PodeGui is currently only available for Windows PowerShell, and PowerShell 7+ on Windows' + # Show-PodeGui is currently only available for Windows PowerShell and PowerShell 7+ on Windows + throw $msgTable.showPodeGuiOnlyAvailableOnWindowsExceptionMessage } # enable the gui and set general settings @@ -902,7 +903,8 @@ function Add-PodeEndpoint { # if RedirectTo is supplied, then a Name is mandatory if (![string]::IsNullOrWhiteSpace($RedirectTo) -and [string]::IsNullOrWhiteSpace($Name)) { - throw 'A Name is required for the endpoint if the RedirectTo parameter is supplied' + # A Name is required for the endpoint if the RedirectTo parameter is supplied + throw $msgTable.nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage } # get the type of endpoint @@ -953,22 +955,26 @@ function Add-PodeEndpoint { # protocol must be https for client certs, or hosted behind a proxy like iis if (($Protocol -ine 'https') -and !(Test-PodeIsHosted) -and $AllowClientCertificate) { - throw 'Client certificates are only supported on HTTPS endpoints' + # Client certificates are only supported on HTTPS endpoints + throw $msgTable.clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage } # explicit tls is only supported for smtp/tcp if (($type -inotin @('smtp', 'tcp')) -and ($TlsMode -ieq 'explicit')) { - throw 'The Explicit TLS mode is only supported on SMTPS and TCPS endpoints' + # The Explicit TLS mode is only supported on SMTPS and TCPS endpoints + throw $msgTable.explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage } # ack message is only for smtp/tcp if (($type -inotin @('smtp', 'tcp')) -and ![string]::IsNullOrEmpty($Acknowledge)) { - throw 'The Acknowledge message is only supported on SMTP and TCP endpoints' + # The Acknowledge message is only supported on SMTP and TCP endpoints + throw $msgTable.acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage } # crlf message end is only for tcp if (($type -ine 'tcp') -and $CRLFMessageEnd) { - throw 'The CRLF message end check is only supported on TCP endpoints' + # The CRLF message end check is only supported on TCP endpoints + throw $msgTable.crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage } # new endpoint object @@ -1041,7 +1047,8 @@ function Add-PodeEndpoint { # if the address is non-local, then check admin privileges if (!$Force -and !(Test-PodeIPAddressLocal -IP $obj.Address) -and !(Test-PodeIsAdminUser)) { - throw 'Must be running with administrator priviledges to listen on non-localhost addresses' + # Must be running with administrator privileges to listen on non-localhost addresses + throw $msgTable.mustBeRunningWithAdminPrivilegesExceptionMessage } # has this endpoint been added before? (for http/https we can just not add it again) @@ -1053,7 +1060,8 @@ function Add-PodeEndpoint { if (!(Test-PodeIsHosted) -and ($PSCmdlet.ParameterSetName -ilike 'cert*')) { # fail if protocol is not https if (@('https', 'wss', 'smtps', 'tcps') -inotcontains $Protocol) { - throw 'Certificate supplied for non-HTTPS/WSS endpoint' + # Certificate supplied for non-HTTPS/WSS endpoint + throw $msgTable.certificateSuppliedForNonHttpsWssEndpointExceptionMessage } switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { diff --git a/src/Public/Flash.ps1 b/src/Public/Flash.ps1 index ca005ea8c..4d704e74b 100644 --- a/src/Public/Flash.ps1 +++ b/src/Public/Flash.ps1 @@ -29,7 +29,8 @@ function Add-PodeFlashMessage { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { - throw 'Sessions are required to use Flash messages' + # Sessions are required to use Flash messages + throw $msgTable.sessionsRequiredForFlashMessagesExceptionMessage } # append the message against the key @@ -61,7 +62,8 @@ function Clear-PodeFlashMessages { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { - throw 'Sessions are required to use Flash messages' + # Sessions are required to use Flash messages + throw $msgTable.sessionsRequiredForFlashMessagesExceptionMessage } # clear all keys @@ -95,7 +97,8 @@ function Get-PodeFlashMessage { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { - throw 'Sessions are required to use Flash messages' + # Sessions are required to use Flash messages + throw $msgTable.sessionsRequiredForFlashMessagesExceptionMessage } # retrieve messages from session, then delete it @@ -130,7 +133,8 @@ function Get-PodeFlashMessageNames { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { - throw 'Sessions are required to use Flash messages' + # Sessions are required to use Flash messages + throw $msgTable.sessionsRequiredForFlashMessagesExceptionMessage } # return list of all current keys @@ -164,7 +168,8 @@ function Remove-PodeFlashMessage { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { - throw 'Sessions are required to use Flash messages' + # Sessions are required to use Flash messages + throw $msgTable.sessionsRequiredForFlashMessagesExceptionMessage } # remove key from flash messages @@ -197,7 +202,8 @@ function Test-PodeFlashMessage { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { - throw 'Sessions are required to use Flash messages' + # Sessions are required to use Flash messages + throw $msgTable.sessionsRequiredForFlashMessagesExceptionMessage } # return if a key exists as a flash message diff --git a/src/Public/Logging.ps1 b/src/Public/Logging.ps1 index 801002f7b..28b7ad9fb 100644 --- a/src/Public/Logging.ps1 +++ b/src/Public/Logging.ps1 @@ -132,7 +132,8 @@ function New-PodeLoggingMethod { [Parameter(Mandatory = $true, ParameterSetName = 'Custom')] [ValidateScript({ if (Test-PodeIsEmpty $_) { - throw 'A non-empty ScriptBlock is required for the Custom logging output method' + # A non-empty ScriptBlock is required for the Custom logging output method + throw $msgTable.nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage } return $true @@ -187,7 +188,8 @@ function New-PodeLoggingMethod { 'eventviewer' { # only windows if (!(Test-PodeIsWindows)) { - throw 'Event Viewer logging only supported on Windows' + # Event Viewer logging only supported on Windows + throw $msgTable.eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage } # create source @@ -260,12 +262,14 @@ function Enable-PodeRequestLogging { # error if it's already enabled if ($PodeContext.Server.Logging.Types.Contains($name)) { - throw 'Request Logging has already been enabled' + # Request Logging has already been enabled + throw $msgTable.requestLoggingAlreadyEnabledExceptionMessage } # ensure the Method contains a scriptblock if (Test-PodeIsEmpty $Method.ScriptBlock) { - throw 'The supplied output Method for Request Logging requires a valid ScriptBlock' + # The supplied output Method for Request Logging requires a valid ScriptBlock + throw $msgTable.outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage } # username property @@ -343,12 +347,14 @@ function Enable-PodeErrorLogging { # error if it's already enabled if ($PodeContext.Server.Logging.Types.Contains($name)) { - throw 'Error Logging has already been enabled' + # Error Logging has already been enabled + throw $msgTable.requestLoggingAlreadyEnabledExceptionMessage } # ensure the Method contains a scriptblock if (Test-PodeIsEmpty $Method.ScriptBlock) { - throw 'The supplied output Method for Error Logging requires a valid ScriptBlock' + # The supplied output Method for Error Logging requires a valid ScriptBlock + throw $msgTable.outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage } # all errors? @@ -420,7 +426,8 @@ function Add-PodeLogger { [Parameter(Mandatory = $true)] [ValidateScript({ if (Test-PodeIsEmpty $_) { - throw 'A non-empty ScriptBlock is required for the logging method' + # A non-empty ScriptBlock is required for the logging method + throw $msgTable.nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage } return $true diff --git a/src/Public/Middleware.ps1 b/src/Public/Middleware.ps1 index 6ee06f80f..aa496fe5d 100644 --- a/src/Public/Middleware.ps1 +++ b/src/Public/Middleware.ps1 @@ -142,7 +142,8 @@ function New-PodeCsrfToken { # fail if the csrf logic hasn't been initialised if (!(Test-PodeCsrfConfigured)) { - throw 'CSRF Middleware has not been initialised' + # CSRF Middleware has not been initialized + throw $msgTable.csrfMiddlewareNotInitializedExceptionMessage } # generate a new secret and salt @@ -171,7 +172,8 @@ function Get-PodeCsrfMiddleware { # fail if the csrf logic hasn't been initialised if (!(Test-PodeCsrfConfigured)) { - throw 'CSRF Middleware has not been initialised' + # CSRF Middleware has not been initialized + throw $msgTable.csrfMiddlewareNotInitializedExceptionMessage } # return scriptblock for the csrf route middleware to test tokens @@ -239,7 +241,8 @@ function Initialize-PodeCsrf { # if sessions haven't been setup and we're not using cookies, error if (!$UseCookies -and !(Test-PodeSessionsEnabled)) { - throw 'Sessions are required to use CSRF unless you want to use cookies' + # Sessions are required to use CSRF unless you want to use cookies + throw $msgTable.sessionsRequiredForCsrfExceptionMessage } # if we're using cookies, ensure a global secret exists @@ -476,7 +479,8 @@ function Add-PodeMiddleware { # ensure we have a script to run if (Test-PodeIsEmpty $InputObject.Logic) { - throw '[Middleware]: No logic supplied in ScriptBlock' + # [Middleware]: No logic supplied in ScriptBlock + throw $msgTable.middlewareNoLogicSuppliedExceptionMessage } # set name, and override route/args diff --git a/src/Public/OAComponents.ps1 b/src/Public/OAComponents.ps1 index 6a9cf4f62..736ba9cf1 100644 --- a/src/Public/OAComponents.ps1 +++ b/src/Public/OAComponents.ps1 @@ -356,6 +356,7 @@ You can use this tag to reference the specific API documentation, schema, or ver .EXAMPLE New-PodeOAIntProperty -Name 'userId' | ConvertTo-PodeOAParameter -In Query | Add-PodeOAComponentParameter -Name 'UserIdParam' #> + function Add-PodeOAComponentParameter { [CmdletBinding()] param( @@ -371,7 +372,7 @@ function Add-PodeOAComponentParameter { [string[]] $DefinitionTag ) - + $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag foreach ($tag in $DefinitionTag) { @@ -380,7 +381,8 @@ function Add-PodeOAComponentParameter { $Name = $Parameter.name } else { - throw 'The Parameter has no name. Please provide a name to this component using -Name property' + # The Parameter has no name. Please provide a name to this component using the `Name` parameter + throw $msgTable.parameterHasNoNameExceptionMessage } } $PodeContext.Server.OpenAPI.Definitions[$tag].components.parameters[$Name] = $Parameter @@ -741,7 +743,8 @@ function Add-PodeOAComponentPathItem { } foreach ($tag in $DefinitionTag) { if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $tag ) { - throw 'The feature reusable component pathItems is not available in OpenAPI v3.0.x' + # The 'pathItems' reusable component feature is not available in OpenAPI v3.0. + throw $msgTable.reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage } #add the default OpenApi responses if ( $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses) { diff --git a/src/Public/OAProperties.ps1 b/src/Public/OAProperties.ps1 index 06f65e502..31691d016 100644 --- a/src/Public/OAProperties.ps1 +++ b/src/Public/OAProperties.ps1 @@ -349,7 +349,8 @@ function New-PodeOAMultiTypeProperty { if ($type -contains 'object') { if ($NoProperties) { if ($Properties -or $MinProperties -or $MaxProperties) { - throw '-NoProperties is not compatible with -Properties, -MinProperties and -MaxProperties' + # The parameter 'NoProperties' is mutually exclusive with 'Properties', 'MinProperties' and 'MaxProperties' + throw $msgTable.noPropertiesMutuallyExclusiveExceptionMessage } $param.properties = @($null) } @@ -368,7 +369,8 @@ function New-PodeOAMultiTypeProperty { } } elseif ($DiscriminatorMapping) { - throw 'Parameter -DiscriminatorMapping requires the -DiscriminatorProperty parameters' + # The parameter 'DiscriminatorMapping' can only be used when 'DiscriminatorProperty' is present + throw $msgTable.discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage } } if ($type -contains 'boolean') { @@ -1645,7 +1647,8 @@ function New-PodeOAObjectProperty { $param = New-PodeOAPropertyInternal -type 'object' -Params $PSBoundParameters if ($NoProperties) { if ($Properties -or $MinProperties -or $MaxProperties) { - throw '-NoProperties is not compatible with -Properties, -MinProperties and -MaxProperties' + # The parameter `NoProperties` is mutually exclusive with `Properties`, `MinProperties` and `MaxProperties` + throw $msgTable.noPropertiesMutuallyExclusiveExceptionMessage } $param.properties = @($null) $PropertiesFromPipeline = $false @@ -1667,7 +1670,8 @@ function New-PodeOAObjectProperty { } } elseif ($DiscriminatorMapping) { - throw 'Parameter -DiscriminatorMapping requires the -DiscriminatorProperty parameters' + # The parameter 'DiscriminatorMapping' can only be used when 'DiscriminatorProperty' is present + throw $msgTable.discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage } $collectedInput = [System.Collections.Generic.List[hashtable]]::new() } @@ -1794,7 +1798,8 @@ function Merge-PodeOAProperty { } if ($DiscriminatorProperty) { if ($type.ToLower() -eq 'allof' ) { - throw 'Discriminator parameter is not compatible with allOf' + # The parameter 'Discriminator' is incompatible with `allOf` + throw $msgTable.discriminatorIncompatibleWithAllOfExceptionMessage } $param.discriminator = @{ 'propertyName' = $DiscriminatorProperty @@ -1804,14 +1809,16 @@ function Merge-PodeOAProperty { } } elseif ($DiscriminatorMapping) { - throw 'Parameter -DiscriminatorMapping requires the -DiscriminatorProperty parameters' + # The parameter 'DiscriminatorMapping' can only be used when 'DiscriminatorProperty' is present + throw $msgTable.discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage } } process { if ($ParamsList) { if ($ParamsList.type -ine 'object' -and !$ParamsList.object) { - throw "Only properties of type Object can be associated with $type" + # {0} can only be associated with an Object + throw ($msgTable.typeCanOnlyBeAssociatedWithObjectExceptionMessage -f $type) } $param.schemas += $ParamsList } diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index e64eb7e55..2d5ac7735 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -1566,7 +1566,8 @@ function Send-PodeSignal { ) # error if not configured if (!$PodeContext.Server.Signals.Enabled) { - throw 'WebSockets have not been configured to send signal messages' + # WebSockets have not been configured to send signal messages + throw $msgTable.websocketsNotConfiguredForSignalMessagesExceptionMessage } # do nothing if no value diff --git a/src/Public/Routes.ps1 b/src/Public/Routes.ps1 index 716d56b97..105a68274 100644 --- a/src/Public/Routes.ps1 +++ b/src/Public/Routes.ps1 @@ -284,7 +284,8 @@ function Add-PodeRoute { # split route on '?' for query $Path = Split-PodeRouteQuery -Path $Path if ([string]::IsNullOrWhiteSpace($Path)) { - throw 'No Path supplied for Route' + # No Path supplied for the Route + throw $msgTable.noPathSuppliedForRouteExceptionMessage } # ensure the route has appropriate slashes @@ -319,11 +320,13 @@ function Add-PodeRoute { # if an access name was supplied, setup access as middleware first to it's after auth middleware if (![string]::IsNullOrWhiteSpace($Access)) { if ([string]::IsNullOrWhiteSpace($Authentication)) { - throw 'Access requires Authentication to be supplied on Routes' + # Access requires Authentication to be supplied on Routes + throw $msgTable.accessRequiresAuthenticationOnRoutesExceptionMessage } if (!(Test-PodeAccessExists -Name $Access)) { - throw "Access method does not exist: $($Access)" + # Access method does not exist + throw ($msgTable.accessMethodDoesNotExistExceptionMessage -f $Access) } $options = @{ @@ -336,7 +339,8 @@ function Add-PodeRoute { # if an auth name was supplied, setup the auth as the first middleware if (![string]::IsNullOrWhiteSpace($Authentication)) { if (!(Test-PodeAuthExists -Name $Authentication)) { - throw "Authentication method does not exist: $($Authentication)" + # Authentication method does not exist + throw ($msgTable.authenticationMethodDoesNotExistExceptionMessage -f $Authentication) } $options = @{ @@ -791,11 +795,13 @@ function Add-PodeStaticRoute { # if an access name was supplied, setup access as middleware first to it's after auth middleware if (![string]::IsNullOrWhiteSpace($Access)) { if ([string]::IsNullOrWhiteSpace($Authentication)) { - throw 'Access requires Authentication to be supplied on Static Routes' + # Access requires Authentication to be supplied on Routes + throw $msgTable.accessRequiresAuthenticationOnRoutesExceptionMessage } if (!(Test-PodeAccessExists -Name $Access)) { - throw "Access method does not exist: $($Access)" + # Access method does not exist + throw ($msgTable.accessMethodDoesNotExistExceptionMessage -f $Access) } $options = @{ @@ -1168,7 +1174,8 @@ function Add-PodeRouteGroup { ) if (Test-PodeIsEmpty $Routes) { - throw 'No scriptblock for -Routes passed' + # The Route parameter needs a valid, not empty, scriptblock + throw $msgTable.routeParameterNeedsValidScriptblockExceptionMessage } if ($Path -eq '/') { @@ -1425,7 +1432,8 @@ function Add-PodeStaticRouteGroup { ) if (Test-PodeIsEmpty $Routes) { - throw 'No scriptblock for -Routes passed' + # The Route parameter needs a valid, not empty, scriptblock + throw $msgTable.routeParameterNeedsValidScriptblockExceptionMessage } if ($Path -eq '/') { @@ -1592,7 +1600,8 @@ function Add-PodeSignalRouteGroup { ) if (Test-PodeIsEmpty $Routes) { - throw 'No scriptblock for -Routes passed' + # The Route parameter needs a valid, not empty, scriptblock + throw $msgTable.routeParameterNeedsValidScriptblockExceptionMessage } if ($Path -eq '/') { @@ -2012,7 +2021,8 @@ function ConvertTo-PodeRoute { # if there are no commands, fail if (Test-PodeIsEmpty $Commands) { - throw 'No commands supplied to convert to Routes' + # No commands supplied to convert to Routes + throw $msgTable.noCommandsSuppliedToConvertToRoutesExceptionMessage } # trim end trailing slashes from the path @@ -2257,7 +2267,8 @@ function Add-PodePage { switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 'scriptblock' { if (Test-PodeIsEmpty $ScriptBlock) { - throw 'A non-empty ScriptBlock is required to created a Page Route' + # A non-empty ScriptBlock is required to create a Page Route + throw $msgTable.nonEmptyScriptBlockRequiredForPageRouteExceptionMessage } $arg = @($ScriptBlock, $Data) @@ -2651,7 +2662,8 @@ function Test-PodeRoute { # split route on '?' for query $Path = Split-PodeRouteQuery -Path $Path if ([string]::IsNullOrWhiteSpace($Path)) { - throw 'No Path supplied for testing Route' + # No Path supplied for the Route + throw $msgTable.noPathSuppliedForRouteExceptionMessage } # ensure the route has appropriate slashes @@ -2704,7 +2716,8 @@ function Test-PodeStaticRoute { # split route on '?' for query $Path = Split-PodeRouteQuery -Path $Path if ([string]::IsNullOrWhiteSpace($Path)) { - throw 'No Path supplied for testing Static Route' + # No Path supplied for the Route + throw $msgTable.noPathSuppliedForRouteExceptionMessage } # ensure the route has appropriate slashes diff --git a/src/Public/SSE.ps1 b/src/Public/SSE.ps1 index c3203e8a4..bb07456c1 100644 --- a/src/Public/SSE.ps1 +++ b/src/Public/SSE.ps1 @@ -78,7 +78,8 @@ function ConvertTo-PodeSseConnection { # check Accept header - unless forcing if (!$Force -and ((Get-PodeHeader -Name 'Accept') -ine 'text/event-stream')) { - throw 'SSE can only be configured on requests with an Accept header value of text/event-stream' + # SSE can only be configured on requests with an Accept header value of text/event-stream + throw $msgTable.sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage } # check for default scope, and set @@ -264,12 +265,14 @@ function Send-PodeSseEvent { # error if no name if ([string]::IsNullOrEmpty($Name)) { - throw 'An SSE connection Name is required, either from -Name or $WebEvent.Sse.Name' + # An SSE connection Name is required, either from -Name or $WebEvent.Sse.Name + throw $msgTable.sseConnectionNameRequiredExceptionMessage } # check if broadcast level if (!(Test-PodeSseBroadcastLevel -Name $Name -Group $Group -ClientId $ClientId)) { - throw "SSE failed to broadcast due to defined SSE broadcast level for $($Name): $(Get-PodeSseBroadcastLevel -Name $Name)" + # SSE failed to broadcast due to defined SSE broadcast level + throw ($msgTable.sseFailedToBroadcastExceptionMessage -f $Name, (Get-PodeSseBroadcastLevel -Name $Name)) } # send event diff --git a/src/Public/Sessions.ps1 b/src/Public/Sessions.ps1 index 55b3991e3..93f0971d0 100644 --- a/src/Public/Sessions.ps1 +++ b/src/Public/Sessions.ps1 @@ -108,7 +108,8 @@ function Enable-PodeSessionMiddleware { # check that session logic hasn't already been initialised if (Test-PodeSessionsEnabled) { - throw 'Session Middleware has already been intialised' + # Session Middleware has already been initialized + throw $msgTable.sessionMiddlewareAlreadyInitializedExceptionMessage } # ensure the override store has the required methods @@ -116,7 +117,8 @@ function Enable-PodeSessionMiddleware { $members = @($Storage | Get-Member | Select-Object -ExpandProperty Name) @('delete', 'get', 'set') | ForEach-Object { if ($members -inotcontains $_) { - throw "Custom session storage does not implement the required '$($_)()' method" + # The custom session storage does not implement the required '{0}()' method + throw ($msgTable.customSessionStorageMethodNotImplementedExceptionMessage -f $_) } } } @@ -124,7 +126,8 @@ function Enable-PodeSessionMiddleware { # verify the secret, set to guid if not supplied, or error if none and we have a storage if ([string]::IsNullOrEmpty($Secret)) { if (!(Test-PodeIsEmpty $Storage)) { - throw 'A Secret is required when using custom session storage' + # A Secret is required when using custom session storage + throw $msgTable.secretRequiredForCustomSessionStorageExceptionMessage } $Secret = Get-PodeServerDefaultSecret @@ -178,7 +181,8 @@ function Remove-PodeSession { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { - throw 'Sessions have not been configured' + # The sessions have not been configured + throw $msgTable.sessionsNotConfiguredExceptionMessage } # do nothing if session is null @@ -212,12 +216,14 @@ function Save-PodeSession { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { - throw 'Sessions have not been configured' + # The sessions have not been configured + throw $msgTable.sessionsNotConfiguredExceptionMessage } # error if session is null if ($null -eq $WebEvent.Session) { - throw 'There is no session available to save' + # There is no session available to save + throw $msgTable.noSessionAvailableToSaveExceptionMessage } # if auth is in use, then assign to session store @@ -306,12 +312,14 @@ function Reset-PodeSessionExpiry { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { - throw 'Sessions have not been configured' + # The sessions have not been configured + throw $msgTable.sessionsNotConfiguredExceptionMessage } # error if session is null if ($null -eq $WebEvent.Session) { - throw 'There is no session available to save' + # There is no session available to save + throw $msgTable.noSessionAvailableToSaveExceptionMessage } # temporarily set this session to auto-extend @@ -354,7 +362,8 @@ function Get-PodeSessionExpiry { # error if session is null if ($null -eq $WebEvent.Session) { - throw 'There is no session available to save' + # There is no session available to save + throw $msgTable.noSessionAvailableToSaveExceptionMessage } # default min date diff --git a/src/Public/State.ps1 b/src/Public/State.ps1 index 34d8519bb..944ce3161 100644 --- a/src/Public/State.ps1 +++ b/src/Public/State.ps1 @@ -38,7 +38,8 @@ function Set-PodeState { ) if ($null -eq $PodeContext.Server.State) { - throw 'Pode has not been initialised' + # Pode has not been initialized + throw $msgTable.podeNotInitializedExceptionMessage } if ($null -eq $Scope) { @@ -81,7 +82,8 @@ function Get-PodeState { ) if ($null -eq $PodeContext.Server.State) { - throw 'Pode has not been initialised' + # Pode has not been initialized + throw $msgTable.podeNotInitializedExceptionMessage } if ($WithScope) { @@ -124,7 +126,8 @@ function Get-PodeStateNames { ) if ($null -eq $PodeContext.Server.State) { - throw 'Pode has not been initialised' + # Pode has not been initialized + throw $msgTable.podeNotInitializedExceptionMessage } if ($null -eq $Scope) { @@ -176,7 +179,8 @@ function Remove-PodeState { ) if ($null -eq $PodeContext.Server.State) { - throw 'Pode has not been initialised' + # Pode has not been initialized + throw $msgTable.podeNotInitializedExceptionMessage } $value = $PodeContext.Server.State[$Name].Value @@ -247,7 +251,8 @@ function Save-PodeState { # error if attempting to use outside of the pode server if ($null -eq $PodeContext.Server.State) { - throw 'Pode has not been initialised' + # Pode has not been initialized + throw $msgTable.podeNotInitializedExceptionMessage } # get the full path to save the state @@ -341,7 +346,8 @@ function Restore-PodeState { # error if attempting to use outside of the pode server if ($null -eq $PodeContext.Server.State) { - throw 'Pode has not been initialised' + # Pode has not been initialized + throw $msgTable.podeNotInitializedExceptionMessage } # get the full path to the state @@ -415,7 +421,8 @@ function Test-PodeState { ) if ($null -eq $PodeContext.Server.State) { - throw 'Pode has not been initialised' + # Pode has not been initialized + throw $msgTable.podeNotInitializedExceptionMessage } return $PodeContext.Server.State.ContainsKey($Name) diff --git a/src/Public/Tasks.ps1 b/src/Public/Tasks.ps1 index d4f47573c..e430b1b0b 100644 --- a/src/Public/Tasks.ps1 +++ b/src/Public/Tasks.ps1 @@ -425,5 +425,6 @@ function Wait-PodeTask { return (Wait-PodeTaskInternal -Task $Task -Timeout $Timeout) } - throw 'Task type is invalid, expected either [System.Threading.Tasks.Task] or [hashtable]' + # Task type is invalid, expected either [System.Threading.Tasks.Task] or [hashtable] + throw $msgTable.invalidTaskTypeExceptionMessage } \ No newline at end of file diff --git a/src/Public/Threading.ps1 b/src/Public/Threading.ps1 index a8249d15e..972ac4f42 100644 --- a/src/Public/Threading.ps1 +++ b/src/Public/Threading.ps1 @@ -246,12 +246,14 @@ function Enter-PodeLockable { # check if value type and throw if ($Object -is [valuetype]) { - throw 'Cannot lock value types' + # Cannot lock a [ValueTypes] + throw $msgTable.cannotLockValueTypeExceptionMessage } # check if null and throw if ($null -eq $Object) { - throw 'Cannot lock a null object' + # Cannot lock an object that is null + throw $msgTable.cannotLockNullObjectExceptionMessage } # check if the global lockable is locked @@ -263,7 +265,8 @@ function Enter-PodeLockable { $locked = $false [System.Threading.Monitor]::TryEnter($Object.SyncRoot, $Timeout, [ref]$locked) if (!$locked) { - throw 'Failed to acquire lock on object' + # Failed to acquire a lock on the object + throw $msgTable.failedToAcquireLockExceptionMessage } } @@ -310,12 +313,14 @@ function Exit-PodeLockable { # check if value type and throw if ($Object -is [valuetype]) { - throw 'Cannot unlock value types' + # Cannot unlock a [ValueTypes] + throw $msgTable.cannotUnlockValueTypeExceptionMessage } # check if null and throw if ($null -eq $Object) { - throw 'Cannot unlock a null object' + # Cannot unlock an object that is null + throw $msgTable.cannotUnlockNullObjectExceptionMessage } if ([System.Threading.Monitor]::IsEntered($Object.SyncRoot)) { diff --git a/src/Public/Utilities.ps1 b/src/Public/Utilities.ps1 index d73fa132f..2d02ab16a 100644 --- a/src/Public/Utilities.ps1 +++ b/src/Public/Utilities.ps1 @@ -384,7 +384,8 @@ function Import-PodeSnapin { # if non-windows or core, fail if ((Test-PodeIsPSCore) -or (Test-PodeIsUnix)) { - throw 'Snapins are only supported on Windows PowerShell' + # Snapins are only supported on Windows PowerShell + throw $msgTable.snapinsSupportedOnWindowsPowershellOnlyExceptionMessage } # import the snap-in @@ -1056,7 +1057,8 @@ function New-PodeCron { # cant have None and Interval if (($Every -ieq 'none') -and ($Interval -gt 0)) { - throw 'Cannot supply an interval when -Every is set to None' + # Cannot supply an interval when the parameter `Every` is set to None + throw $msgTable.cannotSupplyIntervalWhenEveryIsNoneExceptionMessage } # base cron @@ -1156,7 +1158,8 @@ function New-PodeCron { $cron.Month = '1,4,7,10' if ($Interval -gt 0) { - throw 'Cannot supply interval value for every quarter' + # Cannot supply interval value for every quarter + throw $msgTable.cannotSupplyIntervalForQuarterExceptionMessage } } @@ -1167,7 +1170,8 @@ function New-PodeCron { $cron.Month = '1' if ($Interval -gt 0) { - throw 'Cannot supply interval value for every year' + # Cannot supply interval value for every year + throw $msgTable.cannotSupplyIntervalForYearExceptionMessage } } } diff --git a/tests/unit/Helpers.Tests.ps1 b/tests/unit/Helpers.Tests.ps1 index 912cb97bb..23378c533 100644 --- a/tests/unit/Helpers.Tests.ps1 +++ b/tests/unit/Helpers.Tests.ps1 @@ -1704,15 +1704,15 @@ Describe 'New-PodeCron' { } It 'Throws an error when using Interval without Every' { - { New-PodeCron -Interval 3 } | Should -Throw -ExpectedMessage '*Cannot supply an interval*' + { New-PodeCron -Interval 3 } | Should -Throw -ExpectedMessage $msgTable.cannotSupplyIntervalWhenEveryIsNoneExceptionMessage #'*Cannot supply an interval*' } It 'Throws an error when using Interval for Every Quarter' { - { New-PodeCron -Every Quarter -Interval 3 } | Should -Throw -ExpectedMessage 'Cannot supply interval value for every quarter' + { New-PodeCron -Every Quarter -Interval 3 } | Should -Throw -ExpectedMessage $msgTable.cannotSupplyIntervalForQuarterExceptionMessage #Cannot supply interval value for every quarter. } It 'Throws an error when using Interval for Every Year' { - { New-PodeCron -Every Year -Interval 3 } | Should -Throw -ExpectedMessage 'Cannot supply interval value for every year' + { New-PodeCron -Every Year -Interval 3 } | Should -Throw -ExpectedMessage $msgTable.cannotSupplyIntervalForYearExceptionMessage #'Cannot supply interval value for every year' } } diff --git a/tests/unit/Localization.Tests.ps1 b/tests/unit/Localization.Tests.ps1 index 32a85f70d..8ab0b9baf 100644 --- a/tests/unit/Localization.Tests.ps1 +++ b/tests/unit/Localization.Tests.ps1 @@ -17,13 +17,13 @@ Describe 'Localization Files Key Check' { # Discover all language directories $languageDirs = Get-ChildItem -Path $localizationDir -Directory | Where-Object { $_.Name -ne 'en' } - Describe "Language [<_.Name>]" -ForEach ($languageDirs) { + Describe 'Language [<_.Name>]' -ForEach ($languageDirs) { it 'Language resource file exist' { Test-Path -Path "$($_.FullName)/Pode.psd1" | Should -BeTrue } $podeFileContent = Get-Content -Path "$($_.FullName)/Pode.psd1" -Raw $global:content = Invoke-Expression $podeFileContent - it 'Total number of keys equal to the [en]'{ + it 'Total number of keys equal to the [en]' { $global:content.Keys.Count | Should -be $global:localizationKeys.Count } It -ForEach ($global:localizationKeys) -Name 'Resource File contain <_>' { diff --git a/tests/unit/OpenApi.Tests.ps1 b/tests/unit/OpenApi.Tests.ps1 index b39f2008a..3ef7b27ed 100644 --- a/tests/unit/OpenApi.Tests.ps1 +++ b/tests/unit/OpenApi.Tests.ps1 @@ -2086,7 +2086,7 @@ Describe 'OpenApi' { { Merge-PodeOAProperty -Type AllOf -DiscriminatorProperty 'name' -ObjectDefinitions @('Pet', (New-PodeOAObjectProperty -Properties @((New-PodeOAIntProperty -Name 'id'), (New-PodeOAStringProperty -Name 'name'))) - ) } | Should -Throw -ExpectedMessage 'Discriminator parameter is not compatible with allOf' + ) } | Should -Throw -ExpectedMessage $msgTable.discriminatorIncompatibleWithAllOfExceptionMessage #'Discriminator parameter is not compatible with allOf' } #Should -Throw -ExpectedMessage 'Discriminator parameter is not compatible with allOf' @@ -2277,7 +2277,7 @@ Describe 'OpenApi' { it 'throw error' { { Add-PodeOAComponentParameter -Parameter ( New-PodeOAIntProperty -Name 'petId' -Format Int64 -Description 'ID of the pet' | New-PodeOAObjectProperty ) } | - Should -Throw -ExpectedMessage 'The Parameter has no name. Please provide a name to this component using -Name property' + Should -Throw -ExpectedMessage $msgTable.parameterHasNoNameExceptionMessage # The Parameter has no name. Please give this component a name using the 'Name' parameter. } } Context 'ConvertTo-PodeOAParameter' { diff --git a/tests/unit/Routes.Tests.ps1 b/tests/unit/Routes.Tests.ps1 index 591b64342..ab74a7624 100644 --- a/tests/unit/Routes.Tests.ps1 +++ b/tests/unit/Routes.Tests.ps1 @@ -585,7 +585,7 @@ Describe 'ConvertTo-PodeRoute' { } It 'Throws error for no commands' { - { ConvertTo-PodeRoute } | Should -Throw -ExpectedMessage 'No commands supplied to convert to Routes' + { ConvertTo-PodeRoute } | Should -Throw -ExpectedMessage $msgTable.noCommandsSuppliedToConvertToRoutesExceptionMessage # No commands supplied to convert to Routes. } It 'Calls Add-PodeRoute twice for commands' { diff --git a/tests/unit/Security.Tests.ps1 b/tests/unit/Security.Tests.ps1 index 778c20e0f..4fc896dda 100644 --- a/tests/unit/Security.Tests.ps1 +++ b/tests/unit/Security.Tests.ps1 @@ -581,7 +581,7 @@ Describe 'New-PodeCsrfToken' { } } - { New-PodeCsrfToken } | Should -Throw -ExpectedMessage '*not been initialised*' + { New-PodeCsrfToken } | Should -Throw -ExpectedMessage $msgTable.csrfMiddlewareNotInitializedExceptionMessage #CSRF Middleware has not been initialized. } diff --git a/tests/unit/Sessions.Tests.ps1 b/tests/unit/Sessions.Tests.ps1 index 6a6a81c01..31dddb372 100644 --- a/tests/unit/Sessions.Tests.ps1 +++ b/tests/unit/Sessions.Tests.ps1 @@ -259,7 +259,7 @@ Describe 'Set-PodeSession' { Describe 'Remove-PodeSession' { It 'Throws an error if sessions are not configured' { Mock Test-PodeSessionsEnabled { return $false } - { Remove-PodeSession } | Should -Throw 'Sessions have not been configured' + { Remove-PodeSession } | Should -Throw $msgTable.sessionsNotConfiguredExceptionMessage # Sessions have not been configured. } It 'Does nothing if there is no session' { @@ -286,13 +286,13 @@ Describe 'Remove-PodeSession' { Describe 'Save-PodeSession' { It 'Throws an error if sessions are not configured' { Mock Test-PodeSessionsEnabled { return $false } - { Save-PodeSession } | Should -Throw 'Sessions have not been configured' + { Save-PodeSession } | Should -Throw $msgTable.sessionsNotConfiguredExceptionMessage # Sessions have not been configured. } It 'Throws error if there is no session' { Mock Test-PodeSessionsEnabled { return $true } $WebEvent = @{} - { Save-PodeSession } | Should -Throw -ExpectedMessage 'There is no session available to save' + { Save-PodeSession } | Should -Throw -ExpectedMessage $msgTable.noSessionAvailableToSaveExceptionMessage # There is no session available to save. } It 'Call saves the session' { diff --git a/tests/unit/State.Tests.ps1 b/tests/unit/State.Tests.ps1 index ee9143505..700b74d19 100644 --- a/tests/unit/State.Tests.ps1 +++ b/tests/unit/State.Tests.ps1 @@ -13,7 +13,7 @@ BeforeAll { Describe 'Set-PodeState' { It 'Throws error when not initialised' { $PodeContext.Server = @{ 'State' = $null } - { Set-PodeState -Name 'test' } | Should -Throw -ExpectedMessage 'Pode has not been initialised' + { Set-PodeState -Name 'test' } | Should -Throw -ExpectedMessage $msgTable.podeNotInitializedExceptionMessage # Pode has not been initialized. } It 'Sets and returns an object' { @@ -29,7 +29,7 @@ Describe 'Set-PodeState' { Describe 'Get-PodeState' { It 'Throws error when not initialised' { $PodeContext.Server = @{ 'State' = $null } - { Get-PodeState -Name 'test' } | Should -Throw -ExpectedMessage 'Pode has not been initialised' + { Get-PodeState -Name 'test' } | Should -Throw -ExpectedMessage $msgTable.podeNotInitializedExceptionMessage # Pode has not been initialized. } It 'Gets an object from the state' { @@ -42,7 +42,7 @@ Describe 'Get-PodeState' { Describe 'Remove-PodeState' { It 'Throws error when not initialised' { $PodeContext.Server = @{ 'State' = $null } - { Remove-PodeState -Name 'test' } | Should -Throw -ExpectedMessage 'Pode has not been initialised' + { Remove-PodeState -Name 'test' } | Should -Throw -ExpectedMessage $msgTable.podeNotInitializedExceptionMessage # Pode has not been initialized. } It 'Removes an object from the state' { @@ -56,7 +56,7 @@ Describe 'Remove-PodeState' { Describe 'Save-PodeState' { It 'Throws error when not initialised' { $PodeContext.Server = @{ 'State' = $null } - { Save-PodeState -Path 'some/path' } | Should -Throw -ExpectedMessage 'Pode has not been initialised' + { Save-PodeState -Path 'some/path' } | Should -Throw -ExpectedMessage $msgTable.podeNotInitializedExceptionMessage # Pode has not been initialized. } It 'Saves the state to file' { @@ -96,7 +96,7 @@ Describe 'Save-PodeState' { Describe 'Restore-PodeState' { It 'Throws error when not initialised' { $PodeContext.Server = @{ 'State' = $null } - { Restore-PodeState -Path 'some/path' } | Should -Throw -ExpectedMessage 'Pode has not been initialised' + { Restore-PodeState -Path 'some/path' } | Should -Throw -ExpectedMessage $msgTable.podeNotInitializedExceptionMessage # Pode has not been initialized. } It 'Restores the state from file' { @@ -113,7 +113,7 @@ Describe 'Restore-PodeState' { Describe 'Test-PodeState' { It 'Throws error when not initialised' { $PodeContext.Server = @{ 'State' = $null } - { Test-PodeState -Name 'test' } | Should -Throw -ExpectedMessage 'Pode has not been initialised' + { Test-PodeState -Name 'test' } | Should -Throw -ExpectedMessage $msgTable.podeNotInitializedExceptionMessage # Pode has not been initialized. } It 'Returns true for an object being in the state' { From 417df7b8c89e8e6e6ffddb972910d04949d05d18 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sat, 1 Jun 2024 21:27:11 -0700 Subject: [PATCH 021/177] change variable name to PodeLocal Add PodeLocal to runspaces --- examples/PetStore/Petstore-openApi.ps1 | 2 + .../tools/ChocolateyInstall_template.ps1 | 2 +- src/Locales/ar/Pode.psd1 | 18 +++- src/Locales/de/Pode.psd1 | 18 +++- src/Locales/en/Pode.psd1 | 16 +++- src/Locales/es/Pode.psd1 | 18 +++- src/Locales/fr/Pode.psd1 | 18 +++- src/Locales/it/Pode.psd1 | 18 +++- src/Locales/ja/Pode.psd1 | 17 +++- src/Locales/kr/Pode.psd1 | 18 +++- src/Locales/pl/Pode.psd1 | 18 +++- src/Locales/pt/Pode.psd1 | 18 +++- src/Locales/zn/Pode.psd1 | 18 +++- src/Pode.psm1 | 11 +-- src/Private/Authentication.ps1 | 4 +- src/Private/AutoImport.ps1 | 5 +- src/Private/Context.ps1 | 5 +- src/Private/CronParser.ps1 | 20 ++--- src/Private/Cryptography.ps1 | 16 ++-- src/Private/Endpoints.ps1 | 4 +- src/Private/Gui.ps1 | 2 +- src/Private/Helpers.ps1 | 26 +++--- src/Private/Middleware.ps1 | 4 +- src/Private/OpenApi.ps1 | 34 +++---- src/Private/Routes.ps1 | 10 +-- src/Private/ScopedVariables.ps1 | 4 +- src/Private/Secrets.ps1 | 12 +-- src/Private/Security.ps1 | 20 ++--- src/Private/Server.ps1 | 2 +- src/Private/ServiceServer.ps1 | 2 +- src/Private/Sessions.ps1 | 4 +- src/Private/Setup.ps1 | 2 +- src/Private/SmtpServer.ps1 | 2 +- src/Private/Tasks.ps1 | 2 +- src/Private/Verbs.ps1 | 4 +- src/Public/Access.ps1 | 12 +-- src/Public/Authentication.ps1 | 88 +++++++++---------- src/Public/AutoImport.ps1 | 2 +- src/Public/Core.ps1 | 16 ++-- src/Public/Events.ps1 | 4 +- src/Public/Flash.ps1 | 12 +-- src/Public/Logging.ps1 | 14 +-- src/Public/Middleware.ps1 | 8 +- src/Public/OAComponents.ps1 | 4 +- src/Public/OAProperties.ps1 | 14 +-- src/Public/OpenApi.ps1 | 6 +- src/Public/Responses.ps1 | 2 +- src/Public/Routes.ps1 | 26 +++--- src/Public/SSE.ps1 | 6 +- src/Public/Secrets.ps1 | 28 +++--- src/Public/Security.ps1 | 12 ++- src/Public/Sessions.ps1 | 18 ++-- src/Public/State.ps1 | 14 +-- src/Public/Tasks.ps1 | 2 +- src/Public/Threading.ps1 | 10 +-- src/Public/Utilities.ps1 | 8 +- src/Public/WebSockets.ps1 | 13 ++- tests/integration/Authentication.Tests.ps1 | 2 +- tests/unit/Authentication.Tests.ps1 | 6 +- tests/unit/Context.Tests.ps1 | 2 +- tests/unit/Cookies.Tests.ps1 | 2 +- tests/unit/CronParser.Tests.ps1 | 2 +- tests/unit/Cryptography.Tests.ps1 | 2 +- tests/unit/Endware.Tests.ps1 | 2 +- tests/unit/Flash.Tests.ps1 | 2 +- tests/unit/Handlers.Tests.ps1 | 2 +- tests/unit/Headers.Tests.ps1 | 2 +- tests/unit/Helpers.Tests.ps1 | 10 +-- tests/unit/Logging.Tests.ps1 | 2 +- tests/unit/Mappers.Tests.ps1 | 2 +- tests/unit/Metrics.Tests.ps1 | 2 +- tests/unit/Middleware.Tests.ps1 | 2 +- tests/unit/NameGenerator.Tests.ps1 | 2 +- tests/unit/OpenApi.Tests.ps1 | 6 +- tests/unit/PrivateOpenApi.Tests.ps1 | 2 +- tests/unit/Responses.Tests.ps1 | 2 +- tests/unit/Routes.Tests.ps1 | 6 +- tests/unit/Schedules.Tests.ps1 | 2 +- tests/unit/Security.Tests.ps1 | 4 +- tests/unit/Server.Tests.ps1 | 2 +- tests/unit/Serverless.Tests.ps1 | 2 +- tests/unit/Sessions.Tests.ps1 | 8 +- tests/unit/State.Tests.ps1 | 14 +-- tests/unit/Timers.Tests.ps1 | 2 +- 84 files changed, 493 insertions(+), 314 deletions(-) diff --git a/examples/PetStore/Petstore-openApi.ps1 b/examples/PetStore/Petstore-openApi.ps1 index dafd4dfd3..d8ff6dd2c 100644 --- a/examples/PetStore/Petstore-openApi.ps1 +++ b/examples/PetStore/Petstore-openApi.ps1 @@ -4,12 +4,14 @@ param ( ) $petStorePath = Split-Path -Parent -Path $MyInvocation.MyCommand.Path $podePath = Split-Path -Parent -Path (Split-Path -Parent -Path $petStorePath) +try{ if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop } else { Import-Module -Name 'Pode' } +}catch {throw } function Write-ObjectContent { param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] diff --git a/packers/choco/tools/ChocolateyInstall_template.ps1 b/packers/choco/tools/ChocolateyInstall_template.ps1 index d3d6dc08e..e2553172c 100644 --- a/packers/choco/tools/ChocolateyInstall_template.ps1 +++ b/packers/choco/tools/ChocolateyInstall_template.ps1 @@ -24,7 +24,7 @@ function Install-PodeModule($path, $version) { Push-Location (Join-Path $toolsDir 'src') # which folders do we need? - $folders = @('Private', 'Public', 'Misc', 'Libs', 'licenses') + $folders = @('Private', 'Public', 'Misc', 'Libs', 'licenses','Locales') $folders | ForEach-Object { New-Item -ItemType Directory -Path (Join-Path $path $_) -Force | Out-Null Copy-Item -Path "./$($_)/*" -Destination (Join-Path $path $_) -Force -Recurse | Out-Null diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 93b0e07c5..9265d9588 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -2,7 +2,7 @@ ConvertFrom-StringData -StringData @' adModuleWindowsOnlyExceptionMessage = وحدة Active Directory متاحة فقط على نظام Windows. adModuleNotInstalledExceptionMessage = وحدة Active Directory غير مثبتة. secretManagementModuleNotInstalledExceptionMessage = وحدة Microsoft.PowerShell.SecretManagement غير مثبتة. -secretVaultAlreadyRegisteredExceptionMessage = تم تسجيل خزنة سرية باسم '{0}' بالفعل أثناء استيراد الخزن السرية تلقائيًا. +secretVaultAlreadyRegisteredAutoImportExceptionMessage = تم تسجيل خزنة سرية باسم '{0}' بالفعل أثناء استيراد الخزن السرية تلقائيًا. failedToOpenRunspacePoolExceptionMessage = فشل في فتح RunspacePool: {0} cronExpressionInvalidExceptionMessage = يجب أن تتكون تعبير Cron من 5 أجزاء فقط: {0} invalidAliasFoundExceptionMessage = تم العثور على اسم مستعار غير صالح {0}: {1} @@ -164,4 +164,18 @@ noSessionAvailableToSaveExceptionMessage = لا توجد جلسة متاحة ل cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = لا يمكن توفير فترة زمنية عندما يكون المعامل 'Every' مضبوطًا على None. cannotSupplyIntervalForQuarterExceptionMessage = لا يمكن توفير قيمة الفاصل الزمني لكل ربع. cannotSupplyIntervalForYearExceptionMessage = لا يمكن توفير قيمة الفاصل الزمني لكل سنة. -'@ \ No newline at end of file +secretVaultAlreadyRegisteredExceptionMessage = تم تسجيل مخزن الأسرار بالاسم '{0}' بالفعل{1}. +secretVaultUnlockExpiryDateInPastExceptionMessage = تاريخ انتهاء صلاحية فتح مخزن الأسرار في الماضي (UTC): {0} +secretAlreadyMountedExceptionMessage = تم تثبيت سر بالاسم '{0}' بالفعل. +noSecretVaultRegisteredExceptionMessage = لم يتم تسجيل مخزن أسرار بالاسم '{0}'. +noAdditionalPropertiesMutuallyExclusiveExceptionMessage = المعاملات 'NoAdditionalProperties' و 'AdditionalProperties' متعارضة. +credentialsPassedWildcardForHeadersLiteralExceptionMessage = عند تمرير بيانات الاعتماد، سيتم اعتبار العلامة * للعنوان كـ سلسلة نصية حرفية وليس كعلامة. +wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = العلامة * للعنوان غير متوافقة مع مفتاح AutoHeaders. +wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = العلامة * للطرق غير متوافقة مع مفتاح AutoMethods. +invalidAccessControlMaxAgeDurationExceptionMessage = مدة Access-Control-Max-Age غير صالحة المقدمة: {0}. يجب أن تكون أكبر من 0. +noNameForWebSocketDisconnectExceptionMessage = لا يوجد اسم لفصل WebSocket من المزود. +noNameForWebSocketRemoveExceptionMessage = لا يوجد اسم لإزالة WebSocket من المزود. +noNameForWebSocketSendMessageExceptionMessage = لا يوجد اسم لإرسال رسالة إلى WebSocket المزود. +noSecretNamedMountedExceptionMessage = لم يتم تثبيت أي سر بالاسم '{0}'. +noNameForWebSocketResetExceptionMessage = لا يوجد اسم لإعادة تعيين WebSocket من المزود. +'@ diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index 7f6fa0086..4ef2490a8 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -2,7 +2,7 @@ ConvertFrom-StringData -StringData @' adModuleWindowsOnlyExceptionMessage = Active Directory-Modul nur unter Windows verfügbar. adModuleNotInstalledExceptionMessage = Das Active Directory-Modul ist nicht installiert. secretManagementModuleNotInstalledExceptionMessage = Das Modul Microsoft.PowerShell.SecretManagement ist nicht installiert. -secretVaultAlreadyRegisteredExceptionMessage = Ein Geheimtresor mit dem Namen '{0}' wurde bereits beim automatischen Importieren von Geheimtresoren registriert. +secretVaultAlreadyRegisteredAutoImportExceptionMessage = Ein Geheimtresor mit dem Namen '{0}' wurde bereits beim automatischen Importieren von Geheimtresoren registriert. failedToOpenRunspacePoolExceptionMessage = Fehler beim Öffnen des Runspace-Pools: {0} cronExpressionInvalidExceptionMessage = Die Cron-Ausdruck sollte nur aus 5 Teilen bestehen: {0} invalidAliasFoundExceptionMessage = Ungültiges {0}-Alias gefunden: {1} @@ -164,4 +164,18 @@ noSessionAvailableToSaveExceptionMessage = Keine Sitzung verfügbar zum Speicher cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Ein Intervall kann nicht angegeben werden, wenn der Parameter 'Every' auf None gesetzt ist. cannotSupplyIntervalForQuarterExceptionMessage = Ein Intervallwert kann nicht für jedes Quartal angegeben werden. cannotSupplyIntervalForYearExceptionMessage = Ein Intervallwert kann nicht für jedes Jahr angegeben werden. -'@ \ No newline at end of file +secretVaultAlreadyRegisteredExceptionMessage = Ein Geheimnis-Tresor mit dem Namen '{0}' wurde bereits registriert{1}. +secretVaultUnlockExpiryDateInPastExceptionMessage = Das Ablaufdatum zum Entsperren des Geheimnis-Tresors liegt in der Vergangenheit (UTC): {0} +secretAlreadyMountedExceptionMessage = Ein Geheimnis mit dem Namen '{0}' wurde bereits eingebunden. +noSecretVaultRegisteredExceptionMessage = Kein Geheimnis-Tresor mit dem Namen '{0}' wurde registriert. +noAdditionalPropertiesMutuallyExclusiveExceptionMessage = Die Parameter 'NoAdditionalProperties' und 'AdditionalProperties' schließen sich gegenseitig aus. +credentialsPassedWildcardForHeadersLiteralExceptionMessage = Wenn Anmeldeinformationen übergeben werden, wird das *-Wildcard für Header als Literalzeichenfolge und nicht als Platzhalter verwendet. +wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = Das *-Wildcard für Header ist nicht mit dem AutoHeaders-Schalter kompatibel. +wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = Das *-Wildcard für Methoden ist nicht mit dem AutoMethods-Schalter kompatibel. +invalidAccessControlMaxAgeDurationExceptionMessage = Ungültige Access-Control-Max-Age-Dauer angegeben: {0}. Sollte größer als 0 sein. +noNameForWebSocketDisconnectExceptionMessage = Kein Name für die Trennung vom WebSocket angegeben. +noNameForWebSocketRemoveExceptionMessage = Kein Name für das Entfernen des WebSocket angegeben. +noNameForWebSocketSendMessageExceptionMessage = Kein Name für das Senden einer Nachricht an den WebSocket angegeben. +noSecretNamedMountedExceptionMessage = Kein Geheimnis mit dem Namen '{0}' wurde eingebunden. +noNameForWebSocketResetExceptionMessage = Kein Name für das Zurücksetzen des WebSocket angegeben. +'@ diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 1e1785393..68307fa13 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -2,7 +2,7 @@ ConvertFrom-StringData -StringData @' adModuleWindowsOnlyExceptionMessage = Active Directory module only available on Windows. adModuleNotInstalledExceptionMessage = Active Directory module is not installed. secretManagementModuleNotInstalledExceptionMessage = Microsoft.PowerShell.SecretManagement module not installed. -secretVaultAlreadyRegisteredExceptionMessage = A Secret Vault with the name '{0}' has already been registered while auto-importing Secret Vaults. +secretVaultAlreadyRegisteredAutoImportExceptionMessage = A Secret Vault with the name '{0}' has already been registered while auto-importing Secret Vaults. failedToOpenRunspacePoolExceptionMessage = Failed to open RunspacePool: {0} cronExpressionInvalidExceptionMessage = Cron expression should only consist of 5 parts: {0} invalidAliasFoundExceptionMessage = Invalid {0} alias found: {1} @@ -164,4 +164,18 @@ noSessionAvailableToSaveExceptionMessage = There is no session available to save cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Cannot supply an interval when the parameter 'Every' is set to None. cannotSupplyIntervalForQuarterExceptionMessage = Cannot supply interval value for every quarter. cannotSupplyIntervalForYearExceptionMessage = Cannot supply interval value for every year. +secretVaultAlreadyRegisteredExceptionMessage = A Secret Vault with the name '{0}' has already been registered{1}. +secretVaultUnlockExpiryDateInPastExceptionMessage = Secret Vault unlock expiry date is in the past (UTC): {0} +secretAlreadyMountedExceptionMessage = A Secret with the name '{0}' has already been mounted +noSecretVaultRegisteredExceptionMessage = No Secret Vault with the name '{0}' has been registered +noAdditionalPropertiesMutuallyExclusiveExceptionMessage = Parameters 'NoAdditionalProperties' and 'AdditionalProperties' are mutually exclusive. +credentialsPassedWildcardForHeadersLiteralExceptionMessage = When Credentials is passed, The * wildcard for Headers will be taken as a literal string and not a wildcard. +wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = The * wildcard for Headers is incompatible with the AutoHeaders switch. +wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = The * wildcard for Methods is incompatible with the AutoMethods switch. +invalidAccessControlMaxAgeDurationExceptionMessage = Invalid Access-Control-Max-Age duration supplied: {0}. Should be greater than 0. +noNameForWebSocketDisconnectExceptionMessage = No Name for a WebSocket to disconnect from supplied. +noNameForWebSocketRemoveExceptionMessage = No Name for a WebSocket to remove supplied. +noNameForWebSocketSendMessageExceptionMessage = No Name for a WebSocket to send message to supplied. +noSecretNamedMountedExceptionMessage = No Secret named '{0}' has been mounted. +noNameForWebSocketResetExceptionMessage = No Name for a WebSocket to reset supplied. '@ \ No newline at end of file diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 5468df945..4524bc327 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -2,7 +2,7 @@ ConvertFrom-StringData -StringData @' adModuleWindowsOnlyExceptionMessage = El módulo de Active Directory solo está disponible en Windows. adModuleNotInstalledExceptionMessage = El módulo de Active Directory no está instalado. secretManagementModuleNotInstalledExceptionMessage = El módulo Microsoft.PowerShell.SecretManagement no está instalado. -secretVaultAlreadyRegisteredExceptionMessage = Ya se ha registrado un Bóveda Secreta con el nombre '{0}' al importar automáticamente Bóvedas Secretas. +secretVaultAlreadyRegisteredAutoImportExceptionMessage = Ya se ha registrado un Bóveda Secreta con el nombre '{0}' al importar automáticamente Bóvedas Secretas. failedToOpenRunspacePoolExceptionMessage = Error al abrir RunspacePool: {0} cronExpressionInvalidExceptionMessage = La expresión Cron solo debe consistir en 5 partes: {0} invalidAliasFoundExceptionMessage = Se encontró un alias {0} no válido: {1} @@ -164,4 +164,18 @@ noSessionAvailableToSaveExceptionMessage = No hay sesión disponible para guarda cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = No se puede proporcionar un intervalo cuando el parámetro 'Every' está configurado en None. cannotSupplyIntervalForQuarterExceptionMessage = No se puede proporcionar un valor de intervalo para cada trimestre. cannotSupplyIntervalForYearExceptionMessage = No se puede proporcionar un valor de intervalo para cada año. -'@ \ No newline at end of file +secretVaultAlreadyRegisteredExceptionMessage = Un Cofre de Secretos con el nombre '{0}' ya ha sido registrado{1}. +secretVaultUnlockExpiryDateInPastExceptionMessage = La fecha de expiración para desbloquear el Cofre de Secretos está en el pasado (UTC): {0} +secretAlreadyMountedExceptionMessage = Un Secreto con el nombre '{0}' ya ha sido montado. +noSecretVaultRegisteredExceptionMessage = No se ha registrado ningún Cofre de Secretos con el nombre '{0}'. +noAdditionalPropertiesMutuallyExclusiveExceptionMessage = Los parámetros 'NoAdditionalProperties' y 'AdditionalProperties' son mutuamente excluyentes. +credentialsPassedWildcardForHeadersLiteralExceptionMessage = Cuando se pasan las Credenciales, el comodín * para los Encabezados se tomará como una cadena literal y no como un comodín. +wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = El comodín * para los Encabezados es incompatible con el interruptor AutoHeaders. +wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = El comodín * para los Métodos es incompatible con el interruptor AutoMethods. +invalidAccessControlMaxAgeDurationExceptionMessage = Duración inválida para Access-Control-Max-Age proporcionada: {0}. Debe ser mayor que 0. +noNameForWebSocketDisconnectExceptionMessage = No se proporcionó ningún nombre para desconectar el WebSocket. +noNameForWebSocketRemoveExceptionMessage = No se proporcionó ningún nombre para eliminar el WebSocket. +noNameForWebSocketSendMessageExceptionMessage = No se proporcionó ningún nombre para enviar un mensaje al WebSocket. +noSecretNamedMountedExceptionMessage = No se ha montado ningún Secreto con el nombre '{0}'. +noNameForWebSocketResetExceptionMessage = No se proporcionó ningún nombre para restablecer el WebSocket. +'@ diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index 8e620534e..c231b7891 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -2,7 +2,7 @@ ConvertFrom-StringData -StringData @' adModuleWindowsOnlyExceptionMessage = Le module Active Directory est uniquement disponible sur Windows. adModuleNotInstalledExceptionMessage = Le module Active Directory n'est pas installé. secretManagementModuleNotInstalledExceptionMessage = Le module Microsoft.PowerShell.SecretManagement n'est pas installé. -secretVaultAlreadyRegisteredExceptionMessage = Un coffre-fort secret avec le nom '{0}' a déjà été enregistré lors de l'importation automatique des coffres-forts secrets. +secretVaultAlreadyRegisteredAutoImportExceptionMessage = Un coffre-fort secret avec le nom '{0}' a déjà été enregistré lors de l'importation automatique des coffres-forts secrets. failedToOpenRunspacePoolExceptionMessage = Échec de l'ouverture de RunspacePool : {0} cronExpressionInvalidExceptionMessage = L'expression Cron doit uniquement comporter 5 parties : {0} invalidAliasFoundExceptionMessage = Alias {0} non valide trouvé : {1} @@ -164,4 +164,18 @@ noSessionAvailableToSaveExceptionMessage = Aucune session disponible pour sauveg cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Impossible de fournir un intervalle lorsque le paramètre 'Every' est défini sur None. cannotSupplyIntervalForQuarterExceptionMessage = Impossible de fournir une valeur d'intervalle pour chaque trimestre. cannotSupplyIntervalForYearExceptionMessage = Impossible de fournir une valeur d'intervalle pour chaque année. -'@ \ No newline at end of file +secretVaultAlreadyRegisteredExceptionMessage = Un Coffre-Fort de Secrets avec le nom '{0}' a déjà été enregistré{1}. +secretVaultUnlockExpiryDateInPastExceptionMessage = La date d'expiration du déverrouillage du Coffre-Fort de Secrets est dans le passé (UTC) : {0} +secretAlreadyMountedExceptionMessage = Un Secret avec le nom '{0}' a déjà été monté. +noSecretVaultRegisteredExceptionMessage = Aucun Coffre-Fort de Secrets avec le nom '{0}' n'a été enregistré. +noAdditionalPropertiesMutuallyExclusiveExceptionMessage = Les paramètres 'NoAdditionalProperties' et 'AdditionalProperties' sont mutuellement exclusifs. +credentialsPassedWildcardForHeadersLiteralExceptionMessage = Lorsque des Identifiants sont passés, le caractère générique * pour les En-têtes sera pris comme une chaîne littérale et non comme un caractère générique. +wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = Le caractère générique * pour les En-têtes est incompatible avec le commutateur AutoHeaders. +wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = Le caractère générique * pour les Méthodes est incompatible avec le commutateur AutoMethods. +invalidAccessControlMaxAgeDurationExceptionMessage = Durée Access-Control-Max-Age invalide fournie : {0}. Doit être supérieure à 0. +noNameForWebSocketDisconnectExceptionMessage = Aucun Nom fourni pour déconnecter le WebSocket. +noNameForWebSocketRemoveExceptionMessage = Aucun Nom fourni pour supprimer le WebSocket. +noNameForWebSocketSendMessageExceptionMessage = Aucun Nom fourni pour envoyer un message au WebSocket. +noSecretNamedMountedExceptionMessage = Aucun Secret nommé '{0}' n'a été monté. +noNameForWebSocketResetExceptionMessage = Aucun Nom fourni pour réinitialiser le WebSocket. +'@ diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index 8d7c8ab58..87316e090 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -2,7 +2,7 @@ ConvertFrom-StringData -StringData @' adModuleWindowsOnlyExceptionMessage = Il modulo Active Directory è disponibile solo su Windows. adModuleNotInstalledExceptionMessage = Il modulo Active Directory non è installato. secretManagementModuleNotInstalledExceptionMessage = Il modulo Microsoft.PowerShell.SecretManagement non è installato. -secretVaultAlreadyRegisteredExceptionMessage = Una cassaforte segreta con il nome '{0}' è già stata registrata durante l'importazione automatica delle cassaforti segrete. +secretVaultAlreadyRegisteredAutoImportExceptionMessage = Una cassaforte segreta con il nome '{0}' è già stata registrata durante l'importazione automatica delle cassaforti segrete. failedToOpenRunspacePoolExceptionMessage = Impossibile aprire RunspacePool: {0} cronExpressionInvalidExceptionMessage = L'espressione Cron dovrebbe essere composta solo da 5 parti: {0} invalidAliasFoundExceptionMessage = Alias {0} non valido trovato: {1} @@ -164,4 +164,18 @@ noSessionAvailableToSaveExceptionMessage = Nessuna sessione disponibile per il s cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Impossibile fornire un intervallo quando il parametro 'Every' è impostato su None. cannotSupplyIntervalForQuarterExceptionMessage = Impossibile fornire un valore di intervallo per ogni trimestre. cannotSupplyIntervalForYearExceptionMessage = Impossibile fornire un valore di intervallo per ogni anno. -'@ \ No newline at end of file +secretVaultAlreadyRegisteredExceptionMessage = Un Vault dei Segreti con il nome '{0}' è già stato registrato{1}. +secretVaultUnlockExpiryDateInPastExceptionMessage = La data di scadenza per sbloccare il Vault dei Segreti è nel passato (UTC): {0} +secretAlreadyMountedExceptionMessage = Un Segreto con il nome '{0}' è già stato montato. +noSecretVaultRegisteredExceptionMessage = Nessun Vault dei Segreti con il nome '{0}' è stato registrato. +noAdditionalPropertiesMutuallyExclusiveExceptionMessage = I parametri 'NoAdditionalProperties' e 'AdditionalProperties' sono mutuamente esclusivi. +credentialsPassedWildcardForHeadersLiteralExceptionMessage = Quando vengono passate le Credenziali, il carattere jolly * per le Intestazioni sarà considerato come una stringa letterale e non come un carattere jolly. +wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = Il carattere jolly * per le Intestazioni è incompatibile con l'opzione AutoHeaders. +wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = Il carattere jolly * per i Metodi è incompatibile con l'opzione AutoMethods. +invalidAccessControlMaxAgeDurationExceptionMessage = Durata non valida fornita per Access-Control-Max-Age: {0}. Deve essere maggiore di 0. +noNameForWebSocketDisconnectExceptionMessage = Nessun nome fornito per disconnettere il WebSocket. +noNameForWebSocketRemoveExceptionMessage = Nessun nome fornito per rimuovere il WebSocket. +noNameForWebSocketSendMessageExceptionMessage = Nessun nome fornito per inviare un messaggio al WebSocket. +noSecretNamedMountedExceptionMessage = Nessun Segreto con il nome '{0}' è stato montato. +noNameForWebSocketResetExceptionMessage = Nessun nome fornito per reimpostare il WebSocket. +'@ diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index ef6a43934..d5dc10f5b 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -2,7 +2,7 @@ ConvertFrom-StringData -StringData @' adModuleWindowsOnlyExceptionMessage = Active DirectoryモジュールはWindowsでのみ利用可能です。 adModuleNotInstalledExceptionMessage = Active Directoryモジュールがインストールされていません。 secretManagementModuleNotInstalledExceptionMessage = Microsoft.PowerShell.SecretManagementモジュールがインストールされていません。 -secretVaultAlreadyRegisteredExceptionMessage = シークレットボールト'{0}'は既に登録されています(シークレットボールトの自動インポート中)。 +secretVaultAlreadyRegisteredAutoImportExceptionMessage = シークレットボールト'{0}'は既に登録されています(シークレットボールトの自動インポート中)。 failedToOpenRunspacePoolExceptionMessage = RunspacePoolのオープンに失敗しました: {0} cronExpressionInvalidExceptionMessage = Cron式は5つの部分で構成される必要があります: {0} invalidAliasFoundExceptionMessage = 無効な{0}エイリアスが見つかりました: {1} @@ -164,4 +164,19 @@ noSessionAvailableToSaveExceptionMessage = 保存するためのセッション cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = パラメーター'Every'がNoneに設定されている場合、間隔を提供できません。 cannotSupplyIntervalForQuarterExceptionMessage = 四半期ごとの間隔値を提供できません。 cannotSupplyIntervalForYearExceptionMessage = 毎年の間隔値を提供できません。 +secretVaultAlreadyRegisteredExceptionMessage = 名前 '{0}' のシークレットボールトは既に登録されています{1}。 +secretVaultUnlockExpiryDateInPastExceptionMessage = シークレットボールトのアンロック有効期限が過去に設定されています (UTC) :{0} +secretAlreadyMountedExceptionMessage = 名前 '{0}' のシークレットは既にマウントされています。 +noSecretVaultRegisteredExceptionMessage = 名前 '{0}' のシークレットボールトは登録されていません。 +noAdditionalPropertiesMutuallyExclusiveExceptionMessage = パラメータ 'NoAdditionalProperties' と 'AdditionalProperties' は相互に排他的です。 +credentialsPassedWildcardForHeadersLiteralExceptionMessage = 資格情報が渡されると、ヘッダーのワイルドカード * はワイルドカードとしてではなく、リテラル文字列として解釈されます。 +wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = ヘッダーのワイルドカード * は AutoHeaders スイッチと互換性がありません。 +wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = メソッドのワイルドカード * は AutoMethods スイッチと互換性がありません。 +invalidAccessControlMaxAgeDurationExceptionMessage = 無効な Access-Control-Max-Age 期間が提供されました:{0}。0 より大きくする必要があります。 +noNameForWebSocketDisconnectExceptionMessage = 切断する WebSocket の名前が指定されていません。 +noNameForWebSocketRemoveExceptionMessage = 削除する WebSocket の名前が指定されていません。 +noNameForWebSocketSendMessageExceptionMessage = メッセージを送信する WebSocket の名前が指定されていません。 +noSecretNamedMountedExceptionMessage = 名前 '{0}' のシークレットはマウントされていません。 +noNameForWebSocketResetExceptionMessage = リセットする WebSocket の名前が指定されていません。 '@ + diff --git a/src/Locales/kr/Pode.psd1 b/src/Locales/kr/Pode.psd1 index d75ec5c19..da743cbf7 100644 --- a/src/Locales/kr/Pode.psd1 +++ b/src/Locales/kr/Pode.psd1 @@ -2,7 +2,7 @@ ConvertFrom-StringData -StringData @' adModuleWindowsOnlyExceptionMessage = Active Directory 모듈은 Windows에서만 사용할 수 있습니다. adModuleNotInstalledExceptionMessage = Active Directory 모듈이 설치되지 않았습니다. secretManagementModuleNotInstalledExceptionMessage = Microsoft.PowerShell.SecretManagement 모듈이 설치되지 않았습니다. -secretVaultAlreadyRegisteredExceptionMessage = 이름이 '{0}'인 비밀 금고가 이미 자동으로 가져오는 동안 등록되었습니다. +secretVaultAlreadyRegisteredAutoImportExceptionMessage = 이름이 '{0}'인 비밀 금고가 이미 자동으로 가져오는 동안 등록되었습니다. failedToOpenRunspacePoolExceptionMessage = RunspacePool을 여는 데 실패했습니다: {0} cronExpressionInvalidExceptionMessage = Cron 표현식은 5개의 부분으로만 구성되어야 합니다: {0} invalidAliasFoundExceptionMessage = 잘못된 {0} 별칭이 발견되었습니다: {1} @@ -164,4 +164,18 @@ noSessionAvailableToSaveExceptionMessage = 저장할 수 있는 세션이 없습 cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = 매개변수 'Every'가 None으로 설정된 경우 간격을 제공할 수 없습니다. cannotSupplyIntervalForQuarterExceptionMessage = 분기별 간격 값을 제공할 수 없습니다. cannotSupplyIntervalForYearExceptionMessage = 매년 간격 값을 제공할 수 없습니다. -'@ \ No newline at end of file +secretVaultAlreadyRegisteredExceptionMessage = 이름이 '{0}'인 시크릿 금고가 이미 등록되었습니다{1}. +secretVaultUnlockExpiryDateInPastExceptionMessage = 시크릿 금고의 잠금 해제 만료 날짜가 과거입니다 (UTC): {0} +secretAlreadyMountedExceptionMessage = 이름이 '{0}'인 시크릿이 이미 마운트되었습니다. +noSecretVaultRegisteredExceptionMessage = 이름이 '{0}'인 시크릿 금고가 등록되지 않았습니다. +noAdditionalPropertiesMutuallyExclusiveExceptionMessage = 'NoAdditionalProperties' 및 'AdditionalProperties' 매개변수는 상호 배타적입니다. +credentialsPassedWildcardForHeadersLiteralExceptionMessage = 자격 증명이 전달되면, 헤더에 대한 * 와일드카드는 와일드카드가 아닌 리터럴 문자열로 취급됩니다. +wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 헤더에 대한 * 와일드카드는 AutoHeaders 스위치와 호환되지 않습니다. +wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 메서드에 대한 * 와일드카드는 AutoMethods 스위치와 호환되지 않습니다. +invalidAccessControlMaxAgeDurationExceptionMessage = 잘못된 Access-Control-Max-Age 기간이 제공되었습니다: {0}. 0보다 커야 합니다. +noNameForWebSocketDisconnectExceptionMessage = 연결을 끊을 WebSocket의 이름이 제공되지 않았습니다. +noNameForWebSocketRemoveExceptionMessage = 제거할 WebSocket의 이름이 제공되지 않았습니다. +noNameForWebSocketSendMessageExceptionMessage = 메시지를 보낼 WebSocket의 이름이 제공되지 않았습니다. +noSecretNamedMountedExceptionMessage = 이름이 '{0}'인 시크릿이 마운트되지 않았습니다. +noNameForWebSocketResetExceptionMessage = 재설정할 WebSocket의 이름이 제공되지 않았습니다. +'@ diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index 08b432c82..6c14ac170 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -2,7 +2,7 @@ ConvertFrom-StringData -StringData @' adModuleWindowsOnlyExceptionMessage = Moduł Active Directory jest dostępny tylko w systemie Windows. adModuleNotInstalledExceptionMessage = Moduł Active Directory nie jest zainstalowany. secretManagementModuleNotInstalledExceptionMessage = Moduł Microsoft.PowerShell.SecretManagement nie jest zainstalowany. -secretVaultAlreadyRegisteredExceptionMessage = Skarbiec z nazwą '{0}' został już zarejestrowany podczas automatycznego importowania skarbców. +secretVaultAlreadyRegisteredAutoImportExceptionMessage = Skarbiec z nazwą '{0}' został już zarejestrowany podczas automatycznego importowania skarbców. failedToOpenRunspacePoolExceptionMessage = Nie udało się otworzyć RunspacePool: {0} cronExpressionInvalidExceptionMessage = Wyrażenie Cron powinno składać się tylko z 5 części: {0} invalidAliasFoundExceptionMessage = Znaleziono nieprawidłowy alias {0}: {1} @@ -164,4 +164,18 @@ noSessionAvailableToSaveExceptionMessage = Brak dostępnej sesji do zapisania. cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Nie można dostarczyć interwału, gdy parametr 'Every' jest ustawiony na None. cannotSupplyIntervalForQuarterExceptionMessage = Nie można dostarczyć wartości interwału dla każdego kwartału. cannotSupplyIntervalForYearExceptionMessage = Nie można dostarczyć wartości interwału dla każdego roku. -'@ \ No newline at end of file +secretVaultAlreadyRegisteredExceptionMessage = Skarbiec tajemnic o nazwie '{0}' został już zarejestrowany{1}. +secretVaultUnlockExpiryDateInPastExceptionMessage = Data wygaśnięcia odblokowania Skarbca tajemnic jest w przeszłości (UTC): {0} +secretAlreadyMountedExceptionMessage = Tajemnica o nazwie '{0}' została już zamontowana. +noSecretVaultRegisteredExceptionMessage = Skarbiec tajemnic o nazwie '{0}' nie został zarejestrowany. +noAdditionalPropertiesMutuallyExclusiveExceptionMessage = Parametry 'NoAdditionalProperties' i 'AdditionalProperties' wykluczają się wzajemnie. +credentialsPassedWildcardForHeadersLiteralExceptionMessage = Gdy przekazywane są dane uwierzytelniające, symbol wieloznaczny * dla nagłówków będzie traktowany jako dosłowny ciąg znaków, a nie symbol wieloznaczny. +wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = Symbol wieloznaczny * dla nagłówków jest niezgodny z przełącznikiem AutoHeaders. +wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = Symbol wieloznaczny * dla metod jest niezgodny z przełącznikiem AutoMethods. +invalidAccessControlMaxAgeDurationExceptionMessage = Podano nieprawidłowy czas trwania Access-Control-Max-Age: {0}. Powinien być większy niż 0. +noNameForWebSocketDisconnectExceptionMessage = Nie podano nazwy dla rozłączenia WebSocket. +noNameForWebSocketRemoveExceptionMessage = Nie podano nazwy dla usunięcia WebSocket. +noNameForWebSocketSendMessageExceptionMessage = Nie podano nazwy dla wysłania wiadomości do WebSocket. +noSecretNamedMountedExceptionMessage = Nie zamontowano tajemnicy o nazwie '{0}'. +noNameForWebSocketResetExceptionMessage = Nie podano nazwy dla resetowania WebSocket. +'@ diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index 9f1e5f315..48f00bae8 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -2,7 +2,7 @@ ConvertFrom-StringData -StringData @' adModuleWindowsOnlyExceptionMessage = O módulo Active Directory está disponível apenas no Windows. adModuleNotInstalledExceptionMessage = O módulo Active Directory não está instalado. secretManagementModuleNotInstalledExceptionMessage = O módulo Microsoft.PowerShell.SecretManagement não está instalado. -secretVaultAlreadyRegisteredExceptionMessage = Um Cofre de Segredos com o nome '{0}' já foi registrado durante a importação automática de Cofres de Segredos. +secretVaultAlreadyRegisteredAutoImportExceptionMessage = Um Cofre de Segredos com o nome '{0}' já foi registrado durante a importação automática de Cofres de Segredos. failedToOpenRunspacePoolExceptionMessage = Falha ao abrir o RunspacePool: {0} cronExpressionInvalidExceptionMessage = A expressão Cron deve consistir apenas em 5 partes: {0} invalidAliasFoundExceptionMessage = Alias {0} inválido encontrado: {1} @@ -164,4 +164,18 @@ noSessionAvailableToSaveExceptionMessage = Não há sessão disponível para sal cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Não é possível fornecer um intervalo quando o parâmetro 'Every' está definido como None. cannotSupplyIntervalForQuarterExceptionMessage = Não é possível fornecer um valor de intervalo para cada trimestre. cannotSupplyIntervalForYearExceptionMessage = Não é possível fornecer um valor de intervalo para cada ano. -'@ \ No newline at end of file +secretVaultAlreadyRegisteredExceptionMessage = Um Cofre de Segredos com o nome '{0}' já foi registrado{1}. +secretVaultUnlockExpiryDateInPastExceptionMessage = A data de expiração de desbloqueio do Cofre de Segredos está no passado (UTC): {0} +secretAlreadyMountedExceptionMessage = Um Segredo com o nome '{0}' já foi montado. +noSecretVaultRegisteredExceptionMessage = Nenhum Cofre de Segredos com o nome '{0}' foi registrado. +noAdditionalPropertiesMutuallyExclusiveExceptionMessage = Os parâmetros 'NoAdditionalProperties' e 'AdditionalProperties' são mutuamente exclusivos. +credentialsPassedWildcardForHeadersLiteralExceptionMessage = Quando as Credenciais são passadas, o caractere curinga * para os Cabeçalhos será interpretado como uma string literal e não como um caractere curinga. +wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = O caractere curinga * para os Cabeçalhos é incompatível com a chave AutoHeaders. +wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = O caractere curinga * para os Métodos é incompatível com a chave AutoMethods. +invalidAccessControlMaxAgeDurationExceptionMessage = Duração inválida fornecida para Access-Control-Max-Age: {0}. Deve ser maior que 0. +noNameForWebSocketDisconnectExceptionMessage = Nenhum nome fornecido para desconectar do WebSocket. +noNameForWebSocketRemoveExceptionMessage = Nenhum nome fornecido para remover o WebSocket. +noNameForWebSocketSendMessageExceptionMessage = Nenhum nome fornecido para enviar mensagem ao WebSocket. +noSecretNamedMountedExceptionMessage = Nenhum Segredo com o nome '{0}' foi montado. +noNameForWebSocketResetExceptionMessage = Nenhum nome fornecido para redefinir o WebSocket. +'@ diff --git a/src/Locales/zn/Pode.psd1 b/src/Locales/zn/Pode.psd1 index 8d22b0ab4..24551f086 100644 --- a/src/Locales/zn/Pode.psd1 +++ b/src/Locales/zn/Pode.psd1 @@ -2,7 +2,7 @@ ConvertFrom-StringData -StringData @' adModuleWindowsOnlyExceptionMessage = 仅支持 Windows 的 Active Directory 模块。 adModuleNotInstalledExceptionMessage = 未安装 Active Directory 模块。 secretManagementModuleNotInstalledExceptionMessage = 未安装 Microsoft.PowerShell.SecretManagement 模块。 -secretVaultAlreadyRegisteredExceptionMessage = 已经注册了名称为 '{0}' 的秘密保险库,同时正在自动导入秘密保险库。 +secretVaultAlreadyRegisteredAutoImportExceptionMessage = 已经注册了名称为 '{0}' 的秘密保险库,同时正在自动导入秘密保险库。 failedToOpenRunspacePoolExceptionMessage = 打开 RunspacePool 失败: {0} cronExpressionInvalidExceptionMessage = Cron 表达式应仅包含 5 个部分: {0} invalidAliasFoundExceptionMessage = 找到了无效的 {0} 别名: {1} @@ -164,4 +164,18 @@ noSessionAvailableToSaveExceptionMessage = 没有可保存的会话。 cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = 当参数'Every'设置为None时, 无法提供间隔。 cannotSupplyIntervalForQuarterExceptionMessage = 无法为每季度提供间隔值。 cannotSupplyIntervalForYearExceptionMessage = 无法为每年提供间隔值。 -'@ \ No newline at end of file +secretVaultAlreadyRegisteredExceptionMessage = 名为“{0}”的秘密保险库已注册{1}。 +secretVaultUnlockExpiryDateInPastExceptionMessage = 秘密保险库的解锁到期日期已过 (UTC) :{0} +secretAlreadyMountedExceptionMessage = 名为“{0}”的秘密已挂载。 +noSecretVaultRegisteredExceptionMessage = 没有注册名为“{0}”的秘密保险库。 +noAdditionalPropertiesMutuallyExclusiveExceptionMessage = 参数 'NoAdditionalProperties' 和 'AdditionalProperties' 是互斥的。 +credentialsPassedWildcardForHeadersLiteralExceptionMessage = 传递凭据时,标头的通配符 * 将被视为文字字符串,而不是通配符。 +wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 标头的通配符 * 与 AutoHeaders 开关不兼容。 +wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 方法的通配符 * 与 AutoMethods 开关不兼容。 +invalidAccessControlMaxAgeDurationExceptionMessage = 提供的 Access-Control-Max-Age 时长无效:{0}。应大于 0。 +noNameForWebSocketDisconnectExceptionMessage = 没有提供断开连接的 WebSocket 的名称。 +noNameForWebSocketRemoveExceptionMessage = 没有提供要删除的 WebSocket 的名称。 +noNameForWebSocketSendMessageExceptionMessage = 没有提供要发送消息的 WebSocket 的名称。 +noSecretNamedMountedExceptionMessage = 没有挂载名为“{0}”的秘密。 +noNameForWebSocketResetExceptionMessage = 没有提供要重置的 WebSocket 的名称。 +'@ diff --git a/src/Pode.psm1 b/src/Pode.psm1 index ad21d2e0f..bf3f6fd54 100644 --- a/src/Pode.psm1 +++ b/src/Pode.psm1 @@ -37,10 +37,10 @@ if ([string]::IsNullOrEmpty($UICulture)) { } #Culture list available here https://azuliadesigns.com/c-sharp-tutorials/list-net-culture-country-codes/ -Import-LocalizedData -BindingVariable tmpMsgtable -BaseDirectory (Join-Path -Path $root -ChildPath 'Locales') -UICulture $UICulture -ErrorAction:SilentlyContinue -if ($null -eq $tmpMsgtable) { +Import-LocalizedData -BindingVariable tmpPodeLocale -BaseDirectory (Join-Path -Path $root -ChildPath 'Locales') -UICulture $UICulture -ErrorAction:SilentlyContinue +if ($null -eq $tmpPodeLocale) { try { - Import-LocalizedData -BindingVariable tmpMsgtable -BaseDirectory (Join-Path -Path $root -ChildPath 'Locales') -UICulture 'en' -ErrorAction:Stop + Import-LocalizedData -BindingVariable tmpPodeLocale -BaseDirectory (Join-Path -Path $root -ChildPath 'Locales') -UICulture 'en' -ErrorAction:Stop } catch { throw @@ -49,7 +49,7 @@ if ($null -eq $tmpMsgtable) { try { # Create the global msgTable read-only variable - New-Variable -Name 'msgTable' -Value $tmpMsgtable -Scope Global -Option ReadOnly -Force + New-Variable -Name 'PodeLocale' -Value $tmpMsgtable -Scope Global -Option ReadOnly -Force # load assemblies Add-Type -AssemblyName System.Web -ErrorAction Stop @@ -71,7 +71,8 @@ if ($podeDll) { if ( $moduleManifest.ModuleVersion -ne '$version$') { $moduleVersion = ([version]::new($moduleManifest.ModuleVersion + '.0')) if ($podeDll.GetName().Version -ne $moduleVersion) { - throw ($msgTable.incompatiblePodeDllExceptionMessage -f $podeDll.GetName().Version, $moduleVersion) #"An existing incompatible Pode.DLL version $($podeDll.GetName().Version) is loaded. Version $moduleVersion is required. Open a new Powershell/pwsh session and retry." + # An existing incompatible Pode.DLL version {0} is loaded. Version {1} is required. Open a new Powershell/pwsh session and retry. + throw ($PodeLocale.incompatiblePodeDllExceptionMessage -f $podeDll.GetName().Version, $moduleVersion) } } } diff --git a/src/Private/Authentication.ps1 b/src/Private/Authentication.ps1 index 6acaa91c4..6b82e6a6c 100644 --- a/src/Private/Authentication.ps1 +++ b/src/Private/Authentication.ps1 @@ -2195,12 +2195,12 @@ function Expand-PodeAuthMerge { function Import-PodeAuthADModule { if (!(Test-PodeIsWindows)) { # Active Directory module only available on Windows - throw $msgTable.adModuleWindowsOnlyExceptionMessage + throw $PodeLocale.adModuleWindowsOnlyExceptionMessage } if (!(Test-PodeModuleInstalled -Name ActiveDirectory)) { # Active Directory module is not installed - throw $msgTable.adModuleNotInstalledExceptionMessage + throw $PodeLocale.adModuleNotInstalledExceptionMessage } Import-Module -Name ActiveDirectory -Force -ErrorAction Stop diff --git a/src/Private/AutoImport.ps1 b/src/Private/AutoImport.ps1 index 3bf5f0828..e3ec5ac5f 100644 --- a/src/Private/AutoImport.ps1 +++ b/src/Private/AutoImport.ps1 @@ -178,7 +178,7 @@ function Import-PodeSecretManagementVaultsIntoRegistry { # error if SecretManagement module not installed if (!(Test-PodeModuleInstalled -Name Microsoft.PowerShell.SecretManagement)) { # Microsoft.PowerShell.SecretManagement module not installed - throw $msgTable.secretManagementModuleNotInstalledExceptionMessage + throw $PodeLocale.secretManagementModuleNotInstalledExceptionMessage } # import the module @@ -196,7 +196,8 @@ function Import-PodeSecretManagementVaultsIntoRegistry { # is a vault with this name already registered? if (Test-PodeSecretVault -Name $vault.Name) { - throw ($msgTable.secretVaultAlreadyRegisteredExceptionMessage -f $vault.Name) #"A Secret Vault with the name '$($vault.Name)' has already been registered while auto-importing Secret Vaults" + throw ($PodeLocale.secretVaultAlreadyRegisteredExceptionMessage -f $vault.Name) + #"A Secret Vault with the name '$($vault.Name)' has already been registered while auto-importing Secret Vaults" } # register the vault diff --git a/src/Private/Context.ps1 b/src/Private/Context.ps1 index b60e0629b..af03fcf86 100644 --- a/src/Private/Context.ps1 +++ b/src/Private/Context.ps1 @@ -493,6 +493,7 @@ function New-PodeRunspaceState { $session = New-PodeStateContext -Context $PodeContext $variables = @( + (New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'PodeLocale', $PodeLocale, $null), (New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'PodeContext', $session, $null), (New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'Console', $Host, $null), (New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'PODE_SCOPE_RUNSPACE', $true, $null) @@ -666,7 +667,7 @@ function Open-PodeRunspacePools { if ($item.Pool.RunspacePoolStateInfo.State -ieq 'broken') { $item.Pool.EndOpen($item.Result) | Out-Default - throw ($msgTable.failedToOpenRunspacePoolExceptionMessage -f $key) #"Failed to open RunspacePool: $($key)" + throw ($PodeLocale.failedToOpenRunspacePoolExceptionMessage -f $key) #"Failed to open RunspacePool: $($key)" } } @@ -722,7 +723,7 @@ function Close-PodeRunspacePools { if ($item.Pool.RunspacePoolStateInfo.State -ieq 'broken') { $item.Pool.EndClose($item.Result) | Out-Default - throw ($msgTable.failedToOpenRunspacePoolExceptionMessage -f $key) #"Failed to open RunspacePool: $($key)" + throw ($PodeLocale.failedToOpenRunspacePoolExceptionMessage -f $key) #"Failed to open RunspacePool: $($key)" } } diff --git a/src/Private/CronParser.ps1 b/src/Private/CronParser.ps1 index d3358732a..f21f4cd8a 100644 --- a/src/Private/CronParser.ps1 +++ b/src/Private/CronParser.ps1 @@ -109,7 +109,7 @@ function ConvertFrom-PodeCronExpression { # split and check atoms length $atoms = @($Expression -isplit '\s+') if ($atoms.Length -ne 5) { - throw ($msgTable.cronExpressionInvalidExceptionMessage -f $Expression) #"Cron expression should only consist of 5 parts: $($Expression)" + throw ($PodeLocale.cronExpressionInvalidExceptionMessage -f $Expression) #"Cron expression should only consist of 5 parts: $($Expression)" } # basic variables @@ -140,7 +140,7 @@ function ConvertFrom-PodeCronExpression { while ($_atom -imatch $aliasRgx) { $_alias = $_aliases[$Matches['tag']] if ($null -eq $_alias) { - throw ($msgTable.invalidAliasFoundExceptionMessage -f $_field, $Matches['tag']) #"Invalid $($_field) alias found: $($Matches['tag'])" + throw ($PodeLocale.invalidAliasFoundExceptionMessage -f $_field, $Matches['tag']) #"Invalid $($_field) alias found: $($Matches['tag'])" } $_atom = $_atom -ireplace $Matches['tag'], $_alias @@ -150,7 +150,7 @@ function ConvertFrom-PodeCronExpression { # ensure atom is a valid value if (!($_atom -imatch '^[\d|/|*|\-|,r]+$')) { - throw ($msgTable.invalidAtomCharacterExceptionMessage -f $_atom)#"Invalid atom character: $($_atom)" + throw ($PodeLocale.invalidAtomCharacterExceptionMessage -f $_atom)#"Invalid atom character: $($_atom)" } # replace * with min/max constraint @@ -214,28 +214,28 @@ function ConvertFrom-PodeCronExpression { # error else { - throw ($msgTable.invalidAtomCharacterExceptionMessage -f $_atom)#"Invalid cron atom format found: $($_atom)" + throw ($PodeLocale.invalidAtomCharacterExceptionMessage -f $_atom)#"Invalid cron atom format found: $($_atom)" } # ensure cron expression values are valid if ($null -ne $_cronExp.Range) { if ($_cronExp.Range.Min -gt $_cronExp.Range.Max) { - throw ($msgTable.minValueGreaterThanMaxExceptionMessage -f $_field) #"Min value for $($_field) should not be greater than the max value" + throw ($PodeLocale.minValueGreaterThanMaxExceptionMessage -f $_field) #"Min value for $($_field) should not be greater than the max value" } if ($_cronExp.Range.Min -lt $_constraint[0]) { - throw ($msgTable.minValueInvalidExceptionMessage -f $_cronExp.Range.Min, $_field, $_constraint[0]) #"Min value '$($_cronExp.Range.Min)' for $($_field) is invalid, should be greater than/equal to $($_constraint[0])" + throw ($PodeLocale.minValueInvalidExceptionMessage -f $_cronExp.Range.Min, $_field, $_constraint[0]) #"Min value '$($_cronExp.Range.Min)' for $($_field) is invalid, should be greater than/equal to $($_constraint[0])" } if ($_cronExp.Range.Max -gt $_constraint[1]) { - throw ($msgTable.maxValueInvalidExceptionMessage -f $_cronExp.Range.Max, $_field, $_constraint[1]) #"Max value '$($_cronExp.Range.Max)' for $($_field) is invalid, should be less than/equal to $($_constraint[1])" + throw ($PodeLocale.maxValueInvalidExceptionMessage -f $_cronExp.Range.Max, $_field, $_constraint[1]) #"Max value '$($_cronExp.Range.Max)' for $($_field) is invalid, should be less than/equal to $($_constraint[1])" } } if ($null -ne $_cronExp.Values) { $_cronExp.Values | ForEach-Object { if ($_ -lt $_constraint[0] -or $_ -gt $_constraint[1]) { - throw ($msgTable.valueOutOfRangeExceptionMessage -f $value, $_field, $_constraint[0], $_constraint[1]) #"Value '$($_)' for $($_field) is invalid, should be between $($_constraint[0]) and $($_constraint[1])" + throw ($PodeLocale.valueOutOfRangeExceptionMessage -f $value, $_field, $_constraint[0], $_constraint[1]) #"Value '$($_)' for $($_field) is invalid, should be between $($_constraint[0]) and $($_constraint[1])" } } } @@ -250,7 +250,7 @@ function ConvertFrom-PodeCronExpression { foreach ($mon in $cron['Month'].Values) { foreach ($day in $cron['DayOfMonth'].Values) { if ($day -gt $constraints.DaysInMonths[$mon - 1]) { - throw ($msgTable.daysInMonthExceededExceptionMessage -f $constraints.Months[$mon - 1], $constraints.DaysInMonths[$mon - 1], $day) #"$($constraints.Months[$mon - 1]) only has $($constraints.DaysInMonths[$mon - 1]) days, but $($day) was supplied" + throw ($PodeLocale.daysInMonthExceededExceptionMessage -f $constraints.Months[$mon - 1], $constraints.DaysInMonths[$mon - 1], $day) #"$($constraints.Months[$mon - 1]) only has $($constraints.DaysInMonths[$mon - 1]) days, but $($day) was supplied" } } } @@ -518,7 +518,7 @@ function Get-PodeCronNextTrigger { # before we return, make sure the time is valid if (!(Test-PodeCronExpression -Expression $Expression -DateTime $NextTime)) { - throw ($msgTable.nextTriggerCalculationErrorExceptionMessage -f $NextTime) #"Looks like something went wrong trying to calculate the next trigger datetime: $($NextTime)" + throw ($PodeLocale.nextTriggerCalculationErrorExceptionMessage -f $NextTime) #"Looks like something went wrong trying to calculate the next trigger datetime: $($NextTime)" } # if before the start or after end then return null diff --git a/src/Private/Cryptography.ps1 b/src/Private/Cryptography.ps1 index d77012fe2..b295335a7 100644 --- a/src/Private/Cryptography.ps1 +++ b/src/Private/Cryptography.ps1 @@ -20,7 +20,7 @@ function Invoke-PodeHMACSHA256Hash { if ($SecretBytes.Length -eq 0) { # No secret supplied for HMAC256 hash - throw $msgTable.noSecretForHmac256ExceptionMessage + throw $PodeLocale.noSecretForHmac256ExceptionMessage } $crypto = [System.Security.Cryptography.HMACSHA256]::new($SecretBytes) @@ -49,7 +49,7 @@ function Invoke-PodeHMACSHA384Hash { if ($SecretBytes.Length -eq 0) { # No secret supplied for HMAC384 hash - throw $msgTable.noSecretForHmac384ExceptionMessage + throw $PodeLocale.noSecretForHmac384ExceptionMessage } $crypto = [System.Security.Cryptography.HMACSHA384]::new($SecretBytes) @@ -78,7 +78,7 @@ function Invoke-PodeHMACSHA512Hash { if ($SecretBytes.Length -eq 0) { # No secret supplied for HMAC512 hash - throw $msgTable.noSecretForHmac512ExceptionMessage + throw $PodeLocale.noSecretForHmac512ExceptionMessage } $crypto = [System.Security.Cryptography.HMACSHA512]::new($SecretBytes) @@ -308,12 +308,12 @@ function New-PodeJwtSignature { if (($Algorithm -ine 'none') -and (($null -eq $SecretBytes) -or ($SecretBytes.Length -eq 0))) { # No secret supplied for JWT signature - throw $msgTable.noSecretForJwtSignatureExceptionMessage + throw $PodeLocale.noSecretForJwtSignatureExceptionMessage } if (($Algorithm -ieq 'none') -and (($null -ne $secretBytes) -and ($SecretBytes.Length -gt 0))) { # Expected no secret to be supplied for no signature - throw $msgTable.noSecretExpectedForNoSignatureExceptionMessage + throw $PodeLocale.noSecretExpectedForNoSignatureExceptionMessage } $sig = $null @@ -339,7 +339,7 @@ function New-PodeJwtSignature { } default { - throw ($msgTable.unsupportedJwtAlgorithmExceptionMessage -f $Algorithm) #"The JWT algorithm is not currently supported: $($Algorithm)" + throw ($PodeLocale.unsupportedJwtAlgorithmExceptionMessage -f $Algorithm) #"The JWT algorithm is not currently supported: $($Algorithm)" } } @@ -399,7 +399,7 @@ function ConvertFrom-PodeJwtBase64Value { } catch { # Invalid Base64 encoded value found in JWT - throw $msgTable.invalidBase64JwtExceptionMessage + throw $PodeLocale.invalidBase64JwtExceptionMessage } # return json @@ -408,6 +408,6 @@ function ConvertFrom-PodeJwtBase64Value { } catch { # Invalid JSON value found in JWT - throw $msgTable.invalidJsonJwtExceptionMessage + throw $PodeLocale.invalidJsonJwtExceptionMessage } } \ No newline at end of file diff --git a/src/Private/Endpoints.ps1 b/src/Private/Endpoints.ps1 index 86e34f436..0414817ab 100644 --- a/src/Private/Endpoints.ps1 +++ b/src/Private/Endpoints.ps1 @@ -282,7 +282,7 @@ function Find-PodeEndpointName { # error? if ($ThrowError) { - throw ($msgTable.endpointNotExistExceptionMessage -f $Protocol, $Address, $_localAddress) #"Endpoint with protocol '$($Protocol)' and address '$($Address)' or local address '$($_localAddress)' does not exist" + throw ($PodeLocale.endpointNotExistExceptionMessage -f $Protocol, $Address, $_localAddress) #"Endpoint with protocol '$($Protocol)' and address '$($Address)' or local address '$($_localAddress)' does not exist" } return $null @@ -310,7 +310,7 @@ function Get-PodeEndpointByName { # error? if ($ThrowError) { - throw ($msgTable.endpointNameNotExistExceptionMessage -f $Name) #"Endpoint with name '$($Name)' does not exist" + throw ($PodeLocale.endpointNameNotExistExceptionMessage -f $Name) #"Endpoint with name '$($Name)' does not exist" } return $null diff --git a/src/Private/Gui.ps1 b/src/Private/Gui.ps1 index 8372c273a..38265052c 100644 --- a/src/Private/Gui.ps1 +++ b/src/Private/Gui.ps1 @@ -41,7 +41,7 @@ function Start-PodeGuiRunspace { Start-Sleep -Milliseconds 200 } else { - throw ($msgTable.failedToConnectToUrlExceptionMessage -f $uri) #"Failed to connect to URL: $($uri)" + throw ($PodeLocale.failedToConnectToUrlExceptionMessage -f $uri) #"Failed to connect to URL: $($uri)" } } } diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index e05e45835..73d5d5843 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -190,7 +190,7 @@ function Get-PodeEndpointInfo { # validate that we have a valid ip/host:port address if (!(($Address -imatch "^$($cmbdRgx)$") -or ($Address -imatch "^$($hostRgx)[\:]{0,1}") -or ($Address -imatch "[\:]{0,1}$($portRgx)$"))) { - throw ($msgTable.failedToParseAddressExceptionMessage -f $Address)#"Failed to parse '$($Address)' as a valid IP/Host:Port address" + throw ($PodeLocale.failedToParseAddressExceptionMessage -f $Address)#"Failed to parse '$($Address)' as a valid IP/Host:Port address" } # grab the ip address/hostname @@ -201,7 +201,7 @@ function Get-PodeEndpointInfo { # ensure we have a valid ip address/hostname if (!(Test-PodeIPAddress -IP $_host)) { - throw ($msgTable.invalidIpAddressExceptionMessage -f $_host) #"The IP address supplied is invalid: $($_host)" + throw ($PodeLocale.invalidIpAddressExceptionMessage -f $_host) #"The IP address supplied is invalid: $($_host)" } # grab the port @@ -212,7 +212,7 @@ function Get-PodeEndpointInfo { # ensure the port is valid if ($_port -lt 0) { - throw ($msgTable.invalidPortExceptionMessage -f $_port)#"The port cannot be negative: $($_port)" + throw ($PodeLocale.invalidPortExceptionMessage -f $_port)#"The port cannot be negative: $($_port)" } # return the info @@ -873,7 +873,7 @@ function New-PodePSDrive { # if the path supplied doesn't exist, error if (!(Test-Path $Path)) { - throw ($msgTable.pathNotExistExceptionMessage -f $Path)#"Path does not exist: $($Path)" + throw ($PodeLocale.pathNotExistExceptionMessage -f $Path)#"Path does not exist: $($Path)" } # resolve the path @@ -2333,7 +2333,7 @@ function Get-PodeRelativePath { # if flagged, test the path and throw error if it doesn't exist if ($TestPath -and !(Test-PodePath $Path -NoStatus)) { - throw ($msgTable.pathNotExistExceptionMessage -f (Protect-PodeValue -Value $Path -Default $_rawPath))#"The path does not exist: $(Protect-PodeValue -Value $Path -Default $_rawPath)" + throw ($PodeLocale.pathNotExistExceptionMessage -f (Protect-PodeValue -Value $Path -Default $_rawPath))#"The path does not exist: $(Protect-PodeValue -Value $Path -Default $_rawPath)" } return $Path @@ -2379,7 +2379,7 @@ function Test-PodeIsServerless { ) if ($PodeContext.Server.IsServerless -and $ThrowError) { - throw ($msgTable.unsupportedFunctionInServerlessContextExceptionMessage -f $FunctionName) #"The $($FunctionName) function is not supported in a serverless context" + throw ($PodeLocale.unsupportedFunctionInServerlessContextExceptionMessage -f $FunctionName) #"The $($FunctionName) function is not supported in a serverless context" } if (!$ThrowError) { @@ -2512,12 +2512,12 @@ function Convert-PodeFileToScriptBlock { # if Path doesn't exist, error if (!(Test-PodePath -Path $Path -NoStatus)) { - throw ($msgTable.pathNotExistExceptionMessage -f $Path) # "The Path supplied does not exist: $($Path)" + throw ($PodeLocale.pathNotExistExceptionMessage -f $Path) # "The Path supplied does not exist: $($Path)" } # if the path is a wildcard or directory, error if (!(Test-PodePathIsFile -Path $Path -FailOnWildcard)) { - throw ($msgTable.invalidPathWildcardOrDirectoryExceptionMessage -f $Path) # "The Path supplied cannot be a wildcard or a directory: $($Path)" + throw ($PodeLocale.invalidPathWildcardOrDirectoryExceptionMessage -f $Path) # "The Path supplied cannot be a wildcard or a directory: $($Path)" } return ([scriptblock](Use-PodeScript -Path $Path)) @@ -2604,7 +2604,7 @@ function Get-PodeAstFromFile { ) if (!(Test-Path $Path)) { - throw ($msgTable.pathNotExistExceptionMessage -f $Path) # "The Path supplied does not exist: $($Path)" + throw ($PodeLocale.pathNotExistExceptionMessage -f $Path) # "The Path supplied does not exist: $($Path)" } return [System.Management.Automation.Language.Parser]::ParseFile($Path, [ref]$null, [ref]$null) @@ -2709,7 +2709,7 @@ function Read-PodeWebExceptionDetails { } default { - throw ($msgTable.invalidExceptionTypeExceptionMessage -f ($_.Exception.GetType().Name))#"Exception is of an invalid type, should be either WebException or HttpRequestException, but got: $($_.Exception.GetType().Name)" + throw ($PodeLocale.invalidExceptionTypeExceptionMessage -f ($_.Exception.GetType().Name))#"Exception is of an invalid type, should be either WebException or HttpRequestException, but got: $($_.Exception.GetType().Name)" } } @@ -2743,7 +2743,7 @@ function Use-PodeFolder { # fail if path not found if (!(Test-PodePath -Path $Path -NoStatus)) { - throw ($msgTable.pathToLoadNotFoundExceptionMessage -f $DefaultPath, $Path) #"Path to load $($DefaultPath) not found: $($Path)" + throw ($PodeLocale.pathToLoadNotFoundExceptionMessage -f $DefaultPath, $Path) #"Path to load $($DefaultPath) not found: $($Path)" } # get .ps1 files and load them @@ -2847,7 +2847,7 @@ function Set-PodeCronInterval { } if ($Value.Length -gt 1) { - throw ($msgTable.singleValueForIntervalExceptionMessage -f $Type) #"You can only supply a single $($Type) value when using intervals" + throw ($PodeLocale.singleValueForIntervalExceptionMessage -f $Type) #"You can only supply a single $($Type) value when using intervals" } if ($Value.Length -eq 1) { @@ -3315,7 +3315,7 @@ function ConvertTo-PodeYamlInternal { catch { $_ | Write-PodeErrorLog $_.Exception | Write-PodeErrorLog -CheckInnerException - throw ($msgTable.scriptErrorExceptionMessage -f $_, $_.InvocationInfo.ScriptName, $_.InvocationInfo.Line.Trim(), $_.InvocationInfo.ScriptLineNumber, $_.InvocationInfo.OffsetInLine, $_.InvocationInfo.MyCommand, $type, $InputObject, $InputObject.GetType().Name, $InputObject.GetType().BaseType.Name) + throw ($PodeLocale.scriptErrorExceptionMessage -f $_, $_.InvocationInfo.ScriptName, $_.InvocationInfo.Line.Trim(), $_.InvocationInfo.ScriptLineNumber, $_.InvocationInfo.OffsetInLine, $_.InvocationInfo.MyCommand, $type, $InputObject, $InputObject.GetType().Name, $InputObject.GetType().BaseType.Name) #"Error'$($_)' in script $($_.InvocationInfo.ScriptName) $($_.InvocationInfo.Line.Trim()) (line $($_.InvocationInfo.ScriptLineNumber)) char $($_.InvocationInfo.OffsetInLine) executing $($_.InvocationInfo.MyCommand) on $type object '$($InputObject)' Class: $($InputObject.GetType().Name) BaseClass: $($InputObject.GetType().BaseType.Name) " } } diff --git a/src/Private/Middleware.ps1 b/src/Private/Middleware.ps1 index 182f38339..99cdbb445 100644 --- a/src/Private/Middleware.ps1 +++ b/src/Private/Middleware.ps1 @@ -79,7 +79,7 @@ function New-PodeMiddlewareInternal { if (Test-PodeIsEmpty $ScriptBlock) { # No ScriptBlock supplied - throw $msgTable.noScriptBlockSuppliedExceptionMessage + throw $PodeLocale.noScriptBlockSuppliedExceptionMessage } # if route is empty, set it to root @@ -394,7 +394,7 @@ function Initialize-PodeIISMiddleware { # fail if no iis token - because there should be! if ([string]::IsNullOrWhiteSpace($PodeContext.Server.IIS.Token)) { # IIS ASPNETCORE_TOKEN is missing - throw $msgTable.iisAspnetcoreTokenMissingExceptionMessage + throw $PodeLocale.iisAspnetcoreTokenMissingExceptionMessage } # add middleware to check every request has the token diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index 69c708a92..5b5b8db02 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -43,7 +43,7 @@ function ConvertTo-PodeOAObjectSchema { # Ensure all content types are valid MIME types foreach ($type in $Content.Keys) { if ($type -inotmatch '^(application|audio|image|message|model|multipart|text|video|\*)\/[\w\.\-\*]+(;[\s]*(charset|boundary)=[\w\.\-\*]+)*$|^"\*\/\*"$') { - throw ($msgTable.invalidContentTypeForSchemaExceptionMessage -f $type) #"Invalid content-type found for schema: $($type)" + throw ($PodeLocale.invalidContentTypeForSchemaExceptionMessage -f $type) #"Invalid content-type found for schema: $($type)" } } # manage generic schema json conversion issue @@ -182,7 +182,7 @@ function ConvertTo-PodeOAObjectSchema { } else { # The Properties parameters cannot be used if the Property has no name - Throw $msgTable.propertiesParameterWithoutNameExceptionMessage + Throw $PodeLocale.propertiesParameterWithoutNameExceptionMessage } } else { @@ -375,7 +375,7 @@ function ConvertTo-PodeOASchemaProperty { if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag ) { if ($Property.type -is [string[]]) { # Multi type properties requeired OpenApi Version 3.1 or above - throw $msgTable.multiTypePropertiesRequireOpenApi31ExceptionMessage + throw $PodeLocale.multiTypePropertiesRequireOpenApi31ExceptionMessage } $schema['type'] = $Property.type.ToLower() } @@ -809,7 +809,7 @@ function Get-PodeOpenApiDefinitionInternal { if (!$Definition.Version) { # OpenApi Version property is mandatory - throw $msgTable.openApiVersionPropertyMandatoryExceptionMessage + throw $PodeLocale.openApiVersionPropertyMandatoryExceptionMessage } $localEndpoint = $null # set the openapi version @@ -866,7 +866,7 @@ function Get-PodeOpenApiDefinitionInternal { if ($Definition.webhooks.count -gt 0) { if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag) { # Webhooks feature is unsupported in OpenAPI v3.0.x - throw $msgTable.webhooksFeatureNotSupportedInOpenApi30ExceptionMessage + throw $PodeLocale.webhooksFeatureNotSupportedInOpenApi30ExceptionMessage } else { $keys = [string[]]$Definition.webhooks.Keys @@ -914,7 +914,7 @@ function Get-PodeOpenApiDefinitionInternal { if ($components.pathItems.count -gt 0) { if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag) { # Feature pathItems is unsupported in OpenAPI v3.0.x - throw $msgTable.pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage + throw $PodeLocale.pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage } else { $keys = [string[]]$components.pathItems.Keys @@ -1318,7 +1318,7 @@ function Set-PodeOAAuth { # Validate the existence of specified authentication methods foreach ($n in @($Name)) { if (!(Test-PodeAuthExists -Name $n)) { - throw ($msgTable.authenticationMethodDoesNotExistExceptionMessage -f $n) #"Authentication method does not exist: $($n)" + throw ($PodeLocale.authenticationMethodDoesNotExistExceptionMessage -f $n) #"Authentication method does not exist: $($n)" } } } @@ -1385,7 +1385,7 @@ function Set-PodeOAGlobalAuth { # Check if the specified authentication method exists if (!(Test-PodeAuthExists -Name $Name)) { - throw ($msgTable.authenticationMethodDoesNotExistExceptionMessage -f $Name) #"Authentication method does not exist: $($Name)" + throw ($PodeLocale.authenticationMethodDoesNotExistExceptionMessage -f $Name) #"Authentication method does not exist: $($Name)" } # Iterate over each definition tag to apply the authentication method @@ -1463,7 +1463,7 @@ function Resolve-PodeOAReference { } else { # Unsupported object - throw $msgTable.unsupportedObjectExceptionMessage + throw $PodeLocale.unsupportedObjectExceptionMessage } } } @@ -1479,11 +1479,11 @@ function Resolve-PodeOAReference { } elseif ($key -ieq 'oneof') { # Validation of schema with oneof is not supported - throw $msgTable.validationOfOneOfSchemaNotSupportedExceptionMessage + throw $PodeLocale.validationOfOneOfSchemaNotSupportedExceptionMessage } elseif ($key -ieq 'anyof') { # Validation of schema with anyof is not supported - throw $msgTable.validationOfAnyOfSchemaNotSupportedExceptionMessage + throw $PodeLocale.validationOfAnyOfSchemaNotSupportedExceptionMessage } } elseif ($ComponentSchema.properties[$key].type -eq 'object') { @@ -1566,7 +1566,7 @@ function New-PodeOAPropertyInternal { } else { # Cannot create the property no type is defined - throw $msgTable.cannotCreatePropertyWithoutTypeExceptionMessage + throw $PodeLocale.cannotCreatePropertyWithoutTypeExceptionMessage } } @@ -1649,7 +1649,7 @@ function New-PodeOAPropertyInternal { if ($Params.NoAdditionalProperties.IsPresent -and $Params.AdditionalProperties) { # Params -NoAdditionalProperties and -AdditionalProperties are mutually exclusive - throw $msgTable.paramsNoAdditionalPropertiesExclusiveExceptionMessage + throw $PodeLocale.paramsNoAdditionalPropertiesExclusiveExceptionMessage } else { if ($Params.NoAdditionalProperties.IsPresent) { $param.additionalProperties = $false } @@ -1710,7 +1710,7 @@ function ConvertTo-PodeOAHeaderProperty { } else { # Header requires a name when used in an encoding context - throw $msgTable.headerMustHaveNameInEncodingContextExceptionMessage + throw $PodeLocale.headerMustHaveNameInEncodingContextExceptionMessage } } @@ -1826,7 +1826,7 @@ function New-PodeOResponseInternal { } else { # A Description is required - throw $msgTable.descriptionRequiredExceptionMessage + throw $PodeLocale.descriptionRequiredExceptionMessage } } else { @@ -1997,7 +1997,7 @@ function Test-PodeOADefinitionInternal { # Throw an error indicating non-compliance with OpenAPI standards # OpenAPI document compliance issues - throw $msgTable.openApiDocumentNotCompliantExceptionMessage + throw $PodeLocale.openApiDocumentNotCompliantExceptionMessage } } @@ -2069,7 +2069,7 @@ function Test-PodeOAComponentInternal { if (!($PodeContext.Server.OpenAPI.Definitions[$tag].components[$field].keys -ccontains $Name)) { # If $Name is not found in the current $tag, return $false or throw an exception if ($ThrowException.IsPresent ) { - throw ($msgTable.noComponentInDefinitionExceptionMessage -f $field, $Name, $tag) #"No component of type $field named $Name is available in the $tag definition." + throw ($PodeLocale.noComponentInDefinitionExceptionMessage -f $field, $Name, $tag) #"No component of type $field named $Name is available in the $tag definition." } else { return $false diff --git a/src/Private/Routes.ps1 b/src/Private/Routes.ps1 index af7008fde..73605d0bb 100644 --- a/src/Private/Routes.ps1 +++ b/src/Private/Routes.ps1 @@ -504,10 +504,10 @@ function Test-PodeRouteInternal { } if ([string]::IsNullOrEmpty($_url)) { - throw ($msgTable.methodPathAlreadyDefinedExceptionMessage -f $Method, $Path) #"[$($Method)] $($Path): Already defined" + throw ($PodeLocale.methodPathAlreadyDefinedExceptionMessage -f $Method, $Path) #"[$($Method)] $($Path): Already defined" } - throw ($msgTable.methodPathAlreadyDefinedForUrlExceptionMessage -f $Method, $Path, $_url) #"[$($Method)] $($Path): Already defined for $($_url)" + throw ($PodeLocale.methodPathAlreadyDefinedForUrlExceptionMessage -f $Method, $Path, $_url) #"[$($Method)] $($Path): Already defined for $($_url)" } function Convert-PodeFunctionVerbToHttpMethod { @@ -652,19 +652,19 @@ function ConvertTo-PodeMiddleware { # check middleware is a type valid if (($mid -isnot [scriptblock]) -and ($mid -isnot [hashtable])) { - throw ($msgTable.invalidMiddlewareTypeExceptionMessage -f $mid.GetType().Name)#"One of the Middlewares supplied is an invalid type. Expected either a ScriptBlock or Hashtable, but got: $($mid.GetType().Name)" + throw ($PodeLocale.invalidMiddlewareTypeExceptionMessage -f $mid.GetType().Name)#"One of the Middlewares supplied is an invalid type. Expected either a ScriptBlock or Hashtable, but got: $($mid.GetType().Name)" } # if middleware is hashtable, ensure the keys are valid (logic is a scriptblock) if ($mid -is [hashtable]) { if ($null -eq $mid.Logic) { # A Hashtable Middleware supplied has no Logic defined - throw $msgTable.hashtableMiddlewareNoLogicExceptionMessage + throw $PodeLocale.hashtableMiddlewareNoLogicExceptionMessage } if ($mid.Logic -isnot [scriptblock]) { # A Hashtable Middleware supplied has an invalid Logic type. Expected ScriptBlock, but got: {0} - throw ($msgTable.invalidLogicTypeInHashtableMiddlewareExceptionMessage -f $mid.Logic.GetType().Name) + throw ($PodeLocale.invalidLogicTypeInHashtableMiddlewareExceptionMessage -f $mid.Logic.GetType().Name) } } } diff --git a/src/Private/ScopedVariables.ps1 b/src/Private/ScopedVariables.ps1 index c0ee77e94..9fc37ba81 100644 --- a/src/Private/ScopedVariables.ps1 +++ b/src/Private/ScopedVariables.ps1 @@ -27,7 +27,7 @@ function Add-PodeScopedVariableInternal { # check if var already defined if (Test-PodeScopedVariable -Name $Name) { - throw ($msgTable.scopedVariableAlreadyDefinedExceptionMessage -f $Name)#"Scoped Variable already defined: $($Name)" + throw ($PodeLocale.scopedVariableAlreadyDefinedExceptionMessage -f $Name)#"Scoped Variable already defined: $($Name)" } # add scoped var definition @@ -169,7 +169,7 @@ function Find-PodeScopedVariableUsingVariableValues { } if ([string]::IsNullOrEmpty($value)) { - throw ($msgTable.valueForUsingVariableNotFoundExceptionMessage -f $varName) #"Value for `$using:$($varName) could not be found" + throw ($PodeLocale.valueForUsingVariableNotFoundExceptionMessage -f $varName) #"Value for `$using:$($varName) could not be found" } # add to mapped diff --git a/src/Private/Secrets.ps1 b/src/Private/Secrets.ps1 index 7fa49851c..1be53e74f 100644 --- a/src/Private/Secrets.ps1 +++ b/src/Private/Secrets.ps1 @@ -46,7 +46,7 @@ function Register-PodeSecretManagementVault { if ($isSecretStore) { if ([string]::IsNullOrEmpty($VaultConfig.Unlock.Secret)) { # An 'UnlockSecret' is required when using Microsoft.PowerShell.SecretStore - throw $msgTable.unlockSecretRequiredExceptionMessage + throw $PodeLocale.unlockSecretRequiredExceptionMessage } } @@ -147,7 +147,7 @@ function Register-PodeSecretCustomVault { # unlock secret with no script? if ($VaultConfig.Unlock.Enabled -and (Test-PodeIsEmpty $UnlockScriptBlock)) { # Unlock secret supplied for custom Secret Vault type, but not Unlock ScriptBlock supplied - throw $msgTable.unlockSecretButNoScriptBlockExceptionMessage + throw $PodeLocale.unlockSecretButNoScriptBlockExceptionMessage } # all is good, so set the config @@ -197,7 +197,7 @@ function Unlock-PodeSecretCustomVault { # do we have an unlock scriptblock if ($null -eq $VaultConfig.Custom.Unlock) { - throw ($msgTable.noUnlockScriptBlockForVaultExceptionMessage -f $VaultConfig.Name) #"No Unlock ScriptBlock supplied for unlocking the vault '$($VaultConfig.Name)'" + throw ($PodeLocale.noUnlockScriptBlockForVaultExceptionMessage -f $VaultConfig.Name) #"No Unlock ScriptBlock supplied for unlocking the vault '$($VaultConfig.Name)'" } # unlock the vault, and get back an expiry @@ -354,7 +354,7 @@ function Set-PodeSecretCustomKey { # do we have a set scriptblock? if ($null -eq $_vault.Custom.Set) { - throw ($msgTable.noSetScriptBlockForVaultExceptionMessage -f $_vault.Name) #"No Set ScriptBlock supplied for updating/creating secrets in the vault '$($_vault.Name)'" + throw ($PodeLocale.noSetScriptBlockForVaultExceptionMessage -f $_vault.Name) #"No Set ScriptBlock supplied for updating/creating secrets in the vault '$($_vault.Name)'" } # set the secret @@ -404,7 +404,7 @@ function Remove-PodeSecretCustomKey { # do we have a remove scriptblock? if ($null -eq $_vault.Custom.Remove) { - throw ($msgTable.noRemoveScriptBlockForVaultExceptionMessage -f $_vault.Name) #"No Remove ScriptBlock supplied for removing secrets from the vault '$($_vault.Name)'" + throw ($PodeLocale.noRemoveScriptBlockForVaultExceptionMessage -f $_vault.Name) #"No Remove ScriptBlock supplied for removing secrets from the vault '$($_vault.Name)'" } # remove the secret @@ -507,7 +507,7 @@ function Protect-PodeSecretValueType { ($Value -is [pscredential]) -or ($Value -is [System.Management.Automation.OrderedHashtable]) )) { - throw ($msgTable.invalidSecretValueTypeExceptionMessage -f $Value.GetType().Name) #"Value to set secret to is of an invalid type. Expected either String, SecureString, HashTable, Byte[], or PSCredential. But got: $($Value.GetType().Name)" + throw ($PodeLocale.invalidSecretValueTypeExceptionMessage -f $Value.GetType().Name) #"Value to set secret to is of an invalid type. Expected either String, SecureString, HashTable, Byte[], or PSCredential. But got: $($Value.GetType().Name)" } return $Value diff --git a/src/Private/Security.ps1 b/src/Private/Security.ps1 index bd74f585d..12b8f37e3 100644 --- a/src/Private/Security.ps1 +++ b/src/Private/Security.ps1 @@ -348,11 +348,11 @@ function Add-PodeIPLimit { # ensure limit and seconds are non-zero and negative if ($Limit -le 0) { - throw ($msgTable.limitValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Limit value cannot be 0 or less for $($IP)" + throw ($PodeLocale.limitValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Limit value cannot be 0 or less for $($IP)" } if ($Seconds -le 0) { - throw ($msgTable.secondsValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Seconds value cannot be 0 or less for $($IP)" + throw ($PodeLocale.secondsValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Seconds value cannot be 0 or less for $($IP)" } # get current rules @@ -426,11 +426,11 @@ function Add-PodeRouteLimit { # ensure limit and seconds are non-zero and negative if ($Limit -le 0) { - throw ($msgTable.limitValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Limit value cannot be 0 or less for $($IP)" + throw ($PodeLocale.limitValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Limit value cannot be 0 or less for $($IP)" } if ($Seconds -le 0) { - throw ($msgTable.secondsValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Seconds value cannot be 0 or less for $($IP)" + throw ($PodeLocale.secondsValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Seconds value cannot be 0 or less for $($IP)" } # get current rules @@ -482,16 +482,16 @@ function Add-PodeEndpointLimit { # does the endpoint exist? $endpoint = Get-PodeEndpointByName -Name $EndpointName if ($null -eq $endpoint) { - throw ($msgTable.endpointNameNotExistExceptionMessage -f $EndpointName) #"Endpoint not found: $($EndpointName)" + throw ($PodeLocale.endpointNameNotExistExceptionMessage -f $EndpointName) #"Endpoint not found: $($EndpointName)" } # ensure limit and seconds are non-zero and negative if ($Limit -le 0) { - throw ($msgTable.limitValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Limit value cannot be 0 or less for $($IP)" + throw ($PodeLocale.limitValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Limit value cannot be 0 or less for $($IP)" } if ($Seconds -le 0) { - throw ($msgTable.secondsValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Seconds value cannot be 0 or less for $($IP)" + throw ($PodeLocale.secondsValueCannotBeZeroOrLessExceptionMessage -f $IP) #"Seconds value cannot be 0 or less for $($IP)" } # get current rules @@ -816,7 +816,7 @@ function Get-PodeCertificateByPemFile { $result = openssl pkcs12 -inkey $keyPath -in $certPath -export -passin pass:$Password -password pass:$Password -out $tempFile if (!$?) { - throw ($msgTable.failedToCreateOpenSslCertExceptionMessage -f $result) #"Failed to create openssl cert: $($result)" + throw ($PodeLocale.failedToCreateOpenSslCertExceptionMessage -f $result) #"Failed to create openssl cert: $($result)" } $cert = [X509Certificates.X509Certificate2]::new($tempFile, $Password) @@ -851,7 +851,7 @@ function Find-PodeCertificateInCertStore { # fail if not windows if (!(Test-PodeIsWindows)) { # Certificate Thumbprints/Name are only supported on Windows - throw $msgTable.certificateThumbprintsNameSupportedOnWindowsExceptionMessage + throw $PodeLocale.certificateThumbprintsNameSupportedOnWindowsExceptionMessage } # open the currentuser\my store @@ -871,7 +871,7 @@ function Find-PodeCertificateInCertStore { # fail if no cert found for query if (($null -eq $x509certs) -or ($x509certs.Count -eq 0)) { - throw ($msgTable.noCertificateFoundExceptionMessage -f $StoreLocation, $StoreName, $Query) # "No certificate could be found in $($StoreLocation)\$($StoreName) for '$($Query)'" + throw ($PodeLocale.noCertificateFoundExceptionMessage -f $StoreLocation, $StoreName, $Query) # "No certificate could be found in $($StoreLocation)\$($StoreName) for '$($Query)'" } return ([X509Certificates.X509Certificate2]($x509certs[0])) diff --git a/src/Private/Server.ps1 b/src/Private/Server.ps1 index bdad25560..64bc085b3 100644 --- a/src/Private/Server.ps1 +++ b/src/Private/Server.ps1 @@ -136,7 +136,7 @@ function Start-PodeInternalServer { # errored? if ($PodeContext.RunspacePools[$pool].State -ieq 'error') { - throw ($msgTable.runspacePoolFailedToLoadExceptionMessage -f $pool) #"$($pool) RunspacePool failed to load" + throw ($PodeLocale.runspacePoolFailedToLoadExceptionMessage -f $pool) #"$($pool) RunspacePool failed to load" } } } diff --git a/src/Private/ServiceServer.ps1 b/src/Private/ServiceServer.ps1 index d0058d83c..892aa526a 100644 --- a/src/Private/ServiceServer.ps1 +++ b/src/Private/ServiceServer.ps1 @@ -2,7 +2,7 @@ function Start-PodeServiceServer { # ensure we have service handlers if (Test-PodeIsEmpty (Get-PodeHandler -Type Service)) { # No Service handlers have been defined - throw $msgTable.noServiceHandlersDefinedExceptionMessage + throw $PodeLocale.noServiceHandlersDefinedExceptionMessage } # state we're running diff --git a/src/Private/Sessions.ps1 b/src/Private/Sessions.ps1 index 496ed1820..1a5215f0d 100644 --- a/src/Private/Sessions.ps1 +++ b/src/Private/Sessions.ps1 @@ -41,7 +41,7 @@ function Get-PodeSessionFullId { function Set-PodeSession { if ($null -eq $WebEvent.Session) { # There is no session available to set on the response - throw $msgTable.noSessionToSetOnResponseExceptionMessage + throw $PodeLocale.noSessionToSetOnResponseExceptionMessage } # convert secret to strict mode @@ -139,7 +139,7 @@ function Revoke-PodeSession { function Set-PodeSessionDataHash { if ($null -eq $WebEvent.Session) { # No session available to calculate data hash - throw $msgTable.noSessionToCalculateDataHashExceptionMessage + throw $PodeLocale.noSessionToCalculateDataHashExceptionMessage } if (($null -eq $WebEvent.Session.Data) -or ($WebEvent.Session.Data.Count -eq 0)) { diff --git a/src/Private/Setup.ps1 b/src/Private/Setup.ps1 index 9756736de..256f92a20 100644 --- a/src/Private/Setup.ps1 +++ b/src/Private/Setup.ps1 @@ -60,7 +60,7 @@ function Install-PodeLocalModules { } catch { Write-Host 'Failed' -ForegroundColor Red - throw ($msgTable.moduleOrVersionNotFoundExceptionMessage -f $_repository, $_name, $_version) #"Module or version not found on $($_repository): $($_name)@$($_version)" + throw ($PodeLocale.moduleOrVersionNotFoundExceptionMessage -f $_repository, $_name, $_version) #"Module or version not found on $($_repository): $($_name)@$($_version)" } } } \ No newline at end of file diff --git a/src/Private/SmtpServer.ps1 b/src/Private/SmtpServer.ps1 index 43f7d702b..315eaef37 100644 --- a/src/Private/SmtpServer.ps1 +++ b/src/Private/SmtpServer.ps1 @@ -4,7 +4,7 @@ function Start-PodeSmtpServer { # ensure we have smtp handlers if (Test-PodeIsEmpty (Get-PodeHandler -Type Smtp)) { # No SMTP handlers have been defined - throw $msgTable.noSmtpHandlersDefinedExceptionMessage + throw $PodeLocale.noSmtpHandlersDefinedExceptionMessage } # work out which endpoints to listen on diff --git a/src/Private/Tasks.ps1 b/src/Private/Tasks.ps1 index 88b4d090c..1a4c1f7d2 100644 --- a/src/Private/Tasks.ps1 +++ b/src/Private/Tasks.ps1 @@ -168,7 +168,7 @@ function Wait-PodeNetTaskInternal { # if the main task isnt complete, it timed out if (($null -ne $timeoutTask) -and (!$Task.IsCompleted)) { - throw [System.TimeoutException]::new($msgTable.taskTimedOutExceptionMessage -f $Timeout) #"Task has timed out after $($Timeout)ms") + throw [System.TimeoutException]::new($PodeLocale.taskTimedOutExceptionMessage -f $Timeout) #"Task has timed out after $($Timeout)ms") } # only return a value if the result has one diff --git a/src/Private/Verbs.ps1 b/src/Private/Verbs.ps1 index 7ace07a1d..67095e0ee 100644 --- a/src/Private/Verbs.ps1 +++ b/src/Private/Verbs.ps1 @@ -117,9 +117,9 @@ function Test-PodeVerbAndError { } if ([string]::IsNullOrEmpty($_url)) { - throw ($msgTable.verbAlreadyDefinedExceptionMessage -f $Verb) #"[Verb] $($Verb): Already defined" + throw ($PodeLocale.verbAlreadyDefinedExceptionMessage -f $Verb) #"[Verb] $($Verb): Already defined" } else { - throw ($msgTable.verbAlreadyDefinedForUrlExceptionMessage -f $Verb, $_url) # "[Verb] $($Verb): Already defined for $($_url)" + throw ($PodeLocale.verbAlreadyDefinedForUrlExceptionMessage -f $Verb, $_url) # "[Verb] $($Verb): Already defined for $($_url)" } } \ No newline at end of file diff --git a/src/Public/Access.ps1 b/src/Public/Access.ps1 index 2e942aa29..c6394f7b4 100644 --- a/src/Public/Access.ps1 +++ b/src/Public/Access.ps1 @@ -70,7 +70,7 @@ function New-PodeAccessScheme { if ($Custom) { if ([string]::IsNullOrWhiteSpace($Path) -and (Test-PodeIsEmpty $ScriptBlock)) { # A Path or ScriptBlock is required for sourcing the Custom access values - throw $msgTable.pathOrScriptBlockRequiredExceptionMessage + throw $PodeLocale.pathOrScriptBlockRequiredExceptionMessage } } @@ -175,7 +175,7 @@ function Add-PodeAccess { # check name unique if (Test-PodeAccessExists -Name $Name) { - throw ($msgTable.accessMethodAlreadyDefinedExceptionMessage -f $Name) #"Access method already defined: $($Name)" + throw ($PodeLocale.accessMethodAlreadyDefinedExceptionMessage -f $Name) #"Access method already defined: $($Name)" } # parse using variables in validator scriptblock @@ -242,13 +242,13 @@ function Merge-PodeAccess { # ensure the name doesn't already exist if (Test-PodeAccessExists -Name $Name) { - throw ($msgTable.accessMethodAlreadyDefinedExceptionMessage -f $Name) #"Access method already defined: $($Name)" + throw ($PodeLocale.accessMethodAlreadyDefinedExceptionMessage -f $Name) #"Access method already defined: $($Name)" } # ensure all the access methods exist foreach ($accName in $Access) { if (!(Test-PodeAccessExists -Name $accName)) { - throw ($msgTable.accessMethodNotExistForMergingExceptionMessage -f $accName) #"Access method does not exist for merging: $($accName)" + throw ($PodeLocale.accessMethodNotExistForMergingExceptionMessage -f $accName) #"Access method does not exist for merging: $($accName)" } } @@ -314,7 +314,7 @@ function Add-PodeAccessCustom { end { foreach ($r in $routes) { if ($r.AccessMeta.Custom.ContainsKey($Name)) { - throw ($msgTable.routeAlreadyContainsCustomAccessExceptionMessage -f $r.Method, $r.Path, $Name) #"Route '[$($r.Method)] $($r.Path)' already contains Custom Access with name '$($Name)'" + throw ($PodeLocale.routeAlreadyContainsCustomAccessExceptionMessage -f $r.Method, $r.Path, $Name) #"Route '[$($r.Method)] $($r.Path)' already contains Custom Access with name '$($Name)'" } $r.AccessMeta.Custom[$Name] = $Value @@ -664,7 +664,7 @@ function Add-PodeAccessMiddleware { ) if (!(Test-PodeAccessExists -Name $Access)) { - throw ($msgTable.accessMethodNotExistExceptionMessage -f $Access) #"Access method does not exist: $($Access)" + throw ($PodeLocale.accessMethodNotExistExceptionMessage -f $Access) #"Access method does not exist: $($Access)" } Get-PodeAccessMiddlewareScript | diff --git a/src/Public/Authentication.ps1 b/src/Public/Authentication.ps1 index fdfa0f8af..8c2759031 100644 --- a/src/Public/Authentication.ps1 +++ b/src/Public/Authentication.ps1 @@ -160,7 +160,7 @@ function New-PodeAuthScheme { [ValidateScript({ if (Test-PodeIsEmpty $_) { # A non-empty ScriptBlock is required for the Custom authentication scheme - throw $msgTable.nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage + throw $PodeLocale.nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage } return $true @@ -410,22 +410,22 @@ function New-PodeAuthScheme { 'oauth2' { if (($null -ne $InnerScheme) -and ($InnerScheme.Name -inotin @('basic', 'form'))) { # OAuth2 InnerScheme can only be one of either Basic or Form authentication, but got: {0} - throw ($msgTable.oauth2InnerSchemeInvalidExceptionMessage -f $InnerScheme.Name) + throw ($PodeLocale.oauth2InnerSchemeInvalidExceptionMessage -f $InnerScheme.Name) } if (($null -eq $InnerScheme) -and [string]::IsNullOrWhiteSpace($AuthoriseUrl)) { #OAuth2 requires an Authorise URL to be supplied - throw $msgTable.oauth2RequiresAuthorizeUrlExceptionMessage + throw $PodeLocale.oauth2RequiresAuthorizeUrlExceptionMessage } if ($UsePKCE -and !(Test-PodeSessionsEnabled)) { # Sessions are required to use OAuth2 with PKCE - throw $msgTable.sessionsRequiredForOAuth2WithPKCEExceptionMessage + throw $PodeLocale.sessionsRequiredForOAuth2WithPKCEExceptionMessage } if (!$UsePKCE -and [string]::IsNullOrEmpty($ClientSecret)) { # OAuth2 requires a Client Secret when not using PKCE - throw $msgTable.oauth2ClientSecretRequiredExceptionMessage + throw $PodeLocale.oauth2ClientSecretRequiredExceptionMessage } return @{ Name = 'OAuth2' @@ -723,7 +723,7 @@ function Add-PodeAuth { [ValidateScript({ if (Test-PodeIsEmpty $_) { # A non-empty ScriptBlock is required for the authentication method - throw $msgTable.nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage + throw $PodeLocale.nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage } return $true @@ -757,19 +757,19 @@ function Add-PodeAuth { # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { # Authentication method already defined: {0} - throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) + throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) } # ensure the Scheme contains a scriptblock if (Test-PodeIsEmpty $Scheme.ScriptBlock) { # The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock - throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) + throw ($PodeLocale.schemeRequiresValidScriptBlockExceptionMessage -f $Name) } # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { # Sessions are required to use session persistent authentication - throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage + throw $PodeLocale.sessionsRequiredForSessionPersistentAuthExceptionMessage } # check for scoped vars @@ -912,24 +912,24 @@ function Merge-PodeAuth { # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { # Authentication method already defined: { 0 } - throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) + throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) } # ensure all the auth methods exist foreach ($authName in $Authentication) { if (!(Test-PodeAuthExists -Name $authName)) { - throw ($msgTable.authMethodNotExistForMergingExceptionMessage -f $authName) #"Authentication method does not exist for merging: $($authName)" + throw ($PodeLocale.authMethodNotExistForMergingExceptionMessage -f $authName) #"Authentication method does not exist for merging: $($authName)" } } # ensure the merge default is in the auth list if (![string]::IsNullOrEmpty($MergeDefault) -and ($MergeDefault -inotin @($Authentication))) { - throw ($msgTable.mergeDefaultAuthNotInListExceptionMessage -f $MergeDefault) # "the MergeDefault Authentication '$($MergeDefault)' is not in the Authentication list supplied" + throw ($PodeLocale.mergeDefaultAuthNotInListExceptionMessage -f $MergeDefault) # "the MergeDefault Authentication '$($MergeDefault)' is not in the Authentication list supplied" } # ensure the default is in the auth list if (![string]::IsNullOrEmpty($Default) -and ($Default -inotin @($Authentication))) { - throw ($msgTable.defaultAuthNotInListExceptionMessage -f $Default) # "the Default Authentication '$($Default)' is not in the Authentication list supplied" + throw ($PodeLocale.defaultAuthNotInListExceptionMessage -f $Default) # "the Default Authentication '$($Default)' is not in the Authentication list supplied" } # set default @@ -948,7 +948,7 @@ function Merge-PodeAuth { # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { # Sessions are required to use session persistent authentication - throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage + throw $PodeLocale.sessionsRequiredForSessionPersistentAuthExceptionMessage } # check failure url from default @@ -975,7 +975,7 @@ function Merge-PodeAuth { if (($Valid -ieq 'all') -and [string]::IsNullOrEmpty($MergeDefault)) { if ($null -eq $ScriptBlock) { # A Scriptblock for merging multiple authenticated users into 1 object is required When Valid is All - throw $msgTable.scriptBlockRequiredForMergingUsersExceptionMessage + throw $PodeLocale.scriptBlockRequiredForMergingUsersExceptionMessage } $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState @@ -1040,7 +1040,7 @@ function Get-PodeAuth { # ensure the name exists if (!(Test-PodeAuthExists -Name $Name)) { - throw ($msgTable.authenticationMethodDoesNotExistExceptionMessage -f $Name) # "Authentication method not defined: $($Name)" + throw ($PodeLocale.authenticationMethodDoesNotExistExceptionMessage -f $Name) # "Authentication method not defined: $($Name)" } # get auth method @@ -1277,19 +1277,19 @@ function Add-PodeAuthWindowsAd { # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { # Authentication method already defined: {0} - throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) + throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) } # ensure the Scheme contains a scriptblock if (Test-PodeIsEmpty $Scheme.ScriptBlock) { # The supplied Scheme for the '$($Name)' Windows AD authentication validator requires a valid ScriptBlock - throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) + throw ($PodeLocale.schemeRequiresValidScriptBlockExceptionMessage -f $Name) } # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { # Sessions are required to use session persistent authentication - throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage + throw $PodeLocale.sessionsRequiredForSessionPersistentAuthExceptionMessage } # if AD module set, ensure we're on windows and the module is available, then import/export it @@ -1303,7 +1303,7 @@ function Add-PodeAuthWindowsAd { if ([string]::IsNullOrWhiteSpace($Fqdn)) { # No domain server name has been supplied for Windows AD authentication - throw $msgTable.noDomainServerNameForWindowsAdAuthExceptionMessage + throw $PodeLocale.noDomainServerNameForWindowsAdAuthExceptionMessage } } @@ -1417,13 +1417,13 @@ function Add-PodeAuthSession { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { # Sessions have not been configured - throw $msgTable.sessionsNotConfiguredExceptionMessage + throw $PodeLocale.sessionsNotConfiguredExceptionMessage } # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { # Authentication method already defined: { 0 } - throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) + throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) } # if we have a scriptblock, deal with using vars @@ -1577,7 +1577,7 @@ function Add-PodeAuthMiddleware { $DefinitionTag = Test-PodeOADefinitionTag -Tag $OADefinitionTag if (!(Test-PodeAuthExists -Name $Authentication)) { - throw ($msgTable.authenticationMethodDoesNotExistExceptionMessage -f $Authentication) # "Authentication method does not exist: $($Authentication)" + throw ($PodeLocale.authenticationMethodDoesNotExistExceptionMessage -f $Authentication) # "Authentication method does not exist: $($Authentication)" } Get-PodeAuthMiddlewareScript | @@ -1704,13 +1704,13 @@ function Add-PodeAuthIIS { # ensure we're on Windows! if (!(Test-PodeIsWindows)) { # IIS Authentication support is for Windows only - throw $msgTable.iisAuthSupportIsForWindowsOnlyExceptionMessage + throw $PodeLocale.iisAuthSupportIsForWindowsOnlyExceptionMessage } # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { # Authentication method already defined: {0} - throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) + throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) } # if AD module set, ensure we're on windows and the module is available, then import/export it @@ -1869,19 +1869,19 @@ function Add-PodeAuthUserFile { # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { # Authentication method already defined: {0} - throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) + throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) } # ensure the Scheme contains a scriptblock if (Test-PodeIsEmpty $Scheme.ScriptBlock) { # The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock. - throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) + throw ($PodeLocale.schemeRequiresValidScriptBlockExceptionMessage -f $Name) } # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { # Sessions are required to use session persistent authentication - throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage + throw $PodeLocale.sessionsRequiredForSessionPersistentAuthExceptionMessage } # set the file path if not passed @@ -1895,7 +1895,7 @@ function Add-PodeAuthUserFile { # ensure the user file exists if (!(Test-PodePath -Path $FilePath -NoStatus -FailOnDirectory)) { # The user file does not exist: {0} - throw ($msgTable.userFileDoesNotExistExceptionMessage -f $FilePath) + throw ($PodeLocale.userFileDoesNotExistExceptionMessage -f $FilePath) } # if we have a scriptblock, deal with using vars @@ -2031,25 +2031,25 @@ function Add-PodeAuthWindowsLocal { # ensure we're on Windows! if (!(Test-PodeIsWindows)) { # Windows Local Authentication support is for Windows only - throw $msgTable.windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage + throw $PodeLocale.windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage } # ensure the name doesn't already exist if (Test-PodeAuthExists -Name $Name) { # Authentication method already defined: {0} - throw ($msgTable.authMethodAlreadyDefinedExceptionMessage -f $Name) + throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) } # ensure the Scheme contains a scriptblock if (Test-PodeIsEmpty $Scheme.ScriptBlock) { # The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock. - throw ($msgTable.schemeRequiresValidScriptBlockExceptionMessage -f $Name) + throw ($PodeLocale.schemeRequiresValidScriptBlockExceptionMessage -f $Name) } # if we're using sessions, ensure sessions have been setup if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { # Sessions are required to use session persistent authentication - throw $msgTable.sessionsRequiredForSessionPersistentAuthExceptionMessage + throw $PodeLocale.sessionsRequiredForSessionPersistentAuthExceptionMessage } # if we have a scriptblock, deal with using vars @@ -2126,7 +2126,7 @@ function ConvertTo-PodeJwt { # validate header if ([string]::IsNullOrWhiteSpace($Header.alg)) { # No algorithm supplied in JWT Header - throw $msgTable.noAlgorithmInJwtHeaderExceptionMessage + throw $PodeLocale.noAlgorithmInJwtHeaderExceptionMessage } # convert the header @@ -2191,14 +2191,14 @@ function ConvertFrom-PodeJwt { # check number of parts (should be 3) if ($parts.Length -ne 3) { # Invalid JWT supplied - throw $msgTable.invalidJwtSuppliedExceptionMessage + throw $PodeLocale.invalidJwtSuppliedExceptionMessage } # convert to header $header = ConvertFrom-PodeJwtBase64Value -Value $parts[0] if ([string]::IsNullOrWhiteSpace($header.alg)) { # Invalid JWT header algorithm supplied - throw $msgTable.invalidJwtHeaderAlgorithmSuppliedExceptionMessage + throw $PodeLocale.invalidJwtHeaderAlgorithmSuppliedExceptionMessage } # convert to payload @@ -2216,17 +2216,17 @@ function ConvertFrom-PodeJwt { if ([string]::IsNullOrWhiteSpace($signature) -and !$isNoneAlg) { # No JWT signature supplied for {0} - throw ($msgTable.noJwtSignatureForAlgorithmExceptionMessage -f $header.alg) + throw ($PodeLocale.noJwtSignatureForAlgorithmExceptionMessage -f $header.alg) } if (![string]::IsNullOrWhiteSpace($signature) -and $isNoneAlg) { # Expected no JWT signature to be supplied - throw $msgTable.expectedNoJwtSignatureSuppliedExceptionMessage + throw $PodeLocale.expectedNoJwtSignatureSuppliedExceptionMessage } if ($isNoneAlg -and ($null -ne $Secret) -and ($Secret.Length -gt 0)) { # Expected no JWT signature to be supplied - throw $msgTable.expectedNoJwtSignatureSuppliedExceptionMessage + throw $PodeLocale.expectedNoJwtSignatureSuppliedExceptionMessage } if ($isNoneAlg) { @@ -2243,7 +2243,7 @@ function ConvertFrom-PodeJwt { if ($sig -ne $parts[2]) { # Invalid JWT signature supplied - throw $msgTable.invalidJwtSignatureSuppliedExceptionMessage + throw $PodeLocale.invalidJwtSignatureSuppliedExceptionMessage } # it's valid return the payload! @@ -2283,7 +2283,7 @@ function Test-PodeJwt { if (![string]::IsNullOrWhiteSpace($Payload.exp)) { if ($now -gt $unixStart.AddSeconds($Payload.exp)) { # The JWT has expired - throw $msgTable.jwtExpiredExceptionMessage + throw $PodeLocale.jwtExpiredExceptionMessage } } @@ -2291,7 +2291,7 @@ function Test-PodeJwt { if (![string]::IsNullOrWhiteSpace($Payload.nbf)) { if ($now -lt $unixStart.AddSeconds($Payload.nbf)) { # The JWT is not yet valid for use - throw $msgTable.jwtNotYetValidExceptionMessage + throw $PodeLocale.jwtNotYetValidExceptionMessage } } } @@ -2405,13 +2405,13 @@ function ConvertFrom-PodeOIDCDiscovery { # check it supports the code response_type if ($config.response_types_supported -inotcontains 'code') { # The OAuth2 provider does not support the 'code' response_type - throw $msgTable.oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage + throw $PodeLocale.oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage } # can we have an InnerScheme? if (($null -ne $InnerScheme) -and ($config.grant_types_supported -inotcontains 'password')) { # The OAuth2 provider does not support the 'password' grant_type required by using an InnerScheme - throw $msgTable.oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage + throw $PodeLocale.oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage } # scopes diff --git a/src/Public/AutoImport.ps1 b/src/Public/AutoImport.ps1 index ee8c965f5..86bb129c7 100644 --- a/src/Public/AutoImport.ps1 +++ b/src/Public/AutoImport.ps1 @@ -47,7 +47,7 @@ function Export-PodeSnapin { # if non-windows or core, fail if ((Test-PodeIsPSCore) -or (Test-PodeIsUnix)) { # Snapins are only supported on Windows PowerShell - throw $msgTable.snapinsSupportedOnWindowsPowershellOnlyExceptionMessage + throw $PodeLocale.snapinsSupportedOnWindowsPowershellOnlyExceptionMessage } $PodeContext.Server.AutoImport.Snapins.ExportList += @($Name) diff --git a/src/Public/Core.ps1 b/src/Public/Core.ps1 index 3c99f339e..304b3f6f4 100644 --- a/src/Public/Core.ps1 +++ b/src/Public/Core.ps1 @@ -643,7 +643,7 @@ function Show-PodeGui { # only valid for Windows PowerShell if ((Test-PodeIsPSCore) -and ($PSVersionTable.PSVersion.Major -eq 6)) { # Show-PodeGui is currently only available for Windows PowerShell and PowerShell 7+ on Windows - throw $msgTable.showPodeGuiOnlyAvailableOnWindowsExceptionMessage + throw $PodeLocale.showPodeGuiOnlyAvailableOnWindowsExceptionMessage } # enable the gui and set general settings @@ -904,7 +904,7 @@ function Add-PodeEndpoint { # if RedirectTo is supplied, then a Name is mandatory if (![string]::IsNullOrWhiteSpace($RedirectTo) -and [string]::IsNullOrWhiteSpace($Name)) { # A Name is required for the endpoint if the RedirectTo parameter is supplied - throw $msgTable.nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage + throw $PodeLocale.nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage } # get the type of endpoint @@ -956,25 +956,25 @@ function Add-PodeEndpoint { # protocol must be https for client certs, or hosted behind a proxy like iis if (($Protocol -ine 'https') -and !(Test-PodeIsHosted) -and $AllowClientCertificate) { # Client certificates are only supported on HTTPS endpoints - throw $msgTable.clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage + throw $PodeLocale.clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage } # explicit tls is only supported for smtp/tcp if (($type -inotin @('smtp', 'tcp')) -and ($TlsMode -ieq 'explicit')) { # The Explicit TLS mode is only supported on SMTPS and TCPS endpoints - throw $msgTable.explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage + throw $PodeLocale.explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage } # ack message is only for smtp/tcp if (($type -inotin @('smtp', 'tcp')) -and ![string]::IsNullOrEmpty($Acknowledge)) { # The Acknowledge message is only supported on SMTP and TCP endpoints - throw $msgTable.acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage + throw $PodeLocale.acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage } # crlf message end is only for tcp if (($type -ine 'tcp') -and $CRLFMessageEnd) { # The CRLF message end check is only supported on TCP endpoints - throw $msgTable.crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage + throw $PodeLocale.crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage } # new endpoint object @@ -1048,7 +1048,7 @@ function Add-PodeEndpoint { # if the address is non-local, then check admin privileges if (!$Force -and !(Test-PodeIPAddressLocal -IP $obj.Address) -and !(Test-PodeIsAdminUser)) { # Must be running with administrator privileges to listen on non-localhost addresses - throw $msgTable.mustBeRunningWithAdminPrivilegesExceptionMessage + throw $PodeLocale.mustBeRunningWithAdminPrivilegesExceptionMessage } # has this endpoint been added before? (for http/https we can just not add it again) @@ -1061,7 +1061,7 @@ function Add-PodeEndpoint { # fail if protocol is not https if (@('https', 'wss', 'smtps', 'tcps') -inotcontains $Protocol) { # Certificate supplied for non-HTTPS/WSS endpoint - throw $msgTable.certificateSuppliedForNonHttpsWssEndpointExceptionMessage + throw $PodeLocale.certificateSuppliedForNonHttpsWssEndpointExceptionMessage } switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { diff --git a/src/Public/Events.ps1 b/src/Public/Events.ps1 index 6d509e92c..9d129667c 100644 --- a/src/Public/Events.ps1 +++ b/src/Public/Events.ps1 @@ -43,7 +43,7 @@ function Register-PodeEvent { # error if already registered if (Test-PodeEvent -Type $Type -Name $Name) { - throw ($msgTable.eventAlreadyRegisteredExceptionMessage -f $Type, $Name) # "$($Type) event already registered: $($Name)" + throw ($PodeLocale.eventAlreadyRegisteredExceptionMessage -f $Type, $Name) # "$($Type) event already registered: $($Name)" } # check for scoped vars @@ -89,7 +89,7 @@ function Unregister-PodeEvent { # error if not registered if (!(Test-PodeEvent -Type $Type -Name $Name)) { - throw ($msgTable.noEventRegisteredExceptionMessage -f $Type, $Name) # "No $($Type) event registered: $($Name)" + throw ($PodeLocale.noEventRegisteredExceptionMessage -f $Type, $Name) # "No $($Type) event registered: $($Name)" } # remove event diff --git a/src/Public/Flash.ps1 b/src/Public/Flash.ps1 index 4d704e74b..3176381e8 100644 --- a/src/Public/Flash.ps1 +++ b/src/Public/Flash.ps1 @@ -30,7 +30,7 @@ function Add-PodeFlashMessage { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { # Sessions are required to use Flash messages - throw $msgTable.sessionsRequiredForFlashMessagesExceptionMessage + throw $PodeLocale.sessionsRequiredForFlashMessagesExceptionMessage } # append the message against the key @@ -63,7 +63,7 @@ function Clear-PodeFlashMessages { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { # Sessions are required to use Flash messages - throw $msgTable.sessionsRequiredForFlashMessagesExceptionMessage + throw $PodeLocale.sessionsRequiredForFlashMessagesExceptionMessage } # clear all keys @@ -98,7 +98,7 @@ function Get-PodeFlashMessage { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { # Sessions are required to use Flash messages - throw $msgTable.sessionsRequiredForFlashMessagesExceptionMessage + throw $PodeLocale.sessionsRequiredForFlashMessagesExceptionMessage } # retrieve messages from session, then delete it @@ -134,7 +134,7 @@ function Get-PodeFlashMessageNames { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { # Sessions are required to use Flash messages - throw $msgTable.sessionsRequiredForFlashMessagesExceptionMessage + throw $PodeLocale.sessionsRequiredForFlashMessagesExceptionMessage } # return list of all current keys @@ -169,7 +169,7 @@ function Remove-PodeFlashMessage { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { # Sessions are required to use Flash messages - throw $msgTable.sessionsRequiredForFlashMessagesExceptionMessage + throw $PodeLocale.sessionsRequiredForFlashMessagesExceptionMessage } # remove key from flash messages @@ -203,7 +203,7 @@ function Test-PodeFlashMessage { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { # Sessions are required to use Flash messages - throw $msgTable.sessionsRequiredForFlashMessagesExceptionMessage + throw $PodeLocale.sessionsRequiredForFlashMessagesExceptionMessage } # return if a key exists as a flash message diff --git a/src/Public/Logging.ps1 b/src/Public/Logging.ps1 index 28b7ad9fb..34bd8ae56 100644 --- a/src/Public/Logging.ps1 +++ b/src/Public/Logging.ps1 @@ -133,7 +133,7 @@ function New-PodeLoggingMethod { [ValidateScript({ if (Test-PodeIsEmpty $_) { # A non-empty ScriptBlock is required for the Custom logging output method - throw $msgTable.nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage + throw $PodeLocale.nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage } return $true @@ -189,7 +189,7 @@ function New-PodeLoggingMethod { # only windows if (!(Test-PodeIsWindows)) { # Event Viewer logging only supported on Windows - throw $msgTable.eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage + throw $PodeLocale.eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage } # create source @@ -263,13 +263,13 @@ function Enable-PodeRequestLogging { # error if it's already enabled if ($PodeContext.Server.Logging.Types.Contains($name)) { # Request Logging has already been enabled - throw $msgTable.requestLoggingAlreadyEnabledExceptionMessage + throw $PodeLocale.requestLoggingAlreadyEnabledExceptionMessage } # ensure the Method contains a scriptblock if (Test-PodeIsEmpty $Method.ScriptBlock) { # The supplied output Method for Request Logging requires a valid ScriptBlock - throw $msgTable.outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage + throw $PodeLocale.outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage } # username property @@ -348,13 +348,13 @@ function Enable-PodeErrorLogging { # error if it's already enabled if ($PodeContext.Server.Logging.Types.Contains($name)) { # Error Logging has already been enabled - throw $msgTable.requestLoggingAlreadyEnabledExceptionMessage + throw $PodeLocale.requestLoggingAlreadyEnabledExceptionMessage } # ensure the Method contains a scriptblock if (Test-PodeIsEmpty $Method.ScriptBlock) { # The supplied output Method for Error Logging requires a valid ScriptBlock - throw $msgTable.outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage + throw $PodeLocale.outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage } # all errors? @@ -427,7 +427,7 @@ function Add-PodeLogger { [ValidateScript({ if (Test-PodeIsEmpty $_) { # A non-empty ScriptBlock is required for the logging method - throw $msgTable.nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage + throw $PodeLocale.nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage } return $true diff --git a/src/Public/Middleware.ps1 b/src/Public/Middleware.ps1 index aa496fe5d..6d36795ad 100644 --- a/src/Public/Middleware.ps1 +++ b/src/Public/Middleware.ps1 @@ -143,7 +143,7 @@ function New-PodeCsrfToken { # fail if the csrf logic hasn't been initialised if (!(Test-PodeCsrfConfigured)) { # CSRF Middleware has not been initialized - throw $msgTable.csrfMiddlewareNotInitializedExceptionMessage + throw $PodeLocale.csrfMiddlewareNotInitializedExceptionMessage } # generate a new secret and salt @@ -173,7 +173,7 @@ function Get-PodeCsrfMiddleware { # fail if the csrf logic hasn't been initialised if (!(Test-PodeCsrfConfigured)) { # CSRF Middleware has not been initialized - throw $msgTable.csrfMiddlewareNotInitializedExceptionMessage + throw $PodeLocale.csrfMiddlewareNotInitializedExceptionMessage } # return scriptblock for the csrf route middleware to test tokens @@ -242,7 +242,7 @@ function Initialize-PodeCsrf { # if sessions haven't been setup and we're not using cookies, error if (!$UseCookies -and !(Test-PodeSessionsEnabled)) { # Sessions are required to use CSRF unless you want to use cookies - throw $msgTable.sessionsRequiredForCsrfExceptionMessage + throw $PodeLocale.sessionsRequiredForCsrfExceptionMessage } # if we're using cookies, ensure a global secret exists @@ -480,7 +480,7 @@ function Add-PodeMiddleware { # ensure we have a script to run if (Test-PodeIsEmpty $InputObject.Logic) { # [Middleware]: No logic supplied in ScriptBlock - throw $msgTable.middlewareNoLogicSuppliedExceptionMessage + throw $PodeLocale.middlewareNoLogicSuppliedExceptionMessage } # set name, and override route/args diff --git a/src/Public/OAComponents.ps1 b/src/Public/OAComponents.ps1 index 736ba9cf1..a1e70f158 100644 --- a/src/Public/OAComponents.ps1 +++ b/src/Public/OAComponents.ps1 @@ -382,7 +382,7 @@ function Add-PodeOAComponentParameter { } else { # The Parameter has no name. Please provide a name to this component using the `Name` parameter - throw $msgTable.parameterHasNoNameExceptionMessage + throw $PodeLocale.parameterHasNoNameExceptionMessage } } $PodeContext.Server.OpenAPI.Definitions[$tag].components.parameters[$Name] = $Parameter @@ -744,7 +744,7 @@ function Add-PodeOAComponentPathItem { foreach ($tag in $DefinitionTag) { if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $tag ) { # The 'pathItems' reusable component feature is not available in OpenAPI v3.0. - throw $msgTable.reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage + throw $PodeLocale.reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage } #add the default OpenApi responses if ( $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses) { diff --git a/src/Public/OAProperties.ps1 b/src/Public/OAProperties.ps1 index 31691d016..64d458ab7 100644 --- a/src/Public/OAProperties.ps1 +++ b/src/Public/OAProperties.ps1 @@ -350,7 +350,7 @@ function New-PodeOAMultiTypeProperty { if ($NoProperties) { if ($Properties -or $MinProperties -or $MaxProperties) { # The parameter 'NoProperties' is mutually exclusive with 'Properties', 'MinProperties' and 'MaxProperties' - throw $msgTable.noPropertiesMutuallyExclusiveExceptionMessage + throw $PodeLocale.noPropertiesMutuallyExclusiveExceptionMessage } $param.properties = @($null) } @@ -370,7 +370,7 @@ function New-PodeOAMultiTypeProperty { } elseif ($DiscriminatorMapping) { # The parameter 'DiscriminatorMapping' can only be used when 'DiscriminatorProperty' is present - throw $msgTable.discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage + throw $PodeLocale.discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage } } if ($type -contains 'boolean') { @@ -1648,7 +1648,7 @@ function New-PodeOAObjectProperty { if ($NoProperties) { if ($Properties -or $MinProperties -or $MaxProperties) { # The parameter `NoProperties` is mutually exclusive with `Properties`, `MinProperties` and `MaxProperties` - throw $msgTable.noPropertiesMutuallyExclusiveExceptionMessage + throw $PodeLocale.noPropertiesMutuallyExclusiveExceptionMessage } $param.properties = @($null) $PropertiesFromPipeline = $false @@ -1671,7 +1671,7 @@ function New-PodeOAObjectProperty { } elseif ($DiscriminatorMapping) { # The parameter 'DiscriminatorMapping' can only be used when 'DiscriminatorProperty' is present - throw $msgTable.discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage + throw $PodeLocale.discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage } $collectedInput = [System.Collections.Generic.List[hashtable]]::new() } @@ -1799,7 +1799,7 @@ function Merge-PodeOAProperty { if ($DiscriminatorProperty) { if ($type.ToLower() -eq 'allof' ) { # The parameter 'Discriminator' is incompatible with `allOf` - throw $msgTable.discriminatorIncompatibleWithAllOfExceptionMessage + throw $PodeLocale.discriminatorIncompatibleWithAllOfExceptionMessage } $param.discriminator = @{ 'propertyName' = $DiscriminatorProperty @@ -1810,7 +1810,7 @@ function Merge-PodeOAProperty { } elseif ($DiscriminatorMapping) { # The parameter 'DiscriminatorMapping' can only be used when 'DiscriminatorProperty' is present - throw $msgTable.discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage + throw $PodeLocale.discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage } } @@ -1818,7 +1818,7 @@ function Merge-PodeOAProperty { if ($ParamsList) { if ($ParamsList.type -ine 'object' -and !$ParamsList.object) { # {0} can only be associated with an Object - throw ($msgTable.typeCanOnlyBeAssociatedWithObjectExceptionMessage -f $type) + throw ($PodeLocale.typeCanOnlyBeAssociatedWithObjectExceptionMessage -f $type) } $param.schemas += $ParamsList } diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index 70c13b7f1..290d4388e 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -3293,7 +3293,8 @@ function Add-PodeOAWebhook { } foreach ($tag in $DefinitionTag) { if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $tag ) { - throw 'The feature reusable component webhook is not available in OpenAPI v3.0.x' + # The Webhooks feature is not supported in OpenAPI v3.0.x + throw $PodeLocal.webhooksFeatureNotSupportedInOpenApi30ExceptionMessage } $PodeContext.Server.OpenAPI.Definitions[$tag].webhooks[$Name] = $refRoute } @@ -3350,7 +3351,8 @@ function Select-PodeOADefinition { ) if (Test-PodeIsEmpty $Scriptblock) { - throw 'No scriptblock for -Scriptblock passed' + # No ScriptBlock supplied + throw $PodeLocal.noScriptBlockSuppliedExceptionMessage } if (Test-PodeIsEmpty -Value $Tag) { $Tag = $PodeContext.Server.OpenAPI.DefaultDefinitionTag diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index 2d5ac7735..867456b13 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -1567,7 +1567,7 @@ function Send-PodeSignal { # error if not configured if (!$PodeContext.Server.Signals.Enabled) { # WebSockets have not been configured to send signal messages - throw $msgTable.websocketsNotConfiguredForSignalMessagesExceptionMessage + throw $PodeLocale.websocketsNotConfiguredForSignalMessagesExceptionMessage } # do nothing if no value diff --git a/src/Public/Routes.ps1 b/src/Public/Routes.ps1 index 105a68274..36d69848d 100644 --- a/src/Public/Routes.ps1 +++ b/src/Public/Routes.ps1 @@ -285,7 +285,7 @@ function Add-PodeRoute { $Path = Split-PodeRouteQuery -Path $Path if ([string]::IsNullOrWhiteSpace($Path)) { # No Path supplied for the Route - throw $msgTable.noPathSuppliedForRouteExceptionMessage + throw $PodeLocale.noPathSuppliedForRouteExceptionMessage } # ensure the route has appropriate slashes @@ -321,12 +321,12 @@ function Add-PodeRoute { if (![string]::IsNullOrWhiteSpace($Access)) { if ([string]::IsNullOrWhiteSpace($Authentication)) { # Access requires Authentication to be supplied on Routes - throw $msgTable.accessRequiresAuthenticationOnRoutesExceptionMessage + throw $PodeLocale.accessRequiresAuthenticationOnRoutesExceptionMessage } if (!(Test-PodeAccessExists -Name $Access)) { # Access method does not exist - throw ($msgTable.accessMethodDoesNotExistExceptionMessage -f $Access) + throw ($PodeLocale.accessMethodDoesNotExistExceptionMessage -f $Access) } $options = @{ @@ -340,7 +340,7 @@ function Add-PodeRoute { if (![string]::IsNullOrWhiteSpace($Authentication)) { if (!(Test-PodeAuthExists -Name $Authentication)) { # Authentication method does not exist - throw ($msgTable.authenticationMethodDoesNotExistExceptionMessage -f $Authentication) + throw ($PodeLocale.authenticationMethodDoesNotExistExceptionMessage -f $Authentication) } $options = @{ @@ -796,12 +796,12 @@ function Add-PodeStaticRoute { if (![string]::IsNullOrWhiteSpace($Access)) { if ([string]::IsNullOrWhiteSpace($Authentication)) { # Access requires Authentication to be supplied on Routes - throw $msgTable.accessRequiresAuthenticationOnRoutesExceptionMessage + throw $PodeLocale.accessRequiresAuthenticationOnRoutesExceptionMessage } if (!(Test-PodeAccessExists -Name $Access)) { # Access method does not exist - throw ($msgTable.accessMethodDoesNotExistExceptionMessage -f $Access) + throw ($PodeLocale.accessMethodDoesNotExistExceptionMessage -f $Access) } $options = @{ @@ -1175,7 +1175,7 @@ function Add-PodeRouteGroup { if (Test-PodeIsEmpty $Routes) { # The Route parameter needs a valid, not empty, scriptblock - throw $msgTable.routeParameterNeedsValidScriptblockExceptionMessage + throw $PodeLocale.routeParameterNeedsValidScriptblockExceptionMessage } if ($Path -eq '/') { @@ -1433,7 +1433,7 @@ function Add-PodeStaticRouteGroup { if (Test-PodeIsEmpty $Routes) { # The Route parameter needs a valid, not empty, scriptblock - throw $msgTable.routeParameterNeedsValidScriptblockExceptionMessage + throw $PodeLocale.routeParameterNeedsValidScriptblockExceptionMessage } if ($Path -eq '/') { @@ -1601,7 +1601,7 @@ function Add-PodeSignalRouteGroup { if (Test-PodeIsEmpty $Routes) { # The Route parameter needs a valid, not empty, scriptblock - throw $msgTable.routeParameterNeedsValidScriptblockExceptionMessage + throw $PodeLocale.routeParameterNeedsValidScriptblockExceptionMessage } if ($Path -eq '/') { @@ -2022,7 +2022,7 @@ function ConvertTo-PodeRoute { # if there are no commands, fail if (Test-PodeIsEmpty $Commands) { # No commands supplied to convert to Routes - throw $msgTable.noCommandsSuppliedToConvertToRoutesExceptionMessage + throw $PodeLocale.noCommandsSuppliedToConvertToRoutesExceptionMessage } # trim end trailing slashes from the path @@ -2268,7 +2268,7 @@ function Add-PodePage { 'scriptblock' { if (Test-PodeIsEmpty $ScriptBlock) { # A non-empty ScriptBlock is required to create a Page Route - throw $msgTable.nonEmptyScriptBlockRequiredForPageRouteExceptionMessage + throw $PodeLocale.nonEmptyScriptBlockRequiredForPageRouteExceptionMessage } $arg = @($ScriptBlock, $Data) @@ -2663,7 +2663,7 @@ function Test-PodeRoute { $Path = Split-PodeRouteQuery -Path $Path if ([string]::IsNullOrWhiteSpace($Path)) { # No Path supplied for the Route - throw $msgTable.noPathSuppliedForRouteExceptionMessage + throw $PodeLocale.noPathSuppliedForRouteExceptionMessage } # ensure the route has appropriate slashes @@ -2717,7 +2717,7 @@ function Test-PodeStaticRoute { $Path = Split-PodeRouteQuery -Path $Path if ([string]::IsNullOrWhiteSpace($Path)) { # No Path supplied for the Route - throw $msgTable.noPathSuppliedForRouteExceptionMessage + throw $PodeLocale.noPathSuppliedForRouteExceptionMessage } # ensure the route has appropriate slashes diff --git a/src/Public/SSE.ps1 b/src/Public/SSE.ps1 index bb07456c1..0ea8aa559 100644 --- a/src/Public/SSE.ps1 +++ b/src/Public/SSE.ps1 @@ -79,7 +79,7 @@ function ConvertTo-PodeSseConnection { # check Accept header - unless forcing if (!$Force -and ((Get-PodeHeader -Name 'Accept') -ine 'text/event-stream')) { # SSE can only be configured on requests with an Accept header value of text/event-stream - throw $msgTable.sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage + throw $PodeLocale.sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage } # check for default scope, and set @@ -266,13 +266,13 @@ function Send-PodeSseEvent { # error if no name if ([string]::IsNullOrEmpty($Name)) { # An SSE connection Name is required, either from -Name or $WebEvent.Sse.Name - throw $msgTable.sseConnectionNameRequiredExceptionMessage + throw $PodeLocale.sseConnectionNameRequiredExceptionMessage } # check if broadcast level if (!(Test-PodeSseBroadcastLevel -Name $Name -Group $Group -ClientId $ClientId)) { # SSE failed to broadcast due to defined SSE broadcast level - throw ($msgTable.sseFailedToBroadcastExceptionMessage -f $Name, (Get-PodeSseBroadcastLevel -Name $Name)) + throw ($PodeLocale.sseFailedToBroadcastExceptionMessage -f $Name, (Get-PodeSseBroadcastLevel -Name $Name)) } # send event diff --git a/src/Public/Secrets.ps1 b/src/Public/Secrets.ps1 index 82360ab50..d4588e8bf 100644 --- a/src/Public/Secrets.ps1 +++ b/src/Public/Secrets.ps1 @@ -130,8 +130,8 @@ function Register-PodeSecretVault { if ($PodeContext.Server.Secrets.Vaults[$Name].AutoImported) { $autoImported = ' from auto-importing' } - - throw "A Secret Vault with the name '$($Name)' has already been registered$($autoImported)" + # A Secret Vault with the name {0} has already been registered{1} + throw ($PodeLocal.secretVaultAlreadyRegisteredAutoImportExceptionMessage -f $Name, $autoImported) } # base vault config @@ -261,7 +261,8 @@ function Unlock-PodeSecretVault { # has the vault been registered? if (!(Test-PodeSecretVault -Name $Name)) { - throw "No Secret Vault with the name '$($Name)' has been registered" + # No Secret Vault with the name has been registered + throw ($PodeLocal.noSecretVaultRegisteredExceptionMessage -f $Vault) } # get vault @@ -290,7 +291,8 @@ function Unlock-PodeSecretVault { if ($null -ne $expiry) { $expiry = ([datetime]$expiry).ToUniversalTime() if ($expiry -le [datetime]::UtcNow) { - throw "Secret Vault unlock expiry date is in the past (UTC): $($expiry)" + # Secret Vault unlock expiry date is in the past (UTC) + throw ($PodeLocal.secretVaultUnlockExpiryDateInPastExceptionMessage -f $expiry) } $vault.Unlock.Expiry = $expiry @@ -435,17 +437,20 @@ function Mount-PodeSecret { # has the secret been mounted already? if (Test-PodeSecret -Name $Name) { - throw "A Secret with the name '$($Name)' has already been mounted" + # A Secret with the name has already been mounted + throw ($PodeLocal.secretAlreadyMountedExceptionMessage -f $Name) } # does the vault exist? if (!(Test-PodeSecretVault -Name $Vault)) { - throw "No Secret Vault with the name '$($Vault)' has been registered" + # No Secret Vault with the name has been registered + throw ($PodeLocal.noSecretVaultRegisteredExceptionMessage -f $Vault) } # check properties if (!(Test-PodeIsEmpty $Property) -and !(Test-PodeIsEmpty $ExpandProperty)) { - throw 'You can only provide one of either Property or ExpandPropery, but not both' + # Parameters 'NoAdditionalProperties' and 'AdditionalProperties' are mutually exclusive + throw $PodeLocal.noAdditionalPropertiesMutuallyExclusiveExceptionMessage } # which cache value? @@ -508,7 +513,8 @@ function Dismount-PodeSecret { # do nothing if the secret hasn't been mounted, unless Remove is specified if (!(Test-PodeSecret -Name $Name)) { if ($Remove) { - throw "No Secret with the name '$($Name)' has been mounted to be removed from a Secret Vault" + # No Secret named has been mounted + throw ($PodeLocal.noSecretNamedMountedExceptionMessage -f $Name) } return @@ -550,7 +556,8 @@ function Get-PodeSecret { # has the secret been mounted? if (!(Test-PodeSecret -Name $Name)) { - throw "No Secret with the name '$($Name)' has been mounted" + # No Secret named has been mounted + throw ($PodeLocal.noSecretNamedMountedExceptionMessage -f $Name) } # get the secret and vault @@ -664,7 +671,8 @@ function Update-PodeSecret { # has the secret been mounted? if (!(Test-PodeSecret -Name $Name)) { - throw "No Secret with the name '$($Name)' has been mounted" + # No Secret named has been mounted + throw ($PodeLocal.noSecretNamedMountedExceptionMessage -f $Name) } # make sure the value type is correct diff --git a/src/Public/Security.ps1 b/src/Public/Security.ps1 index 3b360f8af..3d7f1ecd4 100644 --- a/src/Public/Security.ps1 +++ b/src/Public/Security.ps1 @@ -1453,7 +1453,8 @@ function Set-PodeSecurityAccessControl { if (![string]::IsNullOrWhiteSpace($Headers) -or $AuthorizationHeader -or $CrossDomainXhrRequests) { if ($Headers -icontains '*') { if ($Credentials) { - throw 'The * wildcard for Headers, when Credentials is passed, will be taken as a literal string and not a wildcard' + # When Credentials is passed, The * wildcard for Headers will be taken as a literal string and not a wildcard + throw $PodeLocal.credentialsPassedWildcardForHeadersLiteralExceptionMessage } $Headers = @('*') @@ -1478,7 +1479,8 @@ function Set-PodeSecurityAccessControl { if ($AutoHeaders) { if ($Headers -icontains '*') { - throw 'The * wildcard for Headers, is not comptatibile with the AutoHeaders switch' + # The * wildcard for Headers is incompatible with the AutoHeaders switch + throw $PodeLocal.wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage } Add-PodeSecurityHeader -Name 'Access-Control-Allow-Headers' -Value 'content-type' -Append @@ -1487,7 +1489,8 @@ function Set-PodeSecurityAccessControl { if ($AutoMethods) { if ($Methods -icontains '*') { - throw 'The * wildcard for Methods, is not comptatibile with the AutoMethods switch' + # The * wildcard for Methods is incompatible with the AutoMethods switch + throw $PodeLocal.wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage } if ($WithOptions) { Add-PodeSecurityHeader -Name 'Access-Control-Allow-Methods' -Value 'Options' -Append @@ -1497,7 +1500,8 @@ function Set-PodeSecurityAccessControl { # duration if ($Duration -le 0) { - throw "Invalid Access-Control-Max-Age duration supplied: $($Duration). Should be greater than 0" + # Invalid Access-Control-Max-Age duration supplied + throw ($PodeLocal.invalidAccessControlMaxAgeDurationExceptionMessage -f $Duration) } Add-PodeSecurityHeader -Name 'Access-Control-Max-Age' -Value $Duration diff --git a/src/Public/Sessions.ps1 b/src/Public/Sessions.ps1 index 93f0971d0..0585ea366 100644 --- a/src/Public/Sessions.ps1 +++ b/src/Public/Sessions.ps1 @@ -109,7 +109,7 @@ function Enable-PodeSessionMiddleware { # check that session logic hasn't already been initialised if (Test-PodeSessionsEnabled) { # Session Middleware has already been initialized - throw $msgTable.sessionMiddlewareAlreadyInitializedExceptionMessage + throw $PodeLocale.sessionMiddlewareAlreadyInitializedExceptionMessage } # ensure the override store has the required methods @@ -118,7 +118,7 @@ function Enable-PodeSessionMiddleware { @('delete', 'get', 'set') | ForEach-Object { if ($members -inotcontains $_) { # The custom session storage does not implement the required '{0}()' method - throw ($msgTable.customSessionStorageMethodNotImplementedExceptionMessage -f $_) + throw ($PodeLocale.customSessionStorageMethodNotImplementedExceptionMessage -f $_) } } } @@ -127,7 +127,7 @@ function Enable-PodeSessionMiddleware { if ([string]::IsNullOrEmpty($Secret)) { if (!(Test-PodeIsEmpty $Storage)) { # A Secret is required when using custom session storage - throw $msgTable.secretRequiredForCustomSessionStorageExceptionMessage + throw $PodeLocale.secretRequiredForCustomSessionStorageExceptionMessage } $Secret = Get-PodeServerDefaultSecret @@ -182,7 +182,7 @@ function Remove-PodeSession { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { # The sessions have not been configured - throw $msgTable.sessionsNotConfiguredExceptionMessage + throw $PodeLocale.sessionsNotConfiguredExceptionMessage } # do nothing if session is null @@ -217,13 +217,13 @@ function Save-PodeSession { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { # The sessions have not been configured - throw $msgTable.sessionsNotConfiguredExceptionMessage + throw $PodeLocale.sessionsNotConfiguredExceptionMessage } # error if session is null if ($null -eq $WebEvent.Session) { # There is no session available to save - throw $msgTable.noSessionAvailableToSaveExceptionMessage + throw $PodeLocale.noSessionAvailableToSaveExceptionMessage } # if auth is in use, then assign to session store @@ -313,13 +313,13 @@ function Reset-PodeSessionExpiry { # if sessions haven't been setup, error if (!(Test-PodeSessionsEnabled)) { # The sessions have not been configured - throw $msgTable.sessionsNotConfiguredExceptionMessage + throw $PodeLocale.sessionsNotConfiguredExceptionMessage } # error if session is null if ($null -eq $WebEvent.Session) { # There is no session available to save - throw $msgTable.noSessionAvailableToSaveExceptionMessage + throw $PodeLocale.noSessionAvailableToSaveExceptionMessage } # temporarily set this session to auto-extend @@ -363,7 +363,7 @@ function Get-PodeSessionExpiry { # error if session is null if ($null -eq $WebEvent.Session) { # There is no session available to save - throw $msgTable.noSessionAvailableToSaveExceptionMessage + throw $PodeLocale.noSessionAvailableToSaveExceptionMessage } # default min date diff --git a/src/Public/State.ps1 b/src/Public/State.ps1 index 944ce3161..c78aad7eb 100644 --- a/src/Public/State.ps1 +++ b/src/Public/State.ps1 @@ -39,7 +39,7 @@ function Set-PodeState { if ($null -eq $PodeContext.Server.State) { # Pode has not been initialized - throw $msgTable.podeNotInitializedExceptionMessage + throw $PodeLocale.podeNotInitializedExceptionMessage } if ($null -eq $Scope) { @@ -83,7 +83,7 @@ function Get-PodeState { if ($null -eq $PodeContext.Server.State) { # Pode has not been initialized - throw $msgTable.podeNotInitializedExceptionMessage + throw $PodeLocale.podeNotInitializedExceptionMessage } if ($WithScope) { @@ -127,7 +127,7 @@ function Get-PodeStateNames { if ($null -eq $PodeContext.Server.State) { # Pode has not been initialized - throw $msgTable.podeNotInitializedExceptionMessage + throw $PodeLocale.podeNotInitializedExceptionMessage } if ($null -eq $Scope) { @@ -180,7 +180,7 @@ function Remove-PodeState { if ($null -eq $PodeContext.Server.State) { # Pode has not been initialized - throw $msgTable.podeNotInitializedExceptionMessage + throw $PodeLocale.podeNotInitializedExceptionMessage } $value = $PodeContext.Server.State[$Name].Value @@ -252,7 +252,7 @@ function Save-PodeState { # error if attempting to use outside of the pode server if ($null -eq $PodeContext.Server.State) { # Pode has not been initialized - throw $msgTable.podeNotInitializedExceptionMessage + throw $PodeLocale.podeNotInitializedExceptionMessage } # get the full path to save the state @@ -347,7 +347,7 @@ function Restore-PodeState { # error if attempting to use outside of the pode server if ($null -eq $PodeContext.Server.State) { # Pode has not been initialized - throw $msgTable.podeNotInitializedExceptionMessage + throw $PodeLocale.podeNotInitializedExceptionMessage } # get the full path to the state @@ -422,7 +422,7 @@ function Test-PodeState { if ($null -eq $PodeContext.Server.State) { # Pode has not been initialized - throw $msgTable.podeNotInitializedExceptionMessage + throw $PodeLocale.podeNotInitializedExceptionMessage } return $PodeContext.Server.State.ContainsKey($Name) diff --git a/src/Public/Tasks.ps1 b/src/Public/Tasks.ps1 index e430b1b0b..e8ac3e70c 100644 --- a/src/Public/Tasks.ps1 +++ b/src/Public/Tasks.ps1 @@ -426,5 +426,5 @@ function Wait-PodeTask { } # Task type is invalid, expected either [System.Threading.Tasks.Task] or [hashtable] - throw $msgTable.invalidTaskTypeExceptionMessage + throw $PodeLocale.invalidTaskTypeExceptionMessage } \ No newline at end of file diff --git a/src/Public/Threading.ps1 b/src/Public/Threading.ps1 index 972ac4f42..5cb4779df 100644 --- a/src/Public/Threading.ps1 +++ b/src/Public/Threading.ps1 @@ -247,13 +247,13 @@ function Enter-PodeLockable { # check if value type and throw if ($Object -is [valuetype]) { # Cannot lock a [ValueTypes] - throw $msgTable.cannotLockValueTypeExceptionMessage + throw $PodeLocale.cannotLockValueTypeExceptionMessage } # check if null and throw if ($null -eq $Object) { # Cannot lock an object that is null - throw $msgTable.cannotLockNullObjectExceptionMessage + throw $PodeLocale.cannotLockNullObjectExceptionMessage } # check if the global lockable is locked @@ -266,7 +266,7 @@ function Enter-PodeLockable { [System.Threading.Monitor]::TryEnter($Object.SyncRoot, $Timeout, [ref]$locked) if (!$locked) { # Failed to acquire a lock on the object - throw $msgTable.failedToAcquireLockExceptionMessage + throw $PodeLocale.failedToAcquireLockExceptionMessage } } @@ -314,13 +314,13 @@ function Exit-PodeLockable { # check if value type and throw if ($Object -is [valuetype]) { # Cannot unlock a [ValueTypes] - throw $msgTable.cannotUnlockValueTypeExceptionMessage + throw $PodeLocale.cannotUnlockValueTypeExceptionMessage } # check if null and throw if ($null -eq $Object) { # Cannot unlock an object that is null - throw $msgTable.cannotUnlockNullObjectExceptionMessage + throw $PodeLocale.cannotUnlockNullObjectExceptionMessage } if ([System.Threading.Monitor]::IsEntered($Object.SyncRoot)) { diff --git a/src/Public/Utilities.ps1 b/src/Public/Utilities.ps1 index 2d02ab16a..5657caad1 100644 --- a/src/Public/Utilities.ps1 +++ b/src/Public/Utilities.ps1 @@ -385,7 +385,7 @@ function Import-PodeSnapin { # if non-windows or core, fail if ((Test-PodeIsPSCore) -or (Test-PodeIsUnix)) { # Snapins are only supported on Windows PowerShell - throw $msgTable.snapinsSupportedOnWindowsPowershellOnlyExceptionMessage + throw $PodeLocale.snapinsSupportedOnWindowsPowershellOnlyExceptionMessage } # import the snap-in @@ -1058,7 +1058,7 @@ function New-PodeCron { # cant have None and Interval if (($Every -ieq 'none') -and ($Interval -gt 0)) { # Cannot supply an interval when the parameter `Every` is set to None - throw $msgTable.cannotSupplyIntervalWhenEveryIsNoneExceptionMessage + throw $PodeLocale.cannotSupplyIntervalWhenEveryIsNoneExceptionMessage } # base cron @@ -1159,7 +1159,7 @@ function New-PodeCron { if ($Interval -gt 0) { # Cannot supply interval value for every quarter - throw $msgTable.cannotSupplyIntervalForQuarterExceptionMessage + throw $PodeLocale.cannotSupplyIntervalForQuarterExceptionMessage } } @@ -1171,7 +1171,7 @@ function New-PodeCron { if ($Interval -gt 0) { # Cannot supply interval value for every year - throw $msgTable.cannotSupplyIntervalForYearExceptionMessage + throw $PodeLocale.cannotSupplyIntervalForYearExceptionMessage } } } diff --git a/src/Public/WebSockets.ps1 b/src/Public/WebSockets.ps1 index 5d2cbd21d..3b6eab478 100644 --- a/src/Public/WebSockets.ps1 +++ b/src/Public/WebSockets.ps1 @@ -170,7 +170,8 @@ function Disconnect-PodeWebSocket { } if ([string]::IsNullOrWhiteSpace($Name)) { - throw 'No Name for a WebSocket to disconnect from supplied' + # No Name for a WebSocket to disconnect from supplied + throw $PodeLocal.noNameForWebSocketDisconnectExceptionMessage } if (Test-PodeWebSocket -Name $Name) { @@ -204,7 +205,9 @@ function Remove-PodeWebSocket { } if ([string]::IsNullOrWhiteSpace($Name)) { - throw 'No Name for a WebSocket to remove supplied' + # No Name for a WebSocket to remove supplied + throw $PodeLocal.noNameForWebSocketRemoveExceptionMessage + } $PodeContext.Server.WebSockets.Receiver.RemoveWebSocket($Name) @@ -260,7 +263,8 @@ function Send-PodeWebSocket { # do we have a name? if ([string]::IsNullOrWhiteSpace($Name)) { - throw 'No Name for a WebSocket to send message to supplied' + # No Name for a WebSocket to send message to supplied + throw $PodeLocal.noNameForWebSocketSendMessageExceptionMessage } # do the socket exist? @@ -315,7 +319,8 @@ function Reset-PodeWebSocket { } if ([string]::IsNullOrWhiteSpace($Name)) { - throw 'No Name for a WebSocket to reset supplied' + # No Name for a WebSocket to reset supplied + throw $PodeLocal.noNameForWebSocketResetExceptionMessage } if (Test-PodeWebSocket -Name $Name) { diff --git a/tests/integration/Authentication.Tests.ps1 b/tests/integration/Authentication.Tests.ps1 index 9ffc4cb4e..527d7e288 100644 --- a/tests/integration/Authentication.Tests.ps1 +++ b/tests/integration/Authentication.Tests.ps1 @@ -6,7 +6,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]integration', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } diff --git a/tests/unit/Authentication.Tests.ps1 b/tests/unit/Authentication.Tests.ps1 index 298d9b9ff..9678402ba 100644 --- a/tests/unit/Authentication.Tests.ps1 +++ b/tests/unit/Authentication.Tests.ps1 @@ -4,7 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } $now = [datetime]::UtcNow @@ -139,12 +139,12 @@ Describe 'Test-PodeJwt' { It 'Throws exception - the JWT has expired' { # "exp" (Expiration Time) Claim - { Test-PodeJwt @{exp = 1 } } | Should -Throw -ExceptionType ([System.Exception]) -ExpectedMessage $msgTable.jwtExpiredExceptionMessage + { Test-PodeJwt @{exp = 1 } } | Should -Throw -ExceptionType ([System.Exception]) -ExpectedMessage $PodeLocale.jwtExpiredExceptionMessage } It 'Throws exception - the JWT is not yet valid for use' { # "nbf" (Not Before) Claim - { Test-PodeJwt @{nbf = 99999999999 } } | Should -Throw -ExceptionType ([System.Exception]) -ExpectedMessage $msgTable.jwtNotYetValidExceptionMessage + { Test-PodeJwt @{nbf = 99999999999 } } | Should -Throw -ExceptionType ([System.Exception]) -ExpectedMessage $PodeLocale.jwtNotYetValidExceptionMessage } } diff --git a/tests/unit/Context.Tests.ps1 b/tests/unit/Context.Tests.ps1 index 94cf871b0..9d7afd22b 100644 --- a/tests/unit/Context.Tests.ps1 +++ b/tests/unit/Context.Tests.ps1 @@ -4,7 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ 'Server' = $null; } } diff --git a/tests/unit/Cookies.Tests.ps1 b/tests/unit/Cookies.Tests.ps1 index 876aea138..25860de41 100644 --- a/tests/unit/Cookies.Tests.ps1 +++ b/tests/unit/Cookies.Tests.ps1 @@ -4,7 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Test-PodeCookie' { It 'Returns true' { diff --git a/tests/unit/CronParser.Tests.ps1 b/tests/unit/CronParser.Tests.ps1 index 7bb1c7920..d37e852cb 100644 --- a/tests/unit/CronParser.Tests.ps1 +++ b/tests/unit/CronParser.Tests.ps1 @@ -4,7 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Get-PodeCronFields' { diff --git a/tests/unit/Cryptography.Tests.ps1 b/tests/unit/Cryptography.Tests.ps1 index 60d0a87ab..959031183 100644 --- a/tests/unit/Cryptography.Tests.ps1 +++ b/tests/unit/Cryptography.Tests.ps1 @@ -2,7 +2,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Invoke-PodeHMACSHA256Hash' { diff --git a/tests/unit/Endware.Tests.ps1 b/tests/unit/Endware.Tests.ps1 index 4a41c1581..d20ee0f04 100644 --- a/tests/unit/Endware.Tests.ps1 +++ b/tests/unit/Endware.Tests.ps1 @@ -2,7 +2,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Invoke-PodeEndware' { diff --git a/tests/unit/Flash.Tests.ps1 b/tests/unit/Flash.Tests.ps1 index e75d741cc..3c1baff68 100644 --- a/tests/unit/Flash.Tests.ps1 +++ b/tests/unit/Flash.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Add-PodeFlashMessage' { diff --git a/tests/unit/Handlers.Tests.ps1 b/tests/unit/Handlers.Tests.ps1 index 1895ee15f..5270ecc4f 100644 --- a/tests/unit/Handlers.Tests.ps1 +++ b/tests/unit/Handlers.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ 'Server' = $null; } } diff --git a/tests/unit/Headers.Tests.ps1 b/tests/unit/Headers.Tests.ps1 index eccd1d30e..d0158b6f7 100644 --- a/tests/unit/Headers.Tests.ps1 +++ b/tests/unit/Headers.Tests.ps1 @@ -4,7 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Test-PodeHeader' { Context 'WebServer' { diff --git a/tests/unit/Helpers.Tests.ps1 b/tests/unit/Helpers.Tests.ps1 index 23378c533..e4b1fc473 100644 --- a/tests/unit/Helpers.Tests.ps1 +++ b/tests/unit/Helpers.Tests.ps1 @@ -4,7 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Get-PodeType' { @@ -1075,7 +1075,7 @@ Describe 'Get-PodeRelativePath' { It 'Throws error for path ot existing' { Mock Test-PodePath { return $false } - { Get-PodeRelativePath -Path './path' -TestPath } | Should -Throw -ExpectedMessage ($msgTable.pathNotExistExceptionMessage -f './path') # '*The path does not exist*' + { Get-PodeRelativePath -Path './path' -TestPath } | Should -Throw -ExpectedMessage ($PodeLocale.pathNotExistExceptionMessage -f './path') # '*The path does not exist*' } } @@ -1704,15 +1704,15 @@ Describe 'New-PodeCron' { } It 'Throws an error when using Interval without Every' { - { New-PodeCron -Interval 3 } | Should -Throw -ExpectedMessage $msgTable.cannotSupplyIntervalWhenEveryIsNoneExceptionMessage #'*Cannot supply an interval*' + { New-PodeCron -Interval 3 } | Should -Throw -ExpectedMessage $PodeLocale.cannotSupplyIntervalWhenEveryIsNoneExceptionMessage #'*Cannot supply an interval*' } It 'Throws an error when using Interval for Every Quarter' { - { New-PodeCron -Every Quarter -Interval 3 } | Should -Throw -ExpectedMessage $msgTable.cannotSupplyIntervalForQuarterExceptionMessage #Cannot supply interval value for every quarter. + { New-PodeCron -Every Quarter -Interval 3 } | Should -Throw -ExpectedMessage $PodeLocale.cannotSupplyIntervalForQuarterExceptionMessage #Cannot supply interval value for every quarter. } It 'Throws an error when using Interval for Every Year' { - { New-PodeCron -Every Year -Interval 3 } | Should -Throw -ExpectedMessage $msgTable.cannotSupplyIntervalForYearExceptionMessage #'Cannot supply interval value for every year' + { New-PodeCron -Every Year -Interval 3 } | Should -Throw -ExpectedMessage $PodeLocale.cannotSupplyIntervalForYearExceptionMessage #'Cannot supply interval value for every year' } } diff --git a/tests/unit/Logging.Tests.ps1 b/tests/unit/Logging.Tests.ps1 index 74a28cec0..f84cd87f9 100644 --- a/tests/unit/Logging.Tests.ps1 +++ b/tests/unit/Logging.Tests.ps1 @@ -4,7 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Get-PodeLogger' { It 'Returns null as the logger does not exist' { diff --git a/tests/unit/Mappers.Tests.ps1 b/tests/unit/Mappers.Tests.ps1 index e86bbe69d..fb18d6700 100644 --- a/tests/unit/Mappers.Tests.ps1 +++ b/tests/unit/Mappers.Tests.ps1 @@ -4,7 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Get-PodeContentType' { Context 'No extension supplied' { diff --git a/tests/unit/Metrics.Tests.ps1 b/tests/unit/Metrics.Tests.ps1 index 6ce9bd00c..d5d2321a5 100644 --- a/tests/unit/Metrics.Tests.ps1 +++ b/tests/unit/Metrics.Tests.ps1 @@ -4,7 +4,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ Metrics = @{ diff --git a/tests/unit/Middleware.Tests.ps1 b/tests/unit/Middleware.Tests.ps1 index c3ddd6b58..ef168eefe 100644 --- a/tests/unit/Middleware.Tests.ps1 +++ b/tests/unit/Middleware.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Get-PodeInbuiltMiddleware' { diff --git a/tests/unit/NameGenerator.Tests.ps1 b/tests/unit/NameGenerator.Tests.ps1 index a3863037f..4a2f05d70 100644 --- a/tests/unit/NameGenerator.Tests.ps1 +++ b/tests/unit/NameGenerator.Tests.ps1 @@ -2,7 +2,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Get-PodeRandomName' { diff --git a/tests/unit/OpenApi.Tests.ps1 b/tests/unit/OpenApi.Tests.ps1 index 3ef7b27ed..d0d2fbfec 100644 --- a/tests/unit/OpenApi.Tests.ps1 +++ b/tests/unit/OpenApi.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } -Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture "en-us" -FileName "Pode" +Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture "en-us" -FileName "Pode" } Describe 'OpenApi' { @@ -2086,7 +2086,7 @@ Describe 'OpenApi' { { Merge-PodeOAProperty -Type AllOf -DiscriminatorProperty 'name' -ObjectDefinitions @('Pet', (New-PodeOAObjectProperty -Properties @((New-PodeOAIntProperty -Name 'id'), (New-PodeOAStringProperty -Name 'name'))) - ) } | Should -Throw -ExpectedMessage $msgTable.discriminatorIncompatibleWithAllOfExceptionMessage #'Discriminator parameter is not compatible with allOf' + ) } | Should -Throw -ExpectedMessage $PodeLocale.discriminatorIncompatibleWithAllOfExceptionMessage #'Discriminator parameter is not compatible with allOf' } #Should -Throw -ExpectedMessage 'Discriminator parameter is not compatible with allOf' @@ -2277,7 +2277,7 @@ Describe 'OpenApi' { it 'throw error' { { Add-PodeOAComponentParameter -Parameter ( New-PodeOAIntProperty -Name 'petId' -Format Int64 -Description 'ID of the pet' | New-PodeOAObjectProperty ) } | - Should -Throw -ExpectedMessage $msgTable.parameterHasNoNameExceptionMessage # The Parameter has no name. Please give this component a name using the 'Name' parameter. + Should -Throw -ExpectedMessage $PodeLocale.parameterHasNoNameExceptionMessage # The Parameter has no name. Please give this component a name using the 'Name' parameter. } } Context 'ConvertTo-PodeOAParameter' { diff --git a/tests/unit/PrivateOpenApi.Tests.ps1 b/tests/unit/PrivateOpenApi.Tests.ps1 index e0f8e1bee..23e76485d 100644 --- a/tests/unit/PrivateOpenApi.Tests.ps1 +++ b/tests/unit/PrivateOpenApi.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'PrivateOpenApi' { diff --git a/tests/unit/Responses.Tests.ps1 b/tests/unit/Responses.Tests.ps1 index 9bd533b69..73c28e745 100644 --- a/tests/unit/Responses.Tests.ps1 +++ b/tests/unit/Responses.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture "en-us" -FileName "Pode" + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture "en-us" -FileName "Pode" } diff --git a/tests/unit/Routes.Tests.ps1 b/tests/unit/Routes.Tests.ps1 index ab74a7624..9638596af 100644 --- a/tests/unit/Routes.Tests.ps1 +++ b/tests/unit/Routes.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ 'Server' = $null; } } @@ -585,7 +585,7 @@ Describe 'ConvertTo-PodeRoute' { } It 'Throws error for no commands' { - { ConvertTo-PodeRoute } | Should -Throw -ExpectedMessage $msgTable.noCommandsSuppliedToConvertToRoutesExceptionMessage # No commands supplied to convert to Routes. + { ConvertTo-PodeRoute } | Should -Throw -ExpectedMessage $PodeLocale.noCommandsSuppliedToConvertToRoutesExceptionMessage # No commands supplied to convert to Routes. } It 'Calls Add-PodeRoute twice for commands' { @@ -619,7 +619,7 @@ Describe 'Add-PodePage' { It 'Throws error for invalid FilePath' { $PodeContext.Server = @{ 'Root' = $pwd } - { Add-PodePage -Name 'RickMorty' -FilePath './fake/path' } | Should -Throw -ExpectedMessage ($msgTable.pathNotExistExceptionMessage -f '*/fake/path') #'*the path does not exist*' + { Add-PodePage -Name 'RickMorty' -FilePath './fake/path' } | Should -Throw -ExpectedMessage ($PodeLocale.pathNotExistExceptionMessage -f '*/fake/path') #'*the path does not exist*' } It 'Call Add-PodeRoute once for ScriptBlock page' { diff --git a/tests/unit/Schedules.Tests.ps1 b/tests/unit/Schedules.Tests.ps1 index e1705db87..10a62e722 100644 --- a/tests/unit/Schedules.Tests.ps1 +++ b/tests/unit/Schedules.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Find-PodeSchedule' { Context 'Invalid parameters supplied' { diff --git a/tests/unit/Security.Tests.ps1 b/tests/unit/Security.Tests.ps1 index 4fc896dda..39512002b 100644 --- a/tests/unit/Security.Tests.ps1 +++ b/tests/unit/Security.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ 'Server' = $null; } } @@ -581,7 +581,7 @@ Describe 'New-PodeCsrfToken' { } } - { New-PodeCsrfToken } | Should -Throw -ExpectedMessage $msgTable.csrfMiddlewareNotInitializedExceptionMessage #CSRF Middleware has not been initialized. + { New-PodeCsrfToken } | Should -Throw -ExpectedMessage $PodeLocale.csrfMiddlewareNotInitializedExceptionMessage #CSRF Middleware has not been initialized. } diff --git a/tests/unit/Server.Tests.ps1 b/tests/unit/Server.Tests.ps1 index 052330a2d..49f091587 100644 --- a/tests/unit/Server.Tests.ps1 +++ b/tests/unit/Server.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ diff --git a/tests/unit/Serverless.Tests.ps1 b/tests/unit/Serverless.Tests.ps1 index a0f35b6fa..4dc4c8e50 100644 --- a/tests/unit/Serverless.Tests.ps1 +++ b/tests/unit/Serverless.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'Start-PodeAzFuncServer' { BeforeAll { diff --git a/tests/unit/Sessions.Tests.ps1 b/tests/unit/Sessions.Tests.ps1 index 31dddb372..76e405e60 100644 --- a/tests/unit/Sessions.Tests.ps1 +++ b/tests/unit/Sessions.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $now = [datetime]::UtcNow } @@ -259,7 +259,7 @@ Describe 'Set-PodeSession' { Describe 'Remove-PodeSession' { It 'Throws an error if sessions are not configured' { Mock Test-PodeSessionsEnabled { return $false } - { Remove-PodeSession } | Should -Throw $msgTable.sessionsNotConfiguredExceptionMessage # Sessions have not been configured. + { Remove-PodeSession } | Should -Throw $PodeLocale.sessionsNotConfiguredExceptionMessage # Sessions have not been configured. } It 'Does nothing if there is no session' { @@ -286,13 +286,13 @@ Describe 'Remove-PodeSession' { Describe 'Save-PodeSession' { It 'Throws an error if sessions are not configured' { Mock Test-PodeSessionsEnabled { return $false } - { Save-PodeSession } | Should -Throw $msgTable.sessionsNotConfiguredExceptionMessage # Sessions have not been configured. + { Save-PodeSession } | Should -Throw $PodeLocale.sessionsNotConfiguredExceptionMessage # Sessions have not been configured. } It 'Throws error if there is no session' { Mock Test-PodeSessionsEnabled { return $true } $WebEvent = @{} - { Save-PodeSession } | Should -Throw -ExpectedMessage $msgTable.noSessionAvailableToSaveExceptionMessage # There is no session available to save. + { Save-PodeSession } | Should -Throw -ExpectedMessage $PodeLocale.noSessionAvailableToSaveExceptionMessage # There is no session available to save. } It 'Call saves the session' { diff --git a/tests/unit/State.Tests.ps1 b/tests/unit/State.Tests.ps1 index 700b74d19..8a3192b19 100644 --- a/tests/unit/State.Tests.ps1 +++ b/tests/unit/State.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ 'Server' = $null; } } @@ -13,7 +13,7 @@ BeforeAll { Describe 'Set-PodeState' { It 'Throws error when not initialised' { $PodeContext.Server = @{ 'State' = $null } - { Set-PodeState -Name 'test' } | Should -Throw -ExpectedMessage $msgTable.podeNotInitializedExceptionMessage # Pode has not been initialized. + { Set-PodeState -Name 'test' } | Should -Throw -ExpectedMessage $PodeLocale.podeNotInitializedExceptionMessage # Pode has not been initialized. } It 'Sets and returns an object' { @@ -29,7 +29,7 @@ Describe 'Set-PodeState' { Describe 'Get-PodeState' { It 'Throws error when not initialised' { $PodeContext.Server = @{ 'State' = $null } - { Get-PodeState -Name 'test' } | Should -Throw -ExpectedMessage $msgTable.podeNotInitializedExceptionMessage # Pode has not been initialized. + { Get-PodeState -Name 'test' } | Should -Throw -ExpectedMessage $PodeLocale.podeNotInitializedExceptionMessage # Pode has not been initialized. } It 'Gets an object from the state' { @@ -42,7 +42,7 @@ Describe 'Get-PodeState' { Describe 'Remove-PodeState' { It 'Throws error when not initialised' { $PodeContext.Server = @{ 'State' = $null } - { Remove-PodeState -Name 'test' } | Should -Throw -ExpectedMessage $msgTable.podeNotInitializedExceptionMessage # Pode has not been initialized. + { Remove-PodeState -Name 'test' } | Should -Throw -ExpectedMessage $PodeLocale.podeNotInitializedExceptionMessage # Pode has not been initialized. } It 'Removes an object from the state' { @@ -56,7 +56,7 @@ Describe 'Remove-PodeState' { Describe 'Save-PodeState' { It 'Throws error when not initialised' { $PodeContext.Server = @{ 'State' = $null } - { Save-PodeState -Path 'some/path' } | Should -Throw -ExpectedMessage $msgTable.podeNotInitializedExceptionMessage # Pode has not been initialized. + { Save-PodeState -Path 'some/path' } | Should -Throw -ExpectedMessage $PodeLocale.podeNotInitializedExceptionMessage # Pode has not been initialized. } It 'Saves the state to file' { @@ -96,7 +96,7 @@ Describe 'Save-PodeState' { Describe 'Restore-PodeState' { It 'Throws error when not initialised' { $PodeContext.Server = @{ 'State' = $null } - { Restore-PodeState -Path 'some/path' } | Should -Throw -ExpectedMessage $msgTable.podeNotInitializedExceptionMessage # Pode has not been initialized. + { Restore-PodeState -Path 'some/path' } | Should -Throw -ExpectedMessage $PodeLocale.podeNotInitializedExceptionMessage # Pode has not been initialized. } It 'Restores the state from file' { @@ -113,7 +113,7 @@ Describe 'Restore-PodeState' { Describe 'Test-PodeState' { It 'Throws error when not initialised' { $PodeContext.Server = @{ 'State' = $null } - { Test-PodeState -Name 'test' } | Should -Throw -ExpectedMessage $msgTable.podeNotInitializedExceptionMessage # Pode has not been initialized. + { Test-PodeState -Name 'test' } | Should -Throw -ExpectedMessage $PodeLocale.podeNotInitializedExceptionMessage # Pode has not been initialized. } It 'Returns true for an object being in the state' { diff --git a/tests/unit/Timers.Tests.ps1 b/tests/unit/Timers.Tests.ps1 index 3938dda18..9e5567f5b 100644 --- a/tests/unit/Timers.Tests.ps1 +++ b/tests/unit/Timers.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable msgTable -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' $PodeContext = @{ 'Server' = $null; } } From 40a05f7ab5f560f85deb460ed36ce6b3cc2ab507 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sat, 1 Jun 2024 22:17:22 -0700 Subject: [PATCH 022/177] fix a message --- src/Public/Secrets.ps1 | 3 +-- tests/integration/Authentication.Tests.ps1 | 8 -------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/Public/Secrets.ps1 b/src/Public/Secrets.ps1 index d4588e8bf..9425ae00b 100644 --- a/src/Public/Secrets.ps1 +++ b/src/Public/Secrets.ps1 @@ -449,8 +449,7 @@ function Mount-PodeSecret { # check properties if (!(Test-PodeIsEmpty $Property) -and !(Test-PodeIsEmpty $ExpandProperty)) { - # Parameters 'NoAdditionalProperties' and 'AdditionalProperties' are mutually exclusive - throw $PodeLocal.noAdditionalPropertiesMutuallyExclusiveExceptionMessage + throw 'You can only provide one of either Property or ExpandPropery, but not both' } # which cache value? diff --git a/tests/integration/Authentication.Tests.ps1 b/tests/integration/Authentication.Tests.ps1 index 527d7e288..c924f0445 100644 --- a/tests/integration/Authentication.Tests.ps1 +++ b/tests/integration/Authentication.Tests.ps1 @@ -2,14 +2,6 @@ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseUsingScopeModifierInNewRunspaces', '')] param() -BeforeAll { - $path = $PSCommandPath - $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]integration', '/src/' - Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } - Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' - -} - Describe 'Authentication Requests' { BeforeAll { From 0b43794200e7facae7cbc39203cbdd6fd4e3b161 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sun, 2 Jun 2024 06:12:55 -0700 Subject: [PATCH 023/177] Update Pode.psm1 fix the tmpPodeLocale variable name --- src/Pode.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Pode.psm1 b/src/Pode.psm1 index bf3f6fd54..7b19597a3 100644 --- a/src/Pode.psm1 +++ b/src/Pode.psm1 @@ -49,7 +49,7 @@ if ($null -eq $tmpPodeLocale) { try { # Create the global msgTable read-only variable - New-Variable -Name 'PodeLocale' -Value $tmpMsgtable -Scope Global -Option ReadOnly -Force + New-Variable -Name 'PodeLocale' -Value $tmpPodeLocale -Scope Global -Option ReadOnly -Force # load assemblies Add-Type -AssemblyName System.Web -ErrorAction Stop From 578f25bc981fd1ba4a44b9a240787e73f5461225 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sun, 2 Jun 2024 09:09:44 -0700 Subject: [PATCH 024/177] Add new test and PodeLocale entries --- src/Locales/ar/Pode.psd1 | 42 +++++++++- src/Locales/de/Pode.psd1 | 44 +++++++++- src/Locales/en/Pode.psd1 | 44 ++++++++-- src/Locales/es/Pode.psd1 | 42 +++++++++- src/Locales/fr/Pode.psd1 | 42 +++++++++- src/Locales/it/Pode.psd1 | 42 +++++++++- src/Locales/ja/Pode.psd1 | 43 ++++++++-- src/Locales/kr/Pode.psd1 | 42 +++++++++- src/Locales/pl/Pode.psd1 | 42 +++++++++- src/Locales/pt/Pode.psd1 | 42 +++++++++- src/Locales/zn/Pode.psd1 | 42 +++++++++- src/Private/OpenApi.ps1 | 4 +- src/Public/Core.ps1 | 3 +- src/Public/FileWatchers.ps1 | 3 +- src/Public/OAProperties.ps1 | 9 +- src/Public/OpenApi.ps1 | 134 +++++++++++++++++++++--------- src/Public/ScopedVariables.ps1 | 3 +- src/Public/Secrets.ps1 | 28 ++++--- src/Public/Security.ps1 | 11 +-- src/Public/Sessions.ps1 | 3 +- src/Public/Tasks.ps1 | 16 ++-- src/Public/Utilities.ps1 | 9 +- src/Public/Verbs.ps1 | 3 +- src/Public/WebSockets.ps1 | 21 +++-- tests/unit/Localization.Tests.ps1 | 41 ++++++++- tests/unit/OpenApi.Tests.ps1 | 7 +- 26 files changed, 626 insertions(+), 136 deletions(-) diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 9265d9588..9e4d9e05c 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -37,7 +37,6 @@ singleValueForIntervalExceptionMessage = يمكنك تقديم قيمة {0} وا scriptErrorExceptionMessage = خطأ '{0}' في البرنامج النصي {1} {2} (السطر {3}) الحرف {4} أثناء تنفيذ {5} على الكائن {6} 'الصنف: {7} الصنف الأساسي: {8} noScriptBlockSuppliedExceptionMessage = لم يتم تقديم أي ScriptBlock. iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN مفقود. -invalidContentTypeForSchemaExceptionMessage = تم العثور على نوع محتوى غير صالح للمخطط: {0} propertiesParameterWithoutNameExceptionMessage = لا يمكن استخدام معلمات الخصائص إذا لم يكن لدى الخاصية اسم. multiTypePropertiesRequireOpenApi31ExceptionMessage = تتطلب خصائص الأنواع المتعددة إصدار OpenApi 3.1 أو أعلى. openApiVersionPropertyMandatoryExceptionMessage = خاصية إصدار OpenApi إلزامية. @@ -47,7 +46,6 @@ unsupportedObjectExceptionMessage = الكائن غير مدعوم validationOfAnyOfSchemaNotSupportedExceptionMessage = التحقق من مخطط يتضمن 'أي منها' غير مدعوم. validationOfOneOfSchemaNotSupportedExceptionMessage = التحقق من مخطط يتضمن 'واحد منها' غير مدعوم. cannotCreatePropertyWithoutTypeExceptionMessage = لا يمكن إنشاء الخاصية لأنه لم يتم تعريف نوع. -paramsNoAdditionalPropertiesExclusiveExceptionMessage = المعلمات -NoAdditionalProperties و -AdditionalProperties تتعارض مع بعضها البعض. headerMustHaveNameInEncodingContextExceptionMessage = يجب أن يحتوي الرأس على اسم عند استخدامه في سياق الترميز. descriptionRequiredExceptionMessage = الوصف مطلوب. openApiDocumentNotCompliantExceptionMessage = مستند OpenAPI غير متوافق. @@ -167,8 +165,6 @@ cannotSupplyIntervalForYearExceptionMessage = لا يمكن توفير قيمة secretVaultAlreadyRegisteredExceptionMessage = تم تسجيل مخزن الأسرار بالاسم '{0}' بالفعل{1}. secretVaultUnlockExpiryDateInPastExceptionMessage = تاريخ انتهاء صلاحية فتح مخزن الأسرار في الماضي (UTC): {0} secretAlreadyMountedExceptionMessage = تم تثبيت سر بالاسم '{0}' بالفعل. -noSecretVaultRegisteredExceptionMessage = لم يتم تسجيل مخزن أسرار بالاسم '{0}'. -noAdditionalPropertiesMutuallyExclusiveExceptionMessage = المعاملات 'NoAdditionalProperties' و 'AdditionalProperties' متعارضة. credentialsPassedWildcardForHeadersLiteralExceptionMessage = عند تمرير بيانات الاعتماد، سيتم اعتبار العلامة * للعنوان كـ سلسلة نصية حرفية وليس كعلامة. wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = العلامة * للعنوان غير متوافقة مع مفتاح AutoHeaders. wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = العلامة * للطرق غير متوافقة مع مفتاح AutoMethods. @@ -178,4 +174,42 @@ noNameForWebSocketRemoveExceptionMessage = لا يوجد اسم لإزالة Web noNameForWebSocketSendMessageExceptionMessage = لا يوجد اسم لإرسال رسالة إلى WebSocket المزود. noSecretNamedMountedExceptionMessage = لم يتم تثبيت أي سر بالاسم '{0}'. noNameForWebSocketResetExceptionMessage = لا يوجد اسم لإعادة تعيين WebSocket من المزود. +schemaValidationRequiresPowerShell610ExceptionMessage = يتطلب التحقق من صحة المخطط إصدار PowerShell 6.1.0 أو أحدث. +routeParameterCannotBeNullExceptionMessage = لا يمكن أن يكون المعامل 'Route' فارغًا. +encodingAttributeOnlyAppliesToMultipartExceptionMessage = ينطبق سمة الترميز فقط على نصوص الطلبات multipart و application/x-www-form-urlencoded. +testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = يجب تمكين 'Test-PodeOAComponentSchema' باستخدام 'Enable-PodeOpenApi -EnableSchemaValidation' +openApiComponentSchemaDoesNotExistExceptionMessage = مخطط مكون OpenApi {0} غير موجود. +openApiParameterRequiresNameExceptionMessage = يتطلب معلمة OpenApi اسمًا محددًا. +openApiLicenseObjectRequiresNameExceptionMessage = يتطلب كائن OpenAPI 'license' الخاصية 'name'. استخدم المعامل -LicenseName. +parametersValueOrExternalValueMandatoryExceptionMessage = المعاملات 'Value' أو 'ExternalValue' إلزامية. +parametersMutuallyExclusiveExceptionMessage = المعاملات '{0}' و '{1}' متعارضة. +maximumConcurrentWebSocketThreadsInvalidExceptionMessage = يجب أن يكون الحد الأقصى لمؤشرات ترابط WebSocket المتزامنة >=1، ولكن تم الحصول عليه: {0} +maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = لا يمكن أن يكون الحد الأقصى لمؤشرات ترابط WebSocket المتزامنة أقل من الحد الأدنى {0}، ولكن تم الحصول عليه: {1} +alreadyConnectedToWebSocketExceptionMessage = متصل بالفعل بـ WebSocket بالاسم '{0}' +failedToConnectToWebSocketExceptionMessage = فشل الاتصال بـ WebSocket: {0} +verbNoLogicPassedExceptionMessage = [الفعل] {0}: لم يتم تمرير أي منطق +scriptPathDoesNotExistExceptionMessage = مسار البرنامج النصي غير موجود: {0} +failedToImportModuleExceptionMessage = فشل في استيراد الوحدة: {0} +modulePathDoesNotExistExceptionMessage = مسار الوحدة غير موجود: {0} +defaultValueNotBooleanOrEnumExceptionMessage = القيمة الافتراضية ليست من نوع boolean وليست جزءًا من التعداد. +propertiesTypeObjectAssociationExceptionMessage = يمكن ربط خصائص النوع Object فقط بـ {0}. +invalidContentTypeForSchemaExceptionMessage = 'content-type' غير صالح في المخطط: {0} +openApiRequestStyleInvalidForParameterExceptionMessage = لا يمكن أن يكون نمط الطلب OpenApi {0} لمعلمة {1}. +pathParameterRequiresRequiredSwitchExceptionMessage = إذا كانت موقع المعلمة هو 'Path'، فإن المعلمة التبديل 'Required' إلزامية. +operationIdMustBeUniqueForArrayExceptionMessage = يجب أن يكون OperationID: {0} فريدًا ولا يمكن تطبيقه على مصفوفة. +operationIdMustBeUniqueExceptionMessage = يجب أن يكون OperationID: {0} فريدًا. +noOpenApiUrlSuppliedExceptionMessage = لم يتم توفير عنوان URL OpenAPI لـ {0}. +noTitleSuppliedForPageExceptionMessage = لم يتم توفير عنوان للصفحة {0}. +noRoutePathSuppliedForPageExceptionMessage = لم يتم توفير مسار للصفحة {0}. +swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = هذا الإصدار من Swagger-Editor لا يدعم OpenAPI 3.1 +rapidPdfDoesNotSupportOpenApi31ExceptionMessage = أداة الوثائق RapidPdf لا تدعم OpenAPI 3.1 +definitionTagNotDefinedExceptionMessage = لم يتم تعريف علامة التعريف {0}. +scopedVariableNotFoundExceptionMessage = لم يتم العثور على المتغير المحدد: {0} +noSecretVaultRegisteredExceptionMessage = لم يتم تسجيل خزينة سرية بالاسم '{0}'. +invalidStrictTransportSecurityDurationExceptionMessage = تم توفير مدة Strict-Transport-Security غير صالحة: {0}. يجب أن تكون أكبر من 0. +durationMustBeZeroOrGreaterExceptionMessage = يجب أن تكون المدة 0 أو أكبر، ولكن تم الحصول عليها: {0}s +taskAlreadyDefinedExceptionMessage = [المهمة] {0}: المهمة معرفة بالفعل. +maximumConcurrentTasksInvalidExceptionMessage = يجب أن يكون الحد الأقصى للمهام المتزامنة >=1، ولكن تم الحصول عليه: {0} +maximumConcurrentTasksLessThanMinimumExceptionMessage = لا يمكن أن يكون الحد الأقصى للمهام المتزامنة أقل من الحد الأدنى {0}، ولكن تم الحصول عليه: {1} +taskDoesNotExistExceptionMessage = المهمة '{0}' غير موجودة. '@ diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index 4ef2490a8..553f86447 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -37,7 +37,6 @@ singleValueForIntervalExceptionMessage = Sie können nur einen einzelnen {0}-Wer scriptErrorExceptionMessage = Fehler '{0}' im Skript {1} {2} (Zeile {3}) Zeichen {4} beim Ausführen von {5} auf {6} Objekt '{7}' Klasse: {8} Basisklasse: {9} noScriptBlockSuppliedExceptionMessage = Kein Skriptblock angegeben. iisAspnetcoreTokenMissingExceptionMessage = Das IIS-ASPNETCORE_TOKEN fehlt. -invalidContentTypeForSchemaExceptionMessage = Ungültiger Inhaltstyp für Schema gefunden: {0} propertiesParameterWithoutNameExceptionMessage = Die Eigenschaftsparameter können nicht verwendet werden, wenn die Eigenschaft keinen Namen hat. multiTypePropertiesRequireOpenApi31ExceptionMessage = Mehrfachtyp-Eigenschaften erfordern OpenApi-Version 3.1 oder höher. openApiVersionPropertyMandatoryExceptionMessage = Die Eigenschaft OpenApi-Version ist obligatorisch. @@ -47,7 +46,6 @@ unsupportedObjectExceptionMessage = Nicht unterstütztes Objekt validationOfAnyOfSchemaNotSupportedExceptionMessage = Die Validierung eines Schemas, das 'anyof' enthält, wird nicht unterstützt. validationOfOneOfSchemaNotSupportedExceptionMessage = Die Validierung eines Schemas, das 'oneof' enthält, wird nicht unterstützt. cannotCreatePropertyWithoutTypeExceptionMessage = Die Eigenschaft kann nicht erstellt werden, weil kein Typ definiert ist. -paramsNoAdditionalPropertiesExclusiveExceptionMessage = Die Parameter -NoAdditionalProperties und -AdditionalProperties schließen sich gegenseitig aus. headerMustHaveNameInEncodingContextExceptionMessage = Ein Header muss einen Namen haben, wenn er im Codierungskontext verwendet wird. descriptionRequiredExceptionMessage = Eine Beschreibung ist erforderlich. openApiDocumentNotCompliantExceptionMessage = Das OpenAPI-Dokument ist nicht konform. @@ -167,8 +165,6 @@ cannotSupplyIntervalForYearExceptionMessage = Ein Intervallwert kann nicht für secretVaultAlreadyRegisteredExceptionMessage = Ein Geheimnis-Tresor mit dem Namen '{0}' wurde bereits registriert{1}. secretVaultUnlockExpiryDateInPastExceptionMessage = Das Ablaufdatum zum Entsperren des Geheimnis-Tresors liegt in der Vergangenheit (UTC): {0} secretAlreadyMountedExceptionMessage = Ein Geheimnis mit dem Namen '{0}' wurde bereits eingebunden. -noSecretVaultRegisteredExceptionMessage = Kein Geheimnis-Tresor mit dem Namen '{0}' wurde registriert. -noAdditionalPropertiesMutuallyExclusiveExceptionMessage = Die Parameter 'NoAdditionalProperties' und 'AdditionalProperties' schließen sich gegenseitig aus. credentialsPassedWildcardForHeadersLiteralExceptionMessage = Wenn Anmeldeinformationen übergeben werden, wird das *-Wildcard für Header als Literalzeichenfolge und nicht als Platzhalter verwendet. wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = Das *-Wildcard für Header ist nicht mit dem AutoHeaders-Schalter kompatibel. wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = Das *-Wildcard für Methoden ist nicht mit dem AutoMethods-Schalter kompatibel. @@ -178,4 +174,44 @@ noNameForWebSocketRemoveExceptionMessage = Kein Name für das Entfernen des WebS noNameForWebSocketSendMessageExceptionMessage = Kein Name für das Senden einer Nachricht an den WebSocket angegeben. noSecretNamedMountedExceptionMessage = Kein Geheimnis mit dem Namen '{0}' wurde eingebunden. noNameForWebSocketResetExceptionMessage = Kein Name für das Zurücksetzen des WebSocket angegeben. +schemaValidationRequiresPowerShell610ExceptionMessage = Die Schema-Validierung erfordert PowerShell Version 6.1.0 oder höher. +routeParameterCannotBeNullExceptionMessage = Der Parameter 'Route' darf nicht null sein. +encodingAttributeOnlyAppliesToMultipartExceptionMessage = Das Encoding-Attribut gilt nur für multipart und application/x-www-form-urlencoded Anfragekörper. +testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema' muss mit 'Enable-PodeOpenApi -EnableSchemaValidation' aktiviert werden. +openApiComponentSchemaDoesNotExistExceptionMessage = Das OpenApi-Komponentenschema {0} existiert nicht. +openApiParameterRequiresNameExceptionMessage = Der OpenApi-Parameter erfordert einen angegebenen Namen. +openApiLicenseObjectRequiresNameExceptionMessage = Das OpenAPI-Objekt 'license' erfordert die Eigenschaft 'name'. Verwenden Sie den Parameter -LicenseName. +parametersValueOrExternalValueMandatoryExceptionMessage = Die Parameter 'Value' oder 'ExternalValue' sind obligatorisch. +parametersMutuallyExclusiveExceptionMessage = Die Parameter '{0}' und '{1}' schließen sich gegenseitig aus. +maximumConcurrentWebSocketThreadsInvalidExceptionMessage = Die maximale Anzahl gleichzeitiger WebSocket-Threads muss >=1 sein, aber erhalten: {0} +maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = Die maximale Anzahl gleichzeitiger WebSocket-Threads darf nicht kleiner als das Minimum von {0} sein, aber erhalten: {1} +alreadyConnectedToWebSocketExceptionMessage = Bereits mit dem WebSocket mit dem Namen '{0}' verbunden +failedToConnectToWebSocketExceptionMessage = Verbindung zum WebSocket fehlgeschlagen: {0} +verbNoLogicPassedExceptionMessage = [Verb] {0}: Keine Logik übergeben +scriptPathDoesNotExistExceptionMessage = Der Skriptpfad existiert nicht: {0} +failedToImportModuleExceptionMessage = Modulimport fehlgeschlagen: {0} +modulePathDoesNotExistExceptionMessage = Der Modulpfad existiert nicht: {0} +defaultValueNotBooleanOrEnumExceptionMessage = Der Standardwert ist kein Boolean und gehört nicht zum Enum. +propertiesTypeObjectAssociationExceptionMessage = Nur Eigenschaften vom Typ Object können mit {0} verknüpft werden. +invalidContentTypeForSchemaExceptionMessage = Ungültiger 'content-type' im Schema gefunden: {0} +openApiRequestStyleInvalidForParameterExceptionMessage = Der OpenApi-Anfragestil kann für einen {1}-Parameter nicht {0} sein. +pathParameterRequiresRequiredSwitchExceptionMessage = Wenn der Parameterstandort 'Path' ist, ist der Schalterparameter 'Required' erforderlich. +operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0} muss eindeutig sein und kann nicht auf ein Array angewendet werden. +operationIdMustBeUniqueExceptionMessage = OperationID: {0} muss eindeutig sein. +noOpenApiUrlSuppliedExceptionMessage = Keine OpenAPI-URL für {0} angegeben. +noTitleSuppliedForPageExceptionMessage = Kein Titel für die Seite {0} angegeben. +noRoutePathSuppliedForPageExceptionMessage = Kein Routenpfad für die Seite {0} angegeben. +swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = Diese Version des Swagger-Editors unterstützt OpenAPI 3.1 nicht. +rapidPdfDoesNotSupportOpenApi31ExceptionMessage = Das Dokumentationstool RapidPdf unterstützt OpenAPI 3.1 nicht. +definitionTagNotDefinedExceptionMessage = Definitionstag {0} ist nicht definiert. +scopedVariableNotFoundExceptionMessage = Bereichsvariable nicht gefunden: {0} +noSecretVaultRegisteredExceptionMessage = Kein Geheimnistresor mit dem Namen '{0}' registriert. +invalidStrictTransportSecurityDurationExceptionMessage = Ungültige Strict-Transport-Security-Dauer angegeben: {0}. Sie sollte größer als 0 sein. +durationMustBeZeroOrGreaterExceptionMessage = Die Dauer muss 0 oder größer sein, aber erhalten: {0}s +taskAlreadyDefinedExceptionMessage = [Aufgabe] {0}: Aufgabe bereits definiert. +maximumConcurrentTasksInvalidExceptionMessage = Die maximale Anzahl gleichzeitiger Aufgaben muss >=1 sein, aber erhalten: {0} +maximumConcurrentTasksLessThanMinimumExceptionMessage = Die maximale Anzahl gleichzeitiger Aufgaben darf nicht kleiner als das Minimum von {0} sein, aber erhalten: {1} +taskDoesNotExistExceptionMessage = Aufgabe '{0}' existiert nicht. '@ + + diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 68307fa13..3b6924a07 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -37,7 +37,6 @@ singleValueForIntervalExceptionMessage = You can only supply a single {0} value scriptErrorExceptionMessage = Error '{0}' in script {1} {2} (line {3}) char {4} executing {5} on {6} object '{7}' Class: {8} BaseClass: {9} noScriptBlockSuppliedExceptionMessage = No ScriptBlock supplied. iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN is missing. -invalidContentTypeForSchemaExceptionMessage = Invalid content-type found for schema: {0} propertiesParameterWithoutNameExceptionMessage = The Properties parameters cannot be used if the Property has no name. multiTypePropertiesRequireOpenApi31ExceptionMessage = Multi-type properties require OpenApi Version 3.1 or above. openApiVersionPropertyMandatoryExceptionMessage = OpenApi Version property is mandatory. @@ -47,7 +46,6 @@ unsupportedObjectExceptionMessage = Unsupported object validationOfAnyOfSchemaNotSupportedExceptionMessage = Validation of a schema that includes 'anyof' is not supported. validationOfOneOfSchemaNotSupportedExceptionMessage = Validation of a schema that includes 'oneof' is not supported. cannotCreatePropertyWithoutTypeExceptionMessage = Cannot create the property because no type is defined. -paramsNoAdditionalPropertiesExclusiveExceptionMessage = Params 'NoAdditionalProperties' and 'AdditionalProperties' are mutually exclusive. headerMustHaveNameInEncodingContextExceptionMessage = Header must have a name when used in an encoding context. descriptionRequiredExceptionMessage = A Description is required. openApiDocumentNotCompliantExceptionMessage = OpenAPI document is not compliant. @@ -166,9 +164,7 @@ cannotSupplyIntervalForQuarterExceptionMessage = Cannot supply interval value fo cannotSupplyIntervalForYearExceptionMessage = Cannot supply interval value for every year. secretVaultAlreadyRegisteredExceptionMessage = A Secret Vault with the name '{0}' has already been registered{1}. secretVaultUnlockExpiryDateInPastExceptionMessage = Secret Vault unlock expiry date is in the past (UTC): {0} -secretAlreadyMountedExceptionMessage = A Secret with the name '{0}' has already been mounted -noSecretVaultRegisteredExceptionMessage = No Secret Vault with the name '{0}' has been registered -noAdditionalPropertiesMutuallyExclusiveExceptionMessage = Parameters 'NoAdditionalProperties' and 'AdditionalProperties' are mutually exclusive. +secretAlreadyMountedExceptionMessage = A Secret with the name '{0}' has already been mounted. credentialsPassedWildcardForHeadersLiteralExceptionMessage = When Credentials is passed, The * wildcard for Headers will be taken as a literal string and not a wildcard. wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = The * wildcard for Headers is incompatible with the AutoHeaders switch. wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = The * wildcard for Methods is incompatible with the AutoMethods switch. @@ -178,4 +174,42 @@ noNameForWebSocketRemoveExceptionMessage = No Name for a WebSocket to remove sup noNameForWebSocketSendMessageExceptionMessage = No Name for a WebSocket to send message to supplied. noSecretNamedMountedExceptionMessage = No Secret named '{0}' has been mounted. noNameForWebSocketResetExceptionMessage = No Name for a WebSocket to reset supplied. +schemaValidationRequiresPowerShell610ExceptionMessage = Schema validation required PowerShell version 6.1.0 or greater. +routeParameterCannotBeNullExceptionMessage = The parameter 'Route' cannot be null. +encodingAttributeOnlyAppliesToMultipartExceptionMessage = The encoding attribute only applies to multipart and application/x-www-form-urlencoded request bodies. +testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentchema' need to be enabled using 'Enable-PodeOpenApi -EnableSchemaValidation' +openApiComponentSchemaDoesNotExistExceptionMessage = The OpenApi component schema {0} doesn't exist. +openApiParameterRequiresNameExceptionMessage = The OpenApi parameter requires a name to be specified. +openApiLicenseObjectRequiresNameExceptionMessage = The OpenAPI object 'license' required the property 'name'. Use -LicenseName parameter. +parametersValueOrExternalValueMandatoryExceptionMessage = Parameters 'Value' or 'ExternalValue' are mandatory +parametersMutuallyExclusiveExceptionMessage = Parameters '{0}' and '{1}' are mutually exclusive. +maximumConcurrentWebSocketThreadsInvalidExceptionMessage = Maximum concurrent WebSocket threads must be >=1 but got: {0} +maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = Maximum concurrent WebSocket threads cannot be less than the minimum of {0} but got: {1} +alreadyConnectedToWebSocketExceptionMessage = Already connected to websocket with name '{0}' +failedToConnectToWebSocketExceptionMessage = Failed to connect to websocket: {0} +verbNoLogicPassedExceptionMessage = [Verb] {0}: No logic passed +scriptPathDoesNotExistExceptionMessage = The script path does not exist: {0} +failedToImportModuleExceptionMessage = Failed to import module: {0} +modulePathDoesNotExistExceptionMessage = The module path does not exist: {0} +defaultValueNotBooleanOrEnumExceptionMessage = The default value is not a boolean and is not part of the enum. +propertiesTypeObjectAssociationExceptionMessage = Only properties of type Object can be associated with {0}. +invalidContentTypeForSchemaExceptionMessage = Invalid 'content-type' found for schema: {0} +openApiRequestStyleInvalidForParameterExceptionMessage = OpenApi request Style cannot be {0} for a {1} parameter. +pathParameterRequiresRequiredSwitchExceptionMessage = If the parameter location is 'Path', the switch parameter 'Required' is mandatory. +operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0} has to be unique and cannot be applied to an array. +operationIdMustBeUniqueExceptionMessage = OperationID: {0} has to be unique. +noOpenApiUrlSuppliedExceptionMessage = No OpenAPI URL supplied for {0}. +noTitleSuppliedForPageExceptionMessage = No title supplied for {0} page. +noRoutePathSuppliedForPageExceptionMessage = No route path supplied for {0} page. +swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = This version on Swagger-Editor doesn't support OpenAPI 3.1 +rapidPdfDoesNotSupportOpenApi31ExceptionMessage = The Document tool RapidPdf doesn't support OpenAPI 3.1 +definitionTagNotDefinedExceptionMessage = DefinitionTag {0} does not exist. +scopedVariableNotFoundExceptionMessage = Scoped Variable not found: {0} +noSecretVaultRegisteredExceptionMessage = No Secret Vault with the name '{0}' has been registered. +invalidStrictTransportSecurityDurationExceptionMessage = Invalid Strict-Transport-Security duration supplied: {0}. It should be greater than 0. +durationMustBeZeroOrGreaterExceptionMessage = Duration must be 0 or greater, but got: {0}s +taskAlreadyDefinedExceptionMessage = [Task] {0}: Task already defined. +maximumConcurrentTasksInvalidExceptionMessage = Maximum concurrent tasks must be >=1 but got: {0} +maximumConcurrentTasksLessThanMinimumExceptionMessage = Maximum concurrent tasks cannot be less than the minimum of {0} but got: {1} +taskDoesNotExistExceptionMessage = Task '{0}' does not exist. '@ \ No newline at end of file diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 4524bc327..1569a419c 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -37,7 +37,6 @@ singleValueForIntervalExceptionMessage = Solo puede suministrar un único valor scriptErrorExceptionMessage = Error '{0}' en el script {1} {2} (línea {3}) carácter {4} al ejecutar {5} en el objeto {6} '{7}' Clase: {8} ClaseBase: {9} noScriptBlockSuppliedExceptionMessage = No se suministró ningún ScriptBlock. iisAspnetcoreTokenMissingExceptionMessage = Falta el token IIS ASPNETCORE_TOKEN. -invalidContentTypeForSchemaExceptionMessage = Tipo de contenido no válido encontrado para el esquema: {0} propertiesParameterWithoutNameExceptionMessage = Los parámetros de propiedades no se pueden usar si la propiedad no tiene nombre. multiTypePropertiesRequireOpenApi31ExceptionMessage = Las propiedades de tipo múltiple requieren OpenApi versión 3.1 o superior. openApiVersionPropertyMandatoryExceptionMessage = La propiedad de versión OpenApi es obligatoria. @@ -47,7 +46,6 @@ unsupportedObjectExceptionMessage = Objeto no compatible validationOfAnyOfSchemaNotSupportedExceptionMessage = La validación de un esquema que incluye 'anyof' no es compatible. validationOfOneOfSchemaNotSupportedExceptionMessage = La validación de un esquema que incluye 'oneof' no es compatible. cannotCreatePropertyWithoutTypeExceptionMessage = No se puede crear la propiedad porque no se ha definido ningún tipo. -paramsNoAdditionalPropertiesExclusiveExceptionMessage = Los parámetros -NoAdditionalProperties y -AdditionalProperties son mutuamente excluyentes. headerMustHaveNameInEncodingContextExceptionMessage = El encabezado debe tener un nombre cuando se usa en un contexto de codificación. descriptionRequiredExceptionMessage = Se requiere una descripción. openApiDocumentNotCompliantExceptionMessage = El documento OpenAPI no cumple con las normas. @@ -167,8 +165,6 @@ cannotSupplyIntervalForYearExceptionMessage = No se puede proporcionar un valor secretVaultAlreadyRegisteredExceptionMessage = Un Cofre de Secretos con el nombre '{0}' ya ha sido registrado{1}. secretVaultUnlockExpiryDateInPastExceptionMessage = La fecha de expiración para desbloquear el Cofre de Secretos está en el pasado (UTC): {0} secretAlreadyMountedExceptionMessage = Un Secreto con el nombre '{0}' ya ha sido montado. -noSecretVaultRegisteredExceptionMessage = No se ha registrado ningún Cofre de Secretos con el nombre '{0}'. -noAdditionalPropertiesMutuallyExclusiveExceptionMessage = Los parámetros 'NoAdditionalProperties' y 'AdditionalProperties' son mutuamente excluyentes. credentialsPassedWildcardForHeadersLiteralExceptionMessage = Cuando se pasan las Credenciales, el comodín * para los Encabezados se tomará como una cadena literal y no como un comodín. wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = El comodín * para los Encabezados es incompatible con el interruptor AutoHeaders. wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = El comodín * para los Métodos es incompatible con el interruptor AutoMethods. @@ -178,4 +174,42 @@ noNameForWebSocketRemoveExceptionMessage = No se proporcionó ningún nombre par noNameForWebSocketSendMessageExceptionMessage = No se proporcionó ningún nombre para enviar un mensaje al WebSocket. noSecretNamedMountedExceptionMessage = No se ha montado ningún Secreto con el nombre '{0}'. noNameForWebSocketResetExceptionMessage = No se proporcionó ningún nombre para restablecer el WebSocket. +schemaValidationRequiresPowerShell610ExceptionMessage = La validación del esquema requiere PowerShell versión 6.1.0 o superior. +routeParameterCannotBeNullExceptionMessage = El parámetro 'Route' no puede ser nulo. +encodingAttributeOnlyAppliesToMultipartExceptionMessage = El atributo de codificación solo se aplica a cuerpos de solicitud multipart y application/x-www-form-urlencoded. +testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema' necesita ser habilitado usando 'Enable-PodeOpenApi -EnableSchemaValidation' +openApiComponentSchemaDoesNotExistExceptionMessage = El esquema del componente OpenApi {0} no existe. +openApiParameterRequiresNameExceptionMessage = El parámetro OpenApi requiere un nombre especificado. +openApiLicenseObjectRequiresNameExceptionMessage = El objeto OpenAPI 'license' requiere la propiedad 'name'. Use el parámetro -LicenseName. +parametersValueOrExternalValueMandatoryExceptionMessage = Los parámetros 'Value' o 'ExternalValue' son obligatorios. +parametersMutuallyExclusiveExceptionMessage = Los parámetros '{0}' y '{1}' son mutuamente excluyentes. +maximumConcurrentWebSocketThreadsInvalidExceptionMessage = El número máximo de hilos concurrentes de WebSocket debe ser >=1, pero se obtuvo: {0} +maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = El número máximo de hilos concurrentes de WebSocket no puede ser menor que el mínimo de {0}, pero se obtuvo: {1} +alreadyConnectedToWebSocketExceptionMessage = Ya conectado al WebSocket con el nombre '{0}' +failedToConnectToWebSocketExceptionMessage = Error al conectar con el WebSocket: {0} +verbNoLogicPassedExceptionMessage = [Verbo] {0}: No se pasó ninguna lógica +scriptPathDoesNotExistExceptionMessage = La ruta del script no existe: {0} +failedToImportModuleExceptionMessage = Error al importar el módulo: {0} +modulePathDoesNotExistExceptionMessage = La ruta del módulo no existe: {0} +defaultValueNotBooleanOrEnumExceptionMessage = El valor predeterminado no es un booleano y no forma parte del enum. +propertiesTypeObjectAssociationExceptionMessage = Solo las propiedades de tipo Objeto pueden estar asociadas con {0}. +invalidContentTypeForSchemaExceptionMessage = 'content-type' inválido encontrado para el esquema: {0} +openApiRequestStyleInvalidForParameterExceptionMessage = El estilo de la solicitud OpenApi no puede ser {0} para un parámetro {1}. +pathParameterRequiresRequiredSwitchExceptionMessage = Si la ubicación del parámetro es 'Path', el parámetro switch 'Required' es obligatorio. +operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0} debe ser único y no puede aplicarse a un array. +operationIdMustBeUniqueExceptionMessage = OperationID: {0} debe ser único. +noOpenApiUrlSuppliedExceptionMessage = No se proporcionó URL de OpenAPI para {0}. +noTitleSuppliedForPageExceptionMessage = No se proporcionó título para la página {0}. +noRoutePathSuppliedForPageExceptionMessage = No se proporcionó ruta de acceso para la página {0}. +swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = Esta versión de Swagger-Editor no admite OpenAPI 3.1 +rapidPdfDoesNotSupportOpenApi31ExceptionMessage = La herramienta de documentación RapidPdf no admite OpenAPI 3.1 +definitionTagNotDefinedExceptionMessage = La etiqueta de definición {0} no está definida. +scopedVariableNotFoundExceptionMessage = Variable de alcance no encontrada: {0} +noSecretVaultRegisteredExceptionMessage = No se ha registrado un Cofre de Secretos con el nombre '{0}'. +invalidStrictTransportSecurityDurationExceptionMessage = Duración de Strict-Transport-Security no válida proporcionada: {0}. Debe ser mayor que 0. +durationMustBeZeroOrGreaterExceptionMessage = La duración debe ser igual o mayor a 0, pero se obtuvo: {0}s +taskAlreadyDefinedExceptionMessage = [Tarea] {0}: Tarea ya definida. +maximumConcurrentTasksInvalidExceptionMessage = El número máximo de tareas concurrentes debe ser >=1, pero se obtuvo: {0} +maximumConcurrentTasksLessThanMinimumExceptionMessage = El número máximo de tareas concurrentes no puede ser menor que el mínimo de {0}, pero se obtuvo: {1} +taskDoesNotExistExceptionMessage = La tarea '{0}' no existe. '@ diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index c231b7891..7dd7e8a5e 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -37,7 +37,6 @@ singleValueForIntervalExceptionMessage = Vous ne pouvez fournir qu'une seule val scriptErrorExceptionMessage = Erreur '{0}' dans le script {1} {2} (ligne {3}) char {4} en exécutant {5} sur l'objet {6} '{7}' Classe : {8} ClasseBase : {9} noScriptBlockSuppliedExceptionMessage = Aucun ScriptBlock fourni. iisAspnetcoreTokenMissingExceptionMessage = Le jeton IIS ASPNETCORE_TOKEN est manquant. -invalidContentTypeForSchemaExceptionMessage = Type de contenu non valide trouvé pour le schéma : {0} propertiesParameterWithoutNameExceptionMessage = Les paramètres Properties ne peuvent pas être utilisés si la propriété n'a pas de nom. multiTypePropertiesRequireOpenApi31ExceptionMessage = Les propriétés multi-types nécessitent OpenApi Version 3.1 ou supérieure. openApiVersionPropertyMandatoryExceptionMessage = La propriété Version OpenApi est obligatoire. @@ -47,7 +46,6 @@ unsupportedObjectExceptionMessage = Objet non pris en charge validationOfAnyOfSchemaNotSupportedExceptionMessage = La validation d'un schéma qui inclut 'anyof' n'est pas prise en charge. validationOfOneOfSchemaNotSupportedExceptionMessage = La validation d'un schéma qui inclut 'oneof' n'est pas prise en charge. cannotCreatePropertyWithoutTypeExceptionMessage = Impossible de créer la propriété car aucun type n'est défini. -paramsNoAdditionalPropertiesExclusiveExceptionMessage = Les paramètres -NoAdditionalProperties et -AdditionalProperties sont mutuellement exclusifs. headerMustHaveNameInEncodingContextExceptionMessage = L'en-tête doit avoir un nom lorsqu'il est utilisé dans un contexte de codage. descriptionRequiredExceptionMessage = Une description est requise. openApiDocumentNotCompliantExceptionMessage = Le document OpenAPI n'est pas conforme. @@ -167,8 +165,6 @@ cannotSupplyIntervalForYearExceptionMessage = Impossible de fournir une valeur d secretVaultAlreadyRegisteredExceptionMessage = Un Coffre-Fort de Secrets avec le nom '{0}' a déjà été enregistré{1}. secretVaultUnlockExpiryDateInPastExceptionMessage = La date d'expiration du déverrouillage du Coffre-Fort de Secrets est dans le passé (UTC) : {0} secretAlreadyMountedExceptionMessage = Un Secret avec le nom '{0}' a déjà été monté. -noSecretVaultRegisteredExceptionMessage = Aucun Coffre-Fort de Secrets avec le nom '{0}' n'a été enregistré. -noAdditionalPropertiesMutuallyExclusiveExceptionMessage = Les paramètres 'NoAdditionalProperties' et 'AdditionalProperties' sont mutuellement exclusifs. credentialsPassedWildcardForHeadersLiteralExceptionMessage = Lorsque des Identifiants sont passés, le caractère générique * pour les En-têtes sera pris comme une chaîne littérale et non comme un caractère générique. wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = Le caractère générique * pour les En-têtes est incompatible avec le commutateur AutoHeaders. wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = Le caractère générique * pour les Méthodes est incompatible avec le commutateur AutoMethods. @@ -178,4 +174,42 @@ noNameForWebSocketRemoveExceptionMessage = Aucun Nom fourni pour supprimer le We noNameForWebSocketSendMessageExceptionMessage = Aucun Nom fourni pour envoyer un message au WebSocket. noSecretNamedMountedExceptionMessage = Aucun Secret nommé '{0}' n'a été monté. noNameForWebSocketResetExceptionMessage = Aucun Nom fourni pour réinitialiser le WebSocket. +schemaValidationRequiresPowerShell610ExceptionMessage = La validation du schéma nécessite PowerShell version 6.1.0 ou supérieure. +routeParameterCannotBeNullExceptionMessage = Le paramètre 'Route' ne peut pas être nul. +encodingAttributeOnlyAppliesToMultipartExceptionMessage = L'attribut d'encodage s'applique uniquement aux corps de requête multipart et application/x-www-form-urlencoded. +testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema' doit être activé en utilisant 'Enable-PodeOpenApi -EnableSchemaValidation' +openApiComponentSchemaDoesNotExistExceptionMessage = Le schéma du composant OpenApi {0} n'existe pas. +openApiParameterRequiresNameExceptionMessage = Le paramètre OpenApi nécessite un nom spécifié. +openApiLicenseObjectRequiresNameExceptionMessage = L'objet OpenAPI 'license' nécessite la propriété 'name'. Utilisez le paramètre -LicenseName. +parametersValueOrExternalValueMandatoryExceptionMessage = Les paramètres 'Value' ou 'ExternalValue' sont obligatoires. +parametersMutuallyExclusiveExceptionMessage = Les paramètres '{0}' et '{1}' sont mutuellement exclusifs. +maximumConcurrentWebSocketThreadsInvalidExceptionMessage = Le nombre maximum de threads WebSocket simultanés doit être >=1, mais a obtenu : {0} +maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = Le nombre maximum de threads WebSocket simultanés ne peut pas être inférieur au minimum de {0}, mais a obtenu : {1} +alreadyConnectedToWebSocketExceptionMessage = Déjà connecté au WebSocket avec le nom '{0}' +failedToConnectToWebSocketExceptionMessage = Échec de la connexion au WebSocket : {0} +verbNoLogicPassedExceptionMessage = [Verbe] {0} : Aucune logique transmise +scriptPathDoesNotExistExceptionMessage = Le chemin du script n'existe pas : {0} +failedToImportModuleExceptionMessage = Échec de l'importation du module : {0} +modulePathDoesNotExistExceptionMessage = Le chemin du module n'existe pas : {0} +defaultValueNotBooleanOrEnumExceptionMessage = La valeur par défaut n'est pas un booléen et ne fait pas partie de l'énumération. +propertiesTypeObjectAssociationExceptionMessage = Seules les propriétés de type Objet peuvent être associées à {0}. +invalidContentTypeForSchemaExceptionMessage = 'content-type' invalide trouvé pour le schéma : {0} +openApiRequestStyleInvalidForParameterExceptionMessage = Le style de la requête OpenApi ne peut pas être {0} pour un paramètre {1}. +pathParameterRequiresRequiredSwitchExceptionMessage = Si l'emplacement du paramètre est 'Path', le paramètre switch 'Required' est obligatoire. +operationIdMustBeUniqueForArrayExceptionMessage = OperationID : {0} doit être unique et ne peut pas être appliqué à un tableau. +operationIdMustBeUniqueExceptionMessage = OperationID : {0} doit être unique. +noOpenApiUrlSuppliedExceptionMessage = Aucune URL OpenAPI fournie pour {0}. +noTitleSuppliedForPageExceptionMessage = Aucun titre fourni pour la page {0}. +noRoutePathSuppliedForPageExceptionMessage = Aucun chemin de route fourni pour la page {0}. +swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = Cette version de Swagger-Editor ne prend pas en charge OpenAPI 3.1 +rapidPdfDoesNotSupportOpenApi31ExceptionMessage = L'outil de documentation RapidPdf ne prend pas en charge OpenAPI 3.1 +definitionTagNotDefinedExceptionMessage = Tag de définition {0} non défini. +scopedVariableNotFoundExceptionMessage = Variable d'étendue non trouvée : {0} +noSecretVaultRegisteredExceptionMessage = Aucun coffre-fort de secrets enregistré sous le nom '{0}'. +invalidStrictTransportSecurityDurationExceptionMessage = Durée Strict-Transport-Security invalide fournie : {0}. Doit être supérieure à 0. +durationMustBeZeroOrGreaterExceptionMessage = La durée doit être égale ou supérieure à 0, mais a obtenu : {0}s +taskAlreadyDefinedExceptionMessage = [Tâche] {0} : Tâche déjà définie. +maximumConcurrentTasksInvalidExceptionMessage = Le nombre maximum de tâches simultanées doit être >=1, mais a obtenu : {0} +maximumConcurrentTasksLessThanMinimumExceptionMessage = Le nombre maximum de tâches simultanées ne peut pas être inférieur au minimum de {0}, mais a obtenu : {1} +taskDoesNotExistExceptionMessage = La tâche '{0}' n'existe pas. '@ diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index 87316e090..ea28f0900 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -37,7 +37,6 @@ singleValueForIntervalExceptionMessage = Puoi fornire solo un singolo valore {0} scriptErrorExceptionMessage = Errore '{0}' nello script {1} {2} (riga {3}) carattere {4} eseguendo {5} su {6} oggetto '{7}' Classe: {8} Classe di base: {9} noScriptBlockSuppliedExceptionMessage = Nessun ScriptBlock fornito. iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN è mancante. -invalidContentTypeForSchemaExceptionMessage = Tipo di contenuto non valido trovato per lo schema: {0} propertiesParameterWithoutNameExceptionMessage = I parametri Properties non possono essere utilizzati se la proprietà non ha un nome. multiTypePropertiesRequireOpenApi31ExceptionMessage = Le proprietà multi-tipo richiedono OpenApi versione 3.1 o superiore. openApiVersionPropertyMandatoryExceptionMessage = La proprietà della versione OpenApi è obbligatoria. @@ -47,7 +46,6 @@ unsupportedObjectExceptionMessage = Oggetto non supportato validationOfAnyOfSchemaNotSupportedExceptionMessage = La validazione di uno schema che include 'anyof' non è supportata. validationOfOneOfSchemaNotSupportedExceptionMessage = La validazione di uno schema che include 'oneof' non è supportata. cannotCreatePropertyWithoutTypeExceptionMessage = Impossibile creare la proprietà perché non è definito alcun tipo. -paramsNoAdditionalPropertiesExclusiveExceptionMessage = I parametri -NoAdditionalProperties e -AdditionalProperties si escludono a vicenda. headerMustHaveNameInEncodingContextExceptionMessage = L'intestazione deve avere un nome quando viene utilizzata in un contesto di codifica. descriptionRequiredExceptionMessage = È necessaria una descrizione. openApiDocumentNotCompliantExceptionMessage = Il documento OpenAPI non è conforme. @@ -167,8 +165,6 @@ cannotSupplyIntervalForYearExceptionMessage = Impossibile fornire un valore di i secretVaultAlreadyRegisteredExceptionMessage = Un Vault dei Segreti con il nome '{0}' è già stato registrato{1}. secretVaultUnlockExpiryDateInPastExceptionMessage = La data di scadenza per sbloccare il Vault dei Segreti è nel passato (UTC): {0} secretAlreadyMountedExceptionMessage = Un Segreto con il nome '{0}' è già stato montato. -noSecretVaultRegisteredExceptionMessage = Nessun Vault dei Segreti con il nome '{0}' è stato registrato. -noAdditionalPropertiesMutuallyExclusiveExceptionMessage = I parametri 'NoAdditionalProperties' e 'AdditionalProperties' sono mutuamente esclusivi. credentialsPassedWildcardForHeadersLiteralExceptionMessage = Quando vengono passate le Credenziali, il carattere jolly * per le Intestazioni sarà considerato come una stringa letterale e non come un carattere jolly. wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = Il carattere jolly * per le Intestazioni è incompatibile con l'opzione AutoHeaders. wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = Il carattere jolly * per i Metodi è incompatibile con l'opzione AutoMethods. @@ -178,4 +174,42 @@ noNameForWebSocketRemoveExceptionMessage = Nessun nome fornito per rimuovere il noNameForWebSocketSendMessageExceptionMessage = Nessun nome fornito per inviare un messaggio al WebSocket. noSecretNamedMountedExceptionMessage = Nessun Segreto con il nome '{0}' è stato montato. noNameForWebSocketResetExceptionMessage = Nessun nome fornito per reimpostare il WebSocket. +schemaValidationRequiresPowerShell610ExceptionMessage = La convalida dello schema richiede PowerShell versione 6.1.0 o superiore. +routeParameterCannotBeNullExceptionMessage = Il parametro 'Route' non può essere null. +encodingAttributeOnlyAppliesToMultipartExceptionMessage = L'attributo di codifica si applica solo ai corpi delle richieste multipart e application/x-www-form-urlencoded. +testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema' deve essere abilitato utilizzando 'Enable-PodeOpenApi -EnableSchemaValidation' +openApiComponentSchemaDoesNotExistExceptionMessage = Lo schema del componente OpenApi {0} non esiste. +openApiParameterRequiresNameExceptionMessage = Il parametro OpenApi richiede un nome specificato. +openApiLicenseObjectRequiresNameExceptionMessage = L'oggetto OpenAPI 'license' richiede la proprietà 'name'. Utilizzare il parametro -LicenseName. +parametersValueOrExternalValueMandatoryExceptionMessage = I parametri 'Value' o 'ExternalValue' sono obbligatori. +parametersMutuallyExclusiveExceptionMessage = I parametri '{0}' e '{1}' sono mutuamente esclusivi. +maximumConcurrentWebSocketThreadsInvalidExceptionMessage = Il numero massimo di thread WebSocket simultanei deve essere >=1, ma è stato ottenuto: {0} +maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = Il numero massimo di thread WebSocket simultanei non può essere inferiore al minimo di {0}, ma è stato ottenuto: {1} +alreadyConnectedToWebSocketExceptionMessage = Già connesso al WebSocket con il nome '{0}' +failedToConnectToWebSocketExceptionMessage = Connessione al WebSocket non riuscita: {0} +verbNoLogicPassedExceptionMessage = [Verbo] {0}: Nessuna logica passata +scriptPathDoesNotExistExceptionMessage = Il percorso dello script non esiste: {0} +failedToImportModuleExceptionMessage = Importazione del modulo non riuscita: {0} +modulePathDoesNotExistExceptionMessage = Il percorso del modulo non esiste: {0} +defaultValueNotBooleanOrEnumExceptionMessage = Il valore predefinito non è un booleano e non fa parte dell'enum. +propertiesTypeObjectAssociationExceptionMessage = Solo le proprietà di tipo Oggetto possono essere associate a {0}. +invalidContentTypeForSchemaExceptionMessage = 'content-type' non valido trovato per lo schema: {0} +openApiRequestStyleInvalidForParameterExceptionMessage = Lo stile della richiesta OpenApi non può essere {0} per un parametro {1}. +pathParameterRequiresRequiredSwitchExceptionMessage = Se la posizione del parametro è 'Path', il parametro switch 'Required' è obbligatorio. +operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0} deve essere univoco e non può essere applicato a una matrice. +operationIdMustBeUniqueExceptionMessage = OperationID: {0} deve essere univoco. +noOpenApiUrlSuppliedExceptionMessage = Nessun URL OpenAPI fornito per {0}. +noTitleSuppliedForPageExceptionMessage = Nessun titolo fornito per la pagina {0}. +noRoutePathSuppliedForPageExceptionMessage = Nessun percorso di rotta fornito per la pagina {0}. +swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = Questa versione di Swagger-Editor non supporta OpenAPI 3.1 +rapidPdfDoesNotSupportOpenApi31ExceptionMessage = Lo strumento di documentazione RapidPdf non supporta OpenAPI 3.1 +definitionTagNotDefinedExceptionMessage = Tag di definizione {0} non definito. +scopedVariableNotFoundExceptionMessage = Variabile di ambito non trovata: {0} +noSecretVaultRegisteredExceptionMessage = Nessun Vault dei Segreti con il nome '{0}' è stato registrato. +invalidStrictTransportSecurityDurationExceptionMessage = Durata Strict-Transport-Security non valida fornita: {0}. Deve essere maggiore di 0. +durationMustBeZeroOrGreaterExceptionMessage = La durata deve essere 0 o superiore, ma è stato ottenuto: {0}s +taskAlreadyDefinedExceptionMessage = [Attività] {0}: Attività già definita. +maximumConcurrentTasksInvalidExceptionMessage = Il numero massimo di attività simultanee deve essere >=1, ma è stato ottenuto: {0} +maximumConcurrentTasksLessThanMinimumExceptionMessage = Il numero massimo di attività simultanee non può essere inferiore al minimo di {0}, ma è stato ottenuto: {1} +taskDoesNotExistExceptionMessage = L'attività '{0}' non esiste. '@ diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index d5dc10f5b..ca3ca814d 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -37,7 +37,6 @@ singleValueForIntervalExceptionMessage = インターバルを使用する場合 scriptErrorExceptionMessage = スクリプト{1} {2}(行{3})のエラー'{0}'(文字{4})が{6}オブジェクト'{7}'の{5}を実行中に発生しました クラス: {8} 基底クラス: {9} noScriptBlockSuppliedExceptionMessage = ScriptBlockが提供されていません。 iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKENがありません。 -invalidContentTypeForSchemaExceptionMessage = スキーマに対して無効なコンテンツタイプが見つかりました: {0} propertiesParameterWithoutNameExceptionMessage = プロパティに名前がない場合、プロパティパラメータは使用できません。 multiTypePropertiesRequireOpenApi31ExceptionMessage = 複数タイプのプロパティはOpenApiバージョン3.1以上が必要です。 openApiVersionPropertyMandatoryExceptionMessage = OpenApiバージョンプロパティは必須です。 @@ -47,7 +46,6 @@ unsupportedObjectExceptionMessage = サポートされていないオブジェ validationOfAnyOfSchemaNotSupportedExceptionMessage = 'anyof'を含むスキーマの検証はサポートされていません。 validationOfOneOfSchemaNotSupportedExceptionMessage = 'oneof'を含むスキーマの検証はサポートされていません。 cannotCreatePropertyWithoutTypeExceptionMessage = 型が定義されていないため、プロパティを作成できません。 -paramsNoAdditionalPropertiesExclusiveExceptionMessage = パラメータ -NoAdditionalPropertiesと-AdditionalPropertiesは相互に排他です。 headerMustHaveNameInEncodingContextExceptionMessage = エンコーディングコンテキストで使用される場合、ヘッダーには名前が必要です。 descriptionRequiredExceptionMessage = 説明が必要です。 openApiDocumentNotCompliantExceptionMessage = OpenAPIドキュメントが準拠していません。 @@ -167,8 +165,6 @@ cannotSupplyIntervalForYearExceptionMessage = 毎年の間隔値を提供でき secretVaultAlreadyRegisteredExceptionMessage = 名前 '{0}' のシークレットボールトは既に登録されています{1}。 secretVaultUnlockExpiryDateInPastExceptionMessage = シークレットボールトのアンロック有効期限が過去に設定されています (UTC) :{0} secretAlreadyMountedExceptionMessage = 名前 '{0}' のシークレットは既にマウントされています。 -noSecretVaultRegisteredExceptionMessage = 名前 '{0}' のシークレットボールトは登録されていません。 -noAdditionalPropertiesMutuallyExclusiveExceptionMessage = パラメータ 'NoAdditionalProperties' と 'AdditionalProperties' は相互に排他的です。 credentialsPassedWildcardForHeadersLiteralExceptionMessage = 資格情報が渡されると、ヘッダーのワイルドカード * はワイルドカードとしてではなく、リテラル文字列として解釈されます。 wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = ヘッダーのワイルドカード * は AutoHeaders スイッチと互換性がありません。 wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = メソッドのワイルドカード * は AutoMethods スイッチと互換性がありません。 @@ -178,5 +174,42 @@ noNameForWebSocketRemoveExceptionMessage = 削除する WebSocket の名前が noNameForWebSocketSendMessageExceptionMessage = メッセージを送信する WebSocket の名前が指定されていません。 noSecretNamedMountedExceptionMessage = 名前 '{0}' のシークレットはマウントされていません。 noNameForWebSocketResetExceptionMessage = リセットする WebSocket の名前が指定されていません。 +schemaValidationRequiresPowerShell610ExceptionMessage = スキーマ検証には PowerShell バージョン 6.1.0 以上が必要です。 +routeParameterCannotBeNullExceptionMessage = パラメータ 'Route' は null ではいけません。 +encodingAttributeOnlyAppliesToMultipartExceptionMessage = エンコーディング属性は、multipart および application/x-www-form-urlencoded リクエストボディにのみ適用されます。 +testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema' は 'Enable-PodeOpenApi -EnableSchemaValidation' を使用して有効にする必要があります。 +openApiComponentSchemaDoesNotExistExceptionMessage = OpenApi コンポーネントスキーマ {0} は存在しません。 +openApiParameterRequiresNameExceptionMessage = OpenApi パラメータには名前が必要です。 +openApiLicenseObjectRequiresNameExceptionMessage = OpenAPI オブジェクト 'license' には 'name' プロパティが必要です。-LicenseName パラメータを使用してください。 +parametersValueOrExternalValueMandatoryExceptionMessage = パラメータ 'Value' または 'ExternalValue' は必須です。 +parametersMutuallyExclusiveExceptionMessage = パラメータ '{0}' と '{1}' は互いに排他的です。 +maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 最大同時 WebSocket スレッド数は >=1 でなければなりませんが、取得した値は: {0} +maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 最大同時 WebSocket スレッド数は最小値 {0} より小さくてはいけませんが、取得した値は: {1} +alreadyConnectedToWebSocketExceptionMessage = 名前 '{0}' の WebSocket に既に接続されています +failedToConnectToWebSocketExceptionMessage = WebSocket への接続に失敗しました: {0} +verbNoLogicPassedExceptionMessage = [動詞] {0}: ロジックが渡されていません +scriptPathDoesNotExistExceptionMessage = スクリプトパスが存在しません: {0} +failedToImportModuleExceptionMessage = モジュールのインポートに失敗しました: {0} +modulePathDoesNotExistExceptionMessage = モジュールパスが存在しません: {0} +defaultValueNotBooleanOrEnumExceptionMessage = デフォルト値は boolean ではなく、enum に含まれていません。 +propertiesTypeObjectAssociationExceptionMessage = Object 型のプロパティのみが {0} と関連付けられます。 +invalidContentTypeForSchemaExceptionMessage = スキーマの 'content-type' が無効です: {0} +openApiRequestStyleInvalidForParameterExceptionMessage = OpenApi リクエストのスタイルは {1} パラメータに対して {0} であってはなりません。 +pathParameterRequiresRequiredSwitchExceptionMessage = パラメータの場所が 'Path' の場合、スイッチパラメータ 'Required' は必須です。 +operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0} は一意でなければならず、配列に適用できません。 +operationIdMustBeUniqueExceptionMessage = OperationID: {0} は一意でなければなりません。 +noOpenApiUrlSuppliedExceptionMessage = {0} 用の OpenAPI URL が提供されていません。 +noTitleSuppliedForPageExceptionMessage = {0} ページのタイトルが提供されていません。 +noRoutePathSuppliedForPageExceptionMessage = {0} ページのルートパスが提供されていません。 +swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = このバージョンの Swagger-Editor は OpenAPI 3.1 をサポートしていません +rapidPdfDoesNotSupportOpenApi31ExceptionMessage = ドキュメントツール RapidPdf は OpenAPI 3.1 をサポートしていません +definitionTagNotDefinedExceptionMessage = 定義タグ {0} が定義されていません。 +scopedVariableNotFoundExceptionMessage = スコープ変数が見つかりません: {0} +noSecretVaultRegisteredExceptionMessage = 名前 '{0}' のシークレットボールトは登録されていません。 +invalidStrictTransportSecurityDurationExceptionMessage = 無効な Strict-Transport-Security 期間が指定されました: {0}。0 より大きい必要があります。 +durationMustBeZeroOrGreaterExceptionMessage = 期間は 0 以上でなければなりませんが、取得した値は: {0}s +taskAlreadyDefinedExceptionMessage = [タスク] {0}: タスクは既に定義されています。 +maximumConcurrentTasksInvalidExceptionMessage = 最大同時タスク数は >=1 でなければなりませんが、取得した値は: {0} +maximumConcurrentTasksLessThanMinimumExceptionMessage = 最大同時タスク数は最小値 {0} より少なくてはいけませんが、取得した値は: {1} +taskDoesNotExistExceptionMessage = タスク '{0}' は存在しません。 '@ - diff --git a/src/Locales/kr/Pode.psd1 b/src/Locales/kr/Pode.psd1 index da743cbf7..b97c3b476 100644 --- a/src/Locales/kr/Pode.psd1 +++ b/src/Locales/kr/Pode.psd1 @@ -37,7 +37,6 @@ singleValueForIntervalExceptionMessage = 간격을 사용할 때는 단일 {0} scriptErrorExceptionMessage = 스크립트 {1} {2} (라인 {3}) 문자 {4}에서 {5}을(를) 실행하는 중에 스크립트 {0} 오류가 발생했습니다. 개체 '{7}' 클래스: {8} 기본 클래스: {9} noScriptBlockSuppliedExceptionMessage = ScriptBlock이 제공되지 않았습니다. iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN이 누락되었습니다. -invalidContentTypeForSchemaExceptionMessage = 스키마에 대해 잘못된 콘텐츠 유형이 발견되었습니다: {0} propertiesParameterWithoutNameExceptionMessage = 속성에 이름이 없으면 Properties 매개변수를 사용할 수 없습니다. multiTypePropertiesRequireOpenApi31ExceptionMessage = 다중 유형 속성은 OpenApi 버전 3.1 이상이 필요합니다. openApiVersionPropertyMandatoryExceptionMessage = OpenApi 버전 속성은 필수입니다. @@ -47,7 +46,6 @@ unsupportedObjectExceptionMessage = 지원되지 않는 개체 validationOfAnyOfSchemaNotSupportedExceptionMessage = 'anyof'을 포함하는 스키마의 유효성 검사는 지원되지 않습니다. validationOfOneOfSchemaNotSupportedExceptionMessage = 'oneof'을 포함하는 스키마의 유효성 검사는 지원되지 않습니다. cannotCreatePropertyWithoutTypeExceptionMessage = 유형이 정의되지 않았기 때문에 속성을 생성할 수 없습니다. -paramsNoAdditionalPropertiesExclusiveExceptionMessage = Params -NoAdditionalProperties와 -AdditionalProperties는 서로 배타적입니다. headerMustHaveNameInEncodingContextExceptionMessage = 인코딩 컨텍스트에서 사용될 때 헤더는 이름이 있어야 합니다. descriptionRequiredExceptionMessage = 설명이 필요합니다. openApiDocumentNotCompliantExceptionMessage = OpenAPI 문서는 준수하지 않습니다. @@ -167,8 +165,6 @@ cannotSupplyIntervalForYearExceptionMessage = 매년 간격 값을 제공할 수 secretVaultAlreadyRegisteredExceptionMessage = 이름이 '{0}'인 시크릿 금고가 이미 등록되었습니다{1}. secretVaultUnlockExpiryDateInPastExceptionMessage = 시크릿 금고의 잠금 해제 만료 날짜가 과거입니다 (UTC): {0} secretAlreadyMountedExceptionMessage = 이름이 '{0}'인 시크릿이 이미 마운트되었습니다. -noSecretVaultRegisteredExceptionMessage = 이름이 '{0}'인 시크릿 금고가 등록되지 않았습니다. -noAdditionalPropertiesMutuallyExclusiveExceptionMessage = 'NoAdditionalProperties' 및 'AdditionalProperties' 매개변수는 상호 배타적입니다. credentialsPassedWildcardForHeadersLiteralExceptionMessage = 자격 증명이 전달되면, 헤더에 대한 * 와일드카드는 와일드카드가 아닌 리터럴 문자열로 취급됩니다. wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 헤더에 대한 * 와일드카드는 AutoHeaders 스위치와 호환되지 않습니다. wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 메서드에 대한 * 와일드카드는 AutoMethods 스위치와 호환되지 않습니다. @@ -178,4 +174,42 @@ noNameForWebSocketRemoveExceptionMessage = 제거할 WebSocket의 이름이 제 noNameForWebSocketSendMessageExceptionMessage = 메시지를 보낼 WebSocket의 이름이 제공되지 않았습니다. noSecretNamedMountedExceptionMessage = 이름이 '{0}'인 시크릿이 마운트되지 않았습니다. noNameForWebSocketResetExceptionMessage = 재설정할 WebSocket의 이름이 제공되지 않았습니다. +schemaValidationRequiresPowerShell610ExceptionMessage = 스키마 유효성 검사는 PowerShell 버전 6.1.0 이상이 필요합니다. +routeParameterCannotBeNullExceptionMessage = 'Route' 매개변수는 null일 수 없습니다. +encodingAttributeOnlyAppliesToMultipartExceptionMessage = 인코딩 속성은 multipart 및 application/x-www-form-urlencoded 요청 본문에만 적용됩니다. +testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema'는 'Enable-PodeOpenApi -EnableSchemaValidation'을 사용하여 활성화해야 합니다. +openApiComponentSchemaDoesNotExistExceptionMessage = OpenApi 구성 요소 스키마 {0}이(가) 존재하지 않습니다. +openApiParameterRequiresNameExceptionMessage = OpenApi 매개변수에는 이름이 필요합니다. +openApiLicenseObjectRequiresNameExceptionMessage = OpenAPI 객체 'license'는 'name' 속성이 필요합니다. -LicenseName 매개변수를 사용하십시오. +parametersValueOrExternalValueMandatoryExceptionMessage = 매개변수 'Value' 또는 'ExternalValue'는 필수입니다. +parametersMutuallyExclusiveExceptionMessage = 매개변수 '{0}'와(과) '{1}'는 상호 배타적입니다. +maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 최대 동시 WebSocket 스레드는 >=1이어야 하지만 받은 값: {0} +maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 최대 동시 WebSocket 스레드는 최소값 {0}보다 작을 수 없지만 받은 값: {1} +alreadyConnectedToWebSocketExceptionMessage = 이름이 '{0}'인 WebSocket에 이미 연결되어 있습니다. +failedToConnectToWebSocketExceptionMessage = WebSocket에 연결하지 못했습니다: {0} +verbNoLogicPassedExceptionMessage = [동사] {0}: 전달된 로직 없음 +scriptPathDoesNotExistExceptionMessage = 스크립트 경로가 존재하지 않습니다: {0} +failedToImportModuleExceptionMessage = 모듈을 가져오지 못했습니다: {0} +modulePathDoesNotExistExceptionMessage = 모듈 경로가 존재하지 않습니다: {0} +defaultValueNotBooleanOrEnumExceptionMessage = 기본값이 boolean이 아니며 enum에 속하지 않습니다. +propertiesTypeObjectAssociationExceptionMessage = Object 유형의 속성만 {0}와(과) 연결될 수 있습니다. +invalidContentTypeForSchemaExceptionMessage = 스키마에 대해 잘못된 'content-type'이 발견되었습니다: {0} +openApiRequestStyleInvalidForParameterExceptionMessage = OpenApi 요청 스타일은 {1} 매개변수에 대해 {0}일 수 없습니다. +pathParameterRequiresRequiredSwitchExceptionMessage = 매개변수 위치가 'Path'인 경우 'Required' 스위치 매개변수가 필수입니다. +operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0}은(는) 고유해야 하며 배열에 적용될 수 없습니다. +operationIdMustBeUniqueExceptionMessage = OperationID: {0}은(는) 고유해야 합니다. +noOpenApiUrlSuppliedExceptionMessage = {0}에 대한 OpenAPI URL이 제공되지 않았습니다. +noTitleSuppliedForPageExceptionMessage = {0} 페이지에 대한 제목이 제공되지 않았습니다. +noRoutePathSuppliedForPageExceptionMessage = {0} 페이지에 대한 경로가 제공되지 않았습니다. +swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = 이 버전의 Swagger-Editor는 OpenAPI 3.1을 지원하지 않습니다. +rapidPdfDoesNotSupportOpenApi31ExceptionMessage = 문서 도구 RapidPdf는 OpenAPI 3.1을 지원하지 않습니다. +definitionTagNotDefinedExceptionMessage = 정의 태그 {0}이(가) 정의되지 않았습니다. +scopedVariableNotFoundExceptionMessage = 범위 변수 {0}을(를) 찾을 수 없습니다. +noSecretVaultRegisteredExceptionMessage = 이름이 '{0}'인 비밀 금고가 등록되지 않았습니다. +invalidStrictTransportSecurityDurationExceptionMessage = 잘못된 Strict-Transport-Security 기간이 제공되었습니다: {0}. 0보다 커야 합니다. +durationMustBeZeroOrGreaterExceptionMessage = 기간은 0 이상이어야 하지만 받은 값: {0}s +taskAlreadyDefinedExceptionMessage = [작업] {0}: 작업이 이미 정의되었습니다. +maximumConcurrentTasksInvalidExceptionMessage = 최대 동시 작업 수는 >=1이어야 하지만 받은 값: {0} +maximumConcurrentTasksLessThanMinimumExceptionMessage = 최대 동시 작업 수는 최소값 {0}보다 작을 수 없지만 받은 값: {1} +taskDoesNotExistExceptionMessage = 작업 '{0}'이(가) 존재하지 않습니다. '@ diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index 6c14ac170..ebd68c5f2 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -37,7 +37,6 @@ singleValueForIntervalExceptionMessage = Możesz podać tylko jedną wartość { scriptErrorExceptionMessage = Błąd '{0}' w skrypcie {1} {2} (linia {3}) znak {4} podczas wykonywania {5} na {6} obiekt '{7}' Klasa: {8} Klasa bazowa: {9} noScriptBlockSuppliedExceptionMessage = Nie podano ScriptBlock. iisAspnetcoreTokenMissingExceptionMessage = Brakujący IIS ASPNETCORE_TOKEN. -invalidContentTypeForSchemaExceptionMessage = Znaleziono nieprawidłowy typ zawartości dla schematu: {0} propertiesParameterWithoutNameExceptionMessage = Parametry Properties nie mogą być używane, jeśli właściwość nie ma nazwy. multiTypePropertiesRequireOpenApi31ExceptionMessage = Właściwości wielotypowe wymagają wersji OpenApi 3.1 lub wyższej. openApiVersionPropertyMandatoryExceptionMessage = Właściwość wersji OpenApi jest obowiązkowa. @@ -47,7 +46,6 @@ unsupportedObjectExceptionMessage = Obiekt nieobsługiwany validationOfAnyOfSchemaNotSupportedExceptionMessage = Walidacja schematu, który zawiera 'anyof', nie jest obsługiwana. validationOfOneOfSchemaNotSupportedExceptionMessage = Walidacja schematu, który zawiera 'oneof', nie jest obsługiwana. cannotCreatePropertyWithoutTypeExceptionMessage = Nie można utworzyć właściwości, ponieważ nie zdefiniowano typu. -paramsNoAdditionalPropertiesExclusiveExceptionMessage = Parametry -NoAdditionalProperties i -AdditionalProperties wykluczają się wzajemnie. headerMustHaveNameInEncodingContextExceptionMessage = Nagłówek musi mieć nazwę, gdy jest używany w kontekście kodowania. descriptionRequiredExceptionMessage = Wymagany jest opis. openApiDocumentNotCompliantExceptionMessage = Dokument OpenAPI nie jest zgodny. @@ -167,8 +165,6 @@ cannotSupplyIntervalForYearExceptionMessage = Nie można dostarczyć wartości i secretVaultAlreadyRegisteredExceptionMessage = Skarbiec tajemnic o nazwie '{0}' został już zarejestrowany{1}. secretVaultUnlockExpiryDateInPastExceptionMessage = Data wygaśnięcia odblokowania Skarbca tajemnic jest w przeszłości (UTC): {0} secretAlreadyMountedExceptionMessage = Tajemnica o nazwie '{0}' została już zamontowana. -noSecretVaultRegisteredExceptionMessage = Skarbiec tajemnic o nazwie '{0}' nie został zarejestrowany. -noAdditionalPropertiesMutuallyExclusiveExceptionMessage = Parametry 'NoAdditionalProperties' i 'AdditionalProperties' wykluczają się wzajemnie. credentialsPassedWildcardForHeadersLiteralExceptionMessage = Gdy przekazywane są dane uwierzytelniające, symbol wieloznaczny * dla nagłówków będzie traktowany jako dosłowny ciąg znaków, a nie symbol wieloznaczny. wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = Symbol wieloznaczny * dla nagłówków jest niezgodny z przełącznikiem AutoHeaders. wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = Symbol wieloznaczny * dla metod jest niezgodny z przełącznikiem AutoMethods. @@ -178,4 +174,42 @@ noNameForWebSocketRemoveExceptionMessage = Nie podano nazwy dla usunięcia WebSo noNameForWebSocketSendMessageExceptionMessage = Nie podano nazwy dla wysłania wiadomości do WebSocket. noSecretNamedMountedExceptionMessage = Nie zamontowano tajemnicy o nazwie '{0}'. noNameForWebSocketResetExceptionMessage = Nie podano nazwy dla resetowania WebSocket. +schemaValidationRequiresPowerShell610ExceptionMessage = Walidacja schematu wymaga wersji PowerShell 6.1.0 lub nowszej. +routeParameterCannotBeNullExceptionMessage = Parametr 'Route' nie może być pusty. +encodingAttributeOnlyAppliesToMultipartExceptionMessage = Atrybut kodowania dotyczy tylko ciał żądania typu multipart i application/x-www-form-urlencoded. +testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema' musi być włączony przy użyciu 'Enable-PodeOpenApi -EnableSchemaValidation' +openApiComponentSchemaDoesNotExistExceptionMessage = Schemat komponentu OpenApi {0} nie istnieje. +openApiParameterRequiresNameExceptionMessage = Parametr OpenApi wymaga podania nazwy. +openApiLicenseObjectRequiresNameExceptionMessage = Obiekt OpenAPI 'license' wymaga właściwości 'name'. Użyj parametru -LicenseName. +parametersValueOrExternalValueMandatoryExceptionMessage = Parametry 'Value' lub 'ExternalValue' są obowiązkowe. +parametersMutuallyExclusiveExceptionMessage = Parametry '{0}' i '{1}' są wzajemnie wykluczające się. +maximumConcurrentWebSocketThreadsInvalidExceptionMessage = Maksymalna liczba jednoczesnych wątków WebSocket musi wynosić >=1, ale otrzymano: {0} +maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = Maksymalna liczba jednoczesnych wątków WebSocket nie może być mniejsza niż minimum {0}, ale otrzymano: {1} +alreadyConnectedToWebSocketExceptionMessage = Już połączono z WebSocket o nazwie '{0}' +failedToConnectToWebSocketExceptionMessage = Nie udało się połączyć z WebSocket: {0} +verbNoLogicPassedExceptionMessage = [Czasownik] {0}: Nie przekazano logiki +scriptPathDoesNotExistExceptionMessage = Ścieżka skryptu nie istnieje: {0} +failedToImportModuleExceptionMessage = Nie udało się zaimportować modułu: {0} +modulePathDoesNotExistExceptionMessage = Ścieżka modułu nie istnieje: {0} +defaultValueNotBooleanOrEnumExceptionMessage = Wartość domyślna nie jest typu boolean i nie należy do enum. +propertiesTypeObjectAssociationExceptionMessage = Tylko właściwości typu Object mogą być powiązane z {0}. +invalidContentTypeForSchemaExceptionMessage = Nieprawidłowy 'content-type' znaleziony w schemacie: {0} +openApiRequestStyleInvalidForParameterExceptionMessage = Styl żądania OpenApi nie może być {0} dla parametru {1}. +pathParameterRequiresRequiredSwitchExceptionMessage = Jeśli lokalizacja parametru to 'Path', przełącznik 'Required' jest obowiązkowy. +operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0} musi być unikalny i nie może być zastosowany do tablicy. +operationIdMustBeUniqueExceptionMessage = OperationID: {0} musi być unikalny. +noOpenApiUrlSuppliedExceptionMessage = Nie dostarczono adresu URL OpenAPI dla {0}. +noTitleSuppliedForPageExceptionMessage = Nie dostarczono tytułu dla strony {0}. +noRoutePathSuppliedForPageExceptionMessage = Nie dostarczono ścieżki trasy dla strony {0}. +swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = Ta wersja Swagger-Editor nie obsługuje OpenAPI 3.1 +rapidPdfDoesNotSupportOpenApi31ExceptionMessage = Narzędzie do dokumentów RapidPdf nie obsługuje OpenAPI 3.1 +definitionTagNotDefinedExceptionMessage = Etykieta definicji {0} nie jest zdefiniowana. +scopedVariableNotFoundExceptionMessage = Nie znaleziono zmiennej zakresu: {0} +noSecretVaultRegisteredExceptionMessage = Nie zarejestrowano Skarbca Tajemnic o nazwie '{0}'. +invalidStrictTransportSecurityDurationExceptionMessage = Nieprawidłowy czas trwania Strict-Transport-Security: {0}. Powinien być większy niż 0. +durationMustBeZeroOrGreaterExceptionMessage = Czas trwania musi wynosić 0 lub więcej, ale otrzymano: {0}s +taskAlreadyDefinedExceptionMessage = [Zadanie] {0}: Zadanie już zdefiniowane. +maximumConcurrentTasksInvalidExceptionMessage = Maksymalna liczba jednoczesnych zadań musi wynosić >=1, ale otrzymano: {0} +maximumConcurrentTasksLessThanMinimumExceptionMessage = Maksymalna liczba jednoczesnych zadań nie może być mniejsza niż minimum {0}, ale otrzymano: {1} +taskDoesNotExistExceptionMessage = Zadanie '{0}' nie istnieje. '@ diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index 48f00bae8..6e3852ce3 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -37,7 +37,6 @@ singleValueForIntervalExceptionMessage = Você pode fornecer apenas um único va scriptErrorExceptionMessage = Erro '{0}' no script {1} {2} (linha {3}) caractere {4} executando {5} em {6} objeto '{7}' Classe: {8} ClasseBase: {9} noScriptBlockSuppliedExceptionMessage = Nenhum ScriptBlock fornecido. iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN está ausente. -invalidContentTypeForSchemaExceptionMessage = Tipo de conteúdo inválido encontrado para o esquema: {0} propertiesParameterWithoutNameExceptionMessage = Os parâmetros Properties não podem ser usados se a propriedade não tiver um nome. multiTypePropertiesRequireOpenApi31ExceptionMessage = Propriedades de múltiplos tipos requerem a versão 3.1 ou superior do OpenApi. openApiVersionPropertyMandatoryExceptionMessage = A propriedade da versão do OpenApi é obrigatória. @@ -47,7 +46,6 @@ unsupportedObjectExceptionMessage = Objeto não suportado validationOfAnyOfSchemaNotSupportedExceptionMessage = A validação de um esquema que inclui 'anyof' não é suportada. validationOfOneOfSchemaNotSupportedExceptionMessage = A validação de um esquema que inclui 'oneof' não é suportada. cannotCreatePropertyWithoutTypeExceptionMessage = Não é possível criar a propriedade porque nenhum tipo é definido. -paramsNoAdditionalPropertiesExclusiveExceptionMessage = Os parâmetros -NoAdditionalProperties e -AdditionalProperties se excluem mutuamente. headerMustHaveNameInEncodingContextExceptionMessage = O cabeçalho deve ter um nome quando usado em um contexto de codificação. descriptionRequiredExceptionMessage = É necessária uma descrição. openApiDocumentNotCompliantExceptionMessage = O documento OpenAPI não está em conformidade. @@ -167,8 +165,6 @@ cannotSupplyIntervalForYearExceptionMessage = Não é possível fornecer um valo secretVaultAlreadyRegisteredExceptionMessage = Um Cofre de Segredos com o nome '{0}' já foi registrado{1}. secretVaultUnlockExpiryDateInPastExceptionMessage = A data de expiração de desbloqueio do Cofre de Segredos está no passado (UTC): {0} secretAlreadyMountedExceptionMessage = Um Segredo com o nome '{0}' já foi montado. -noSecretVaultRegisteredExceptionMessage = Nenhum Cofre de Segredos com o nome '{0}' foi registrado. -noAdditionalPropertiesMutuallyExclusiveExceptionMessage = Os parâmetros 'NoAdditionalProperties' e 'AdditionalProperties' são mutuamente exclusivos. credentialsPassedWildcardForHeadersLiteralExceptionMessage = Quando as Credenciais são passadas, o caractere curinga * para os Cabeçalhos será interpretado como uma string literal e não como um caractere curinga. wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = O caractere curinga * para os Cabeçalhos é incompatível com a chave AutoHeaders. wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = O caractere curinga * para os Métodos é incompatível com a chave AutoMethods. @@ -178,4 +174,42 @@ noNameForWebSocketRemoveExceptionMessage = Nenhum nome fornecido para remover o noNameForWebSocketSendMessageExceptionMessage = Nenhum nome fornecido para enviar mensagem ao WebSocket. noSecretNamedMountedExceptionMessage = Nenhum Segredo com o nome '{0}' foi montado. noNameForWebSocketResetExceptionMessage = Nenhum nome fornecido para redefinir o WebSocket. +schemaValidationRequiresPowerShell610ExceptionMessage = A validação do esquema requer a versão 6.1.0 ou superior do PowerShell. +routeParameterCannotBeNullExceptionMessage = O parâmetro 'Route' não pode ser nulo. +encodingAttributeOnlyAppliesToMultipartExceptionMessage = O atributo de codificação só se aplica a corpos de solicitação multipart e application/x-www-form-urlencoded. +testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema' precisa ser habilitado usando 'Enable-PodeOpenApi -EnableSchemaValidation' +openApiComponentSchemaDoesNotExistExceptionMessage = O esquema do componente OpenApi {0} não existe. +openApiParameterRequiresNameExceptionMessage = O parâmetro OpenApi requer um nome especificado. +openApiLicenseObjectRequiresNameExceptionMessage = O objeto OpenAPI 'license' requer a propriedade 'name'. Use o parâmetro -LicenseName. +parametersValueOrExternalValueMandatoryExceptionMessage = Os parâmetros 'Value' ou 'ExternalValue' são obrigatórios. +parametersMutuallyExclusiveExceptionMessage = Os parâmetros '{0}' e '{1}' são mutuamente exclusivos. +maximumConcurrentWebSocketThreadsInvalidExceptionMessage = O número máximo de threads concorrentes do WebSocket deve ser >=1, mas foi obtido: {0} +maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = O número máximo de threads concorrentes do WebSocket não pode ser menor que o mínimo de {0}, mas foi obtido: {1} +alreadyConnectedToWebSocketExceptionMessage = Já conectado ao websocket com o nome '{0}' +failedToConnectToWebSocketExceptionMessage = Falha ao conectar ao websocket: {0} +verbNoLogicPassedExceptionMessage = [Verbo] {0}: Nenhuma lógica passada +scriptPathDoesNotExistExceptionMessage = O caminho do script não existe: {0} +failedToImportModuleExceptionMessage = Falha ao importar módulo: {0} +modulePathDoesNotExistExceptionMessage = O caminho do módulo não existe: {0} +defaultValueNotBooleanOrEnumExceptionMessage = O valor padrão não é booleano e não faz parte do enum. +propertiesTypeObjectAssociationExceptionMessage = Apenas propriedades do tipo Objeto podem ser associadas com {0}. +invalidContentTypeForSchemaExceptionMessage = 'content-type' inválido encontrado para o esquema: {0} +openApiRequestStyleInvalidForParameterExceptionMessage = O estilo da solicitação OpenApi não pode ser {0} para um parâmetro {1}. +pathParameterRequiresRequiredSwitchExceptionMessage = Se a localização do parâmetro for 'Path', o parâmetro de switch 'Required' é obrigatório. +operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0} deve ser único e não pode ser aplicado a uma matriz. +operationIdMustBeUniqueExceptionMessage = OperationID: {0} deve ser único. +noOpenApiUrlSuppliedExceptionMessage = Nenhuma URL do OpenAPI fornecida para {0}. +noTitleSuppliedForPageExceptionMessage = Nenhum título fornecido para a página {0}. +noRoutePathSuppliedForPageExceptionMessage = Nenhum caminho de rota fornecido para a página {0}. +swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = Esta versão do Swagger-Editor não suporta OpenAPI 3.1 +rapidPdfDoesNotSupportOpenApi31ExceptionMessage = A ferramenta de documentos RapidPdf não suporta OpenAPI 3.1 +definitionTagNotDefinedExceptionMessage = A tag de definição {0} não existe. +scopedVariableNotFoundExceptionMessage = Variável de escopo não encontrada: {0} +noSecretVaultRegisteredExceptionMessage = Nenhum Cofre de Segredos com o nome '{0}' foi registrado. +invalidStrictTransportSecurityDurationExceptionMessage = Duração inválida fornecida para Strict-Transport-Security: {0}. Deve ser maior que 0. +durationMustBeZeroOrGreaterExceptionMessage = A duração deve ser 0 ou maior, mas foi obtido: {0}s +taskAlreadyDefinedExceptionMessage = [Tarefa] {0}: Tarefa já definida. +maximumConcurrentTasksInvalidExceptionMessage = O número máximo de tarefas concorrentes deve ser >=1, mas foi obtido: {0} +maximumConcurrentTasksLessThanMinimumExceptionMessage = O número máximo de tarefas concorrentes não pode ser menor que o mínimo de {0}, mas foi obtido: {1} +taskDoesNotExistExceptionMessage = A tarefa '{0}' não existe. '@ diff --git a/src/Locales/zn/Pode.psd1 b/src/Locales/zn/Pode.psd1 index 24551f086..31a057dcd 100644 --- a/src/Locales/zn/Pode.psd1 +++ b/src/Locales/zn/Pode.psd1 @@ -37,7 +37,6 @@ singleValueForIntervalExceptionMessage = 当使用间隔时,只能提供单个 scriptErrorExceptionMessage = 脚本 '{0}' 在 {1} {2} (第 {3} 行) 第 {4} 个字符处执行 {5} 对象 '{7}' 的错误。类: {8} 基类: {9} noScriptBlockSuppliedExceptionMessage = 未提供脚本块。 iisAspnetcoreTokenMissingExceptionMessage = 缺少 IIS ASPNETCORE_TOKEN。 -invalidContentTypeForSchemaExceptionMessage = 为模式找到的内容类型无效: {0} propertiesParameterWithoutNameExceptionMessage = 如果属性没有名称,则不能使用 Properties 参数。 multiTypePropertiesRequireOpenApi31ExceptionMessage = 多类型属性需要 OpenApi 版本 3.1 或更高版本。 openApiVersionPropertyMandatoryExceptionMessage = OpenApi 版本属性是必需的。 @@ -47,7 +46,6 @@ unsupportedObjectExceptionMessage = 不支持的对象 validationOfAnyOfSchemaNotSupportedExceptionMessage = 不支持包含 'anyof' 的模式的验证。 validationOfOneOfSchemaNotSupportedExceptionMessage = 不支持包含 'oneof' 的模式的验证。 cannotCreatePropertyWithoutTypeExceptionMessage = 无法创建属性,因为未定义类型。 -paramsNoAdditionalPropertiesExclusiveExceptionMessage = Params -NoAdditionalProperties 和 -AdditionalProperties 互斥。 headerMustHaveNameInEncodingContextExceptionMessage = 在编码上下文中使用时,标头必须有名称。 descriptionRequiredExceptionMessage = 描述是必需的。 openApiDocumentNotCompliantExceptionMessage = OpenAPI 文档不符合规范。 @@ -167,8 +165,6 @@ cannotSupplyIntervalForYearExceptionMessage = 无法为每年提供间隔值。 secretVaultAlreadyRegisteredExceptionMessage = 名为“{0}”的秘密保险库已注册{1}。 secretVaultUnlockExpiryDateInPastExceptionMessage = 秘密保险库的解锁到期日期已过 (UTC) :{0} secretAlreadyMountedExceptionMessage = 名为“{0}”的秘密已挂载。 -noSecretVaultRegisteredExceptionMessage = 没有注册名为“{0}”的秘密保险库。 -noAdditionalPropertiesMutuallyExclusiveExceptionMessage = 参数 'NoAdditionalProperties' 和 'AdditionalProperties' 是互斥的。 credentialsPassedWildcardForHeadersLiteralExceptionMessage = 传递凭据时,标头的通配符 * 将被视为文字字符串,而不是通配符。 wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 标头的通配符 * 与 AutoHeaders 开关不兼容。 wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 方法的通配符 * 与 AutoMethods 开关不兼容。 @@ -178,4 +174,42 @@ noNameForWebSocketRemoveExceptionMessage = 没有提供要删除的 WebSocket noNameForWebSocketSendMessageExceptionMessage = 没有提供要发送消息的 WebSocket 的名称。 noSecretNamedMountedExceptionMessage = 没有挂载名为“{0}”的秘密。 noNameForWebSocketResetExceptionMessage = 没有提供要重置的 WebSocket 的名称。 +schemaValidationRequiresPowerShell610ExceptionMessage = 架构验证需要 PowerShell 版本 6.1.0 或更高版本。 +routeParameterCannotBeNullExceptionMessage = 参数 'Route' 不能为空。 +encodingAttributeOnlyAppliesToMultipartExceptionMessage = 编码属性仅适用于 multipart 和 application/x-www-form-urlencoded 请求体。 +testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 必须使用 'Enable-PodeOpenApi -EnableSchemaValidation' 启用 'Test-PodeOAComponentSchema'。 +openApiComponentSchemaDoesNotExistExceptionMessage = OpenApi 组件架构 {0} 不存在。 +openApiParameterRequiresNameExceptionMessage = OpenApi 参数需要指定名称。 +openApiLicenseObjectRequiresNameExceptionMessage = OpenAPI 对象 'license' 需要属性 'name'。请使用 -LicenseName 参数。 +parametersValueOrExternalValueMandatoryExceptionMessage = 参数 'Value' 或 'ExternalValue' 是必需的。 +parametersMutuallyExclusiveExceptionMessage = 参数 '{0}' 和 '{1}' 是互斥的。 +maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 最大并发 WebSocket 线程数必须 >=1, 但获得: {0} +maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 最大并发 WebSocket 线程数不能小于最小值 {0},但获得: {1} +alreadyConnectedToWebSocketExceptionMessage = 已连接到名为 '{0}' 的 WebSocket +failedToConnectToWebSocketExceptionMessage = 连接到 WebSocket 失败: {0} +verbNoLogicPassedExceptionMessage = [动词] {0}: 未传递逻辑 +scriptPathDoesNotExistExceptionMessage = 脚本路径不存在: {0} +failedToImportModuleExceptionMessage = 导入模块失败: {0} +modulePathDoesNotExistExceptionMessage = 模块路径不存在: {0} +defaultValueNotBooleanOrEnumExceptionMessage = 默认值不是布尔值且不属于枚举。 +propertiesTypeObjectAssociationExceptionMessage = 只有 Object 类型的属性可以与 {0} 关联。 +invalidContentTypeForSchemaExceptionMessage = 架构中发现无效的 'content-type': {0} +openApiRequestStyleInvalidForParameterExceptionMessage = OpenApi 请求样式不能为 {0},适用于 {1} 参数。 +pathParameterRequiresRequiredSwitchExceptionMessage = 如果参数位置是 'Path',则 'Required' 开关参数是必需的。 +operationIdMustBeUniqueForArrayExceptionMessage = 操作ID: {0} 必须唯一,不能应用于数组。 +operationIdMustBeUniqueExceptionMessage = 操作ID: {0} 必须唯一。 +noOpenApiUrlSuppliedExceptionMessage = 未提供 {0} 的 OpenAPI URL。 +noTitleSuppliedForPageExceptionMessage = 未提供 {0} 页面的标题。 +noRoutePathSuppliedForPageExceptionMessage = 未提供 {0} 页面的路由路径。 +swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = 此版本的 Swagger-Editor 不支持 OpenAPI 3.1 +rapidPdfDoesNotSupportOpenApi31ExceptionMessage = 文档工具 RapidPdf 不支持 OpenAPI 3.1 +definitionTagNotDefinedExceptionMessage = 定义标签 {0} 未定义。 +scopedVariableNotFoundExceptionMessage = 未找到范围变量: {0} +noSecretVaultRegisteredExceptionMessage = 未注册名为 '{0}' 的秘密保险库。 +invalidStrictTransportSecurityDurationExceptionMessage = 提供的严格传输安全持续时间无效: {0}。应大于 0。 +durationMustBeZeroOrGreaterExceptionMessage = 持续时间必须为 0 或更大,但获得: {0}s +taskAlreadyDefinedExceptionMessage = [任务] {0}: 任务已定义。 +maximumConcurrentTasksInvalidExceptionMessage = 最大并发任务数必须 >=1,但获得: {0} +maximumConcurrentTasksLessThanMinimumExceptionMessage = 最大并发任务数不能小于最小值 {0},但获得: {1} +taskDoesNotExistExceptionMessage = 任务 '{0}' 不存在。 '@ diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index 5b5b8db02..26a1c976b 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -1648,8 +1648,8 @@ function New-PodeOAPropertyInternal { if ($Params.ExternalDocs) { $param.externalDocs = $Params.ExternalDocs } if ($Params.NoAdditionalProperties.IsPresent -and $Params.AdditionalProperties) { - # Params -NoAdditionalProperties and -AdditionalProperties are mutually exclusive - throw $PodeLocale.paramsNoAdditionalPropertiesExclusiveExceptionMessage + # Parameters 'NoAdditionalProperties' and 'AdditionalProperties' are mutually exclusive + throw ($PodeLocale.parametersMutuallyExclusiveExceptionMessage -f 'NoAdditionalProperties', 'AdditionalProperties') } else { if ($Params.NoAdditionalProperties.IsPresent) { $param.additionalProperties = $false } diff --git a/src/Public/Core.ps1 b/src/Public/Core.ps1 index 304b3f6f4..6d05729d6 100644 --- a/src/Public/Core.ps1 +++ b/src/Public/Core.ps1 @@ -679,7 +679,8 @@ function Show-PodeGui { if (![string]::IsNullOrWhiteSpace($EndpointName)) { if (!$PodeContext.Server.Endpoints.ContainsKey($EndpointName)) { - throw "Endpoint with name '$($EndpointName)' does not exist" + # Endpoint with name '$EndpointName' does not exist. + throw ($PodeLocale.endpointNameNotExistExceptionMessage -f $EndpointName) } $PodeContext.Server.Gui.Endpoint = $PodeContext.Server.Endpoints[$EndpointName] diff --git a/src/Public/FileWatchers.ps1 b/src/Public/FileWatchers.ps1 index cce9fbd28..142919244 100644 --- a/src/Public/FileWatchers.ps1 +++ b/src/Public/FileWatchers.ps1 @@ -137,7 +137,8 @@ function Add-PodeFileWatcher { # test path to make sure it exists if (!(Test-PodePath $Path -NoStatus)) { - throw "The path does not exist: $($Path)" + # Path does not exist + throw ($PodeLocale.pathNotExistExceptionMessage -f $Path) } # test if we have the file watcher already diff --git a/src/Public/OAProperties.ps1 b/src/Public/OAProperties.ps1 index 64d458ab7..1abd4bd04 100644 --- a/src/Public/OAProperties.ps1 +++ b/src/Public/OAProperties.ps1 @@ -379,7 +379,8 @@ function New-PodeOAMultiTypeProperty { $param.default = $Default } else { - throw "The default value is not a boolean and it's not part of the enum" + # The default value is not a boolean and is not part of the enum + throw $PodeLocale.defaultValueNotBooleanOrEnumExceptionMessage } } } @@ -1398,7 +1399,8 @@ function New-PodeOABoolProperty { $param.default = $Default } else { - throw "The default value is not a boolean and it's not part of the enum" + # The default value is not a boolean and is not part of the enum + throw $PodeLocale.defaultValueNotBooleanOrEnumExceptionMessage } } @@ -1791,7 +1793,8 @@ function Merge-PodeOAProperty { foreach ($schema in $ObjectDefinitions) { if ($schema -is [System.Object[]] -or ($schema -is [hashtable] -and (($schema.type -ine 'object') -and !$schema.object))) { - throw "Only properties of type Object can be associated with $($param.type)" + # Only properties of type Object can be associated with $param.type + throw ($PodeLocale.propertiesTypeObjectAssociationExceptionMessage -f $param.type) } $param.schemas += $schema } diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index 290d4388e..9d8aecacc 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -224,7 +224,8 @@ function Enable-PodeOpenApi { $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.schemaValidation = $EnableSchemaValidation.IsPresent } else { - throw 'Schema validation required Powershell version 6.1.0 or greater' + # Schema validation required PowerShell version 6.1.0 or greater + throw $PodeLocale.schemaValidationRequiresPowerShell610ExceptionMessage } } @@ -613,7 +614,10 @@ function Add-PodeOAResponse { $DefinitionTag ) - if ($null -eq $Route) { throw 'Add-PodeOAResponse - The parameter -Route cannot be NULL.' } + if ($null -eq $Route) { + # The parameter 'Route' cannot be null + throw $PodeLocale.routeParameterCannotBeNullExceptionMessage + } $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag # override status code with default @@ -686,7 +690,10 @@ function Remove-PodeOAResponse { $PassThru ) - if ($null -eq $Route) { throw 'The parameter -Route cannot be NULL.' } + if ($null -eq $Route) { + # The parameter 'Route' cannot be null + throw $PodeLocale.routeParameterCannotBeNullExceptionMessage + } # override status code with default $code = "$($StatusCode)" @@ -747,7 +754,10 @@ function Set-PodeOARequest { $PassThru ) - if ($null -eq $Route) { throw 'Set-PodeOARequest - The parameter -Route cannot be NULL.' } + if ($null -eq $Route) { + # The parameter 'Route' cannot be null + throw $PodeLocale.routeParameterCannotBeNullExceptionMessage + } foreach ($r in @($Route)) { @@ -868,7 +878,8 @@ function New-PodeOARequestBody { $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag if ($Example -and $Examples) { - throw 'Parameter -Examples and -Example are mutually exclusive' + # Parameters 'Examples' and 'Example' are mutually exclusive + throw ($PodeLocale.parametersMutuallyExclusiveExceptionMessage -f 'Example', 'Examples') } $result = @{} foreach ($tag in $DefinitionTag) { @@ -923,7 +934,8 @@ function New-PodeOARequestBody { $param.Content.$($Content.keys[0]).encoding = $r } else { - throw 'The encoding attribute is only applicable to multipart and application/x-www-form-urlencoded request bodies.' + # The encoding attribute only applies to multipart and application/x-www-form-urlencoded request bodies + throw $PodeLocale.encodingAttributeOnlyAppliesToMultipartExceptionMessage } } $result[$tag] = $param @@ -974,7 +986,8 @@ function Test-PodeOAJsonSchemaCompliance { ) if ($DefinitionTag) { if (! ($PodeContext.Server.OpenApi.Definitions.Keys -ccontains $DefinitionTag)) { - throw "DefinitionTag $DefinitionTag is not defined" + # DefinitionTag does not exist. + throw ($PodeLocale.definitionTagNotDefinedExceptionMessage -f $DefinitionTag) } } else { @@ -986,10 +999,12 @@ function Test-PodeOAJsonSchemaCompliance { } if (!$PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.schemaValidation) { - throw 'Test-PodeOAComponentchema need to be enabled using `Enable-PodeOpenApi -EnableSchemaValidation` ' + # 'Test-PodeOAComponentchema' need to be enabled using 'Enable-PodeOpenApi -EnableSchemaValidation' + throw $PodeLocale.testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage } if (!(Test-PodeOAComponentSchemaJson -Name $SchemaReference -DefinitionTag $DefinitionTag)) { - throw "The OpenApi component schema in Json doesn't exist: $SchemaReference" + # The OpenApi component schema doesn't exist + throw ($PodeLocale.openApiComponentSchemaDoesNotExistExceptionMessage -f $SchemaReference) } if ($PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.schemaJson[$SchemaReference].available) { [string[]] $message = @() @@ -1215,7 +1230,8 @@ function ConvertTo-PodeOAParameter { if ($ContentType ) { # ensure all content types are valid if ($ContentType -inotmatch '^[\w-]+\/[\w\.\+-]+$') { - throw "Invalid content-type found for schema: $($type)" + # Invalid 'content-type' found for schema: $type + throw ($PodeLocale.invalidContentTypeForSchemaExceptionMessage -f $type) } $prop.content = [ordered]@{ $ContentType = [ordered]@{ @@ -1239,25 +1255,29 @@ function ConvertTo-PodeOAParameter { switch ($in.ToLower()) { 'path' { if (@('Simple', 'Label', 'Matrix' ) -inotcontains $Style) { - throw "OpenApi request Style cannot be $Style for a $in parameter" + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) } break } 'query' { if (@('Form', 'SpaceDelimited', 'PipeDelimited', 'DeepObject' ) -inotcontains $Style) { - throw "OpenApi request Style cannot be $Style for a $in parameter" + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) } break } 'header' { if (@('Simple' ) -inotcontains $Style) { - throw "OpenApi request Style cannot be $Style for a $in parameter" + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) } break } 'cookie' { if (@('Form' ) -inotcontains $Style) { - throw "OpenApi request Style cannot be $Style for a $in parameter" + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) } break } @@ -1298,7 +1318,8 @@ function ConvertTo-PodeOAParameter { $Name = $Property.name } else { - throw 'Parameter requires a Name' + # The OpenApi parameter requires a name to be specified + throw $PodeLocale.openApiParameterRequiresNameExceptionMessage } } if ($In -ieq 'Header' -and $PodeContext.Server.Security.autoHeaders -and $Name ) { @@ -1328,7 +1349,8 @@ function ConvertTo-PodeOAParameter { } if ($ContentType) { if ($ContentType -inotmatch '^[\w-]+\/[\w\.\+-]+$') { - throw "Invalid content-type found for schema: $($type)" + # Invalid 'content-type' found for schema: $type + throw ($PodeLocale.invalidContentTypeForSchemaExceptionMessage -f $type) } $prop.content = [ordered]@{ $ContentType = [ordered] @{ @@ -1341,7 +1363,8 @@ function ConvertTo-PodeOAParameter { } if ($Example -and $Examples) { - throw '-Example and -Examples are mutually exclusive' + # Parameters 'Examples' and 'Example' are mutually exclusive + throw ($PodeLocale.parametersMutuallyExclusiveExceptionMessage -f 'Examples' , 'Example' ) } if ($AllowEmptyValue.IsPresent ) { $prop['allowEmptyValue'] = $AllowEmptyValue.IsPresent @@ -1373,25 +1396,29 @@ function ConvertTo-PodeOAParameter { switch ($in.ToLower()) { 'path' { if (@('Simple', 'Label', 'Matrix' ) -inotcontains $Style) { - throw "OpenApi request Style cannot be $Style for a $in parameter" + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) } break } 'query' { if (@('Form', 'SpaceDelimited', 'PipeDelimited', 'DeepObject' ) -inotcontains $Style) { - throw "OpenApi request Style cannot be $Style for a $in parameter" + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) } break } 'header' { if (@('Simple' ) -inotcontains $Style) { - throw "OpenApi request Style cannot be $Style for a $in parameter" + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) } break } 'cookie' { if (@('Form' ) -inotcontains $Style) { - throw "OpenApi request Style cannot be $Style for a $in parameter" + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) } break } @@ -1438,7 +1465,8 @@ function ConvertTo-PodeOAParameter { } if ($In -ieq 'Path' -and !$prop.required ) { - Throw "If the parameter location is 'Path', the switch parameter `-Required` is required" + # If the parameter location is 'Path', the switch parameter 'Required' is mandatory + throw $PodeLocale.pathParameterRequiresRequiredSwitchExceptionMessage } return $prop @@ -1518,7 +1546,10 @@ function Set-PodeOARouteInfo { $DefinitionTag ) - if ($null -eq $Route) { throw 'Set-PodeOARouteInfo - The parameter -Route cannot be NULL.' } + if ($null -eq $Route) { + # The parameter 'Route' cannot be null + throw $PodeLocale.routeParameterCannotBeNullExceptionMessage + } $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag @@ -1534,11 +1565,13 @@ function Set-PodeOARouteInfo { } if ($OperationId) { if ($Route.Count -gt 1) { - throw "OperationID:$OperationId has to be unique and cannot be applied to an array." + # OperationID:$OperationId has to be unique and cannot be applied to an array + throw ($PodeLocale.operationIdMustBeUniqueForArrayExceptionMessage -f $OperationId) } foreach ($tag in $DefinitionTag) { if ($PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.operationId -ccontains $OperationId) { - throw "OperationID:$OperationId has to be unique." + # OperationID:$OperationId has to be unique + throw ($PodeLocale.operationIdMustBeUniqueExceptionMessage -f $OperationId) } $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.operationId += $OperationId } @@ -1708,23 +1741,28 @@ function Enable-PodeOAViewer { # error if there's no OpenAPI URL $OpenApiUrl = Protect-PodeValue -Value $OpenApiUrl -Default $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].Path if ([string]::IsNullOrWhiteSpace($OpenApiUrl)) { - throw "No OpenAPI URL supplied for $($Type)" + # No OpenAPI URL supplied for $Type + throw ($PodeLocale.noOpenApiUrlSuppliedExceptionMessage -f $Type) + } # fail if no title $Title = Protect-PodeValue -Value $Title -Default $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].info.Title if ([string]::IsNullOrWhiteSpace($Title)) { - throw "No title supplied for $($Type) page" + # No title supplied for $Type page + throw ($PodeLocale.noTitleSuppliedForPageExceptionMessage -f $Type) } if ($Editor.IsPresent) { # set a default path $Path = Protect-PodeValue -Value $Path -Default '/editor' if ([string]::IsNullOrWhiteSpace($Title)) { - throw "No route path supplied for $($Type) page" + # No route path supplied for $Type page + throw ($PodeLocale.noRoutePathSuppliedForPageExceptionMessage -f $Type) } if (Test-PodeOAVersion -Version 3.1 -DefinitionTag $DefinitionTag) { - throw "This version on Swagger-Editor doesn't support OpenAPI 3.1" + # This version on Swagger-Editor doesn't support OpenAPI 3.1 + throw $PodeLocale.swaggerEditorDoesNotSupportOpenApi31ExceptionMessage } # setup meta info $meta = @{ @@ -1756,7 +1794,8 @@ function Enable-PodeOAViewer { # set a default path $Path = Protect-PodeValue -Value $Path -Default '/bookmarks' if ([string]::IsNullOrWhiteSpace($Title)) { - throw "No route path supplied for $($Type) page" + # No route path supplied for $Type page + throw ($PodeLocale.noRoutePathSuppliedForPageExceptionMessage -f $Type) } # setup meta info $meta = @{ @@ -1797,12 +1836,14 @@ function Enable-PodeOAViewer { } else { if ($Type -ieq 'RapiPdf' -and (Test-PodeOAVersion -Version 3.1 -DefinitionTag $DefinitionTag)) { - throw "The Document tool RapidPdf doesn't support OpenAPI 3.1" + # The Document tool RapidPdf doesn't support OpenAPI 3.1 + throw $PodeLocale.rapidPdfDoesNotSupportOpenApi31ExceptionMessage } # set a default path $Path = Protect-PodeValue -Value $Path -Default "/$($Type.ToLowerInvariant())" if ([string]::IsNullOrWhiteSpace($Title)) { - throw "No route path supplied for $($Type) page" + # No route path supplied for $Type page + throw ($PodeLocale.noRoutePathSuppliedForPageExceptionMessage -f $Type) } # setup meta info $meta = @{ @@ -2106,7 +2147,8 @@ function Add-PodeOAInfo { $Info.license.url = $LicenseUrl } else { - throw 'The OpenAPI property license.name is required. Use -LicenseName' + # The OpenAPI object 'license' required the property 'name'. Use -LicenseName parameter. + throw $PodeLocale.openApiLicenseObjectRequiresNameExceptionMessage } } @@ -2261,7 +2303,8 @@ function New-PodeOAExample { } else { if ( $ExternalValue -and $Value) { - throw '-Value or -ExternalValue are mutually exclusive' + # Parameters 'ExternalValue' and 'Value' are mutually exclusive + throw ($PodeLocale.parametersMutuallyExclusiveExceptionMessage -f 'ExternalValue', 'Value') } $Example = [ordered]@{ } if ($Summary) { @@ -2277,7 +2320,8 @@ function New-PodeOAExample { $Example.externalValue = $ExternalValue } else { - throw '-Value or -ExternalValue are mandatory' + # Parameters 'Value' or 'ExternalValue' are mandatory + throw $PodeLocale.parametersValueOrExternalValueMandatoryExceptionMessage } } $param = [ordered]@{} @@ -2529,7 +2573,10 @@ function Add-PodeOACallBack { $DefinitionTag ) - if ($null -eq $Route) { throw 'Add-PodeOACallBack - The parameter -Route cannot be NULL.' } + if ($null -eq $Route) { + # The parameter 'Route' cannot be null + throw $PodeLocale.routeParameterCannotBeNullExceptionMessage + } $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag @@ -2834,7 +2881,8 @@ function New-PodeOAContentMediaType { $props = [ordered]@{} foreach ($media in $MediaType) { if ($media -inotmatch '^(application|audio|image|message|model|multipart|text|video|\*)\/[\w\.\-\*]+(;[\s]*(charset|boundary)=[\w\.\-\*]+)*$') { - throw "Invalid content-type found for schema: $($media)" + # Invalid 'content-type' found for schema: $media + throw ($PodeLocale.invalidContentTypeForSchemaExceptionMessage -f $media) } if ($Upload.IsPresent) { if ( $media -ieq 'multipart/form-data' -and $Content) { @@ -3150,7 +3198,10 @@ function Add-PodeOAExternalRoute { } 'pipeline' { - if ($null -eq $Route) { throw 'Add-PodeOAExternalRoute - The parameter -Route cannot be NULL.' } + if ($null -eq $Route) { + # The parameter 'Route' cannot be null + throw $PodeLocale.routeParameterCannotBeNullExceptionMessage + } foreach ($r in @($Route)) { $r.OpenApi.Servers = $Servers } @@ -3294,7 +3345,7 @@ function Add-PodeOAWebhook { foreach ($tag in $DefinitionTag) { if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $tag ) { # The Webhooks feature is not supported in OpenAPI v3.0.x - throw $PodeLocal.webhooksFeatureNotSupportedInOpenApi30ExceptionMessage + throw $PodeLocale.webhooksFeatureNotSupportedInOpenApi30ExceptionMessage } $PodeContext.Server.OpenAPI.Definitions[$tag].webhooks[$Name] = $refRoute } @@ -3352,7 +3403,7 @@ function Select-PodeOADefinition { if (Test-PodeIsEmpty $Scriptblock) { # No ScriptBlock supplied - throw $PodeLocal.noScriptBlockSuppliedExceptionMessage + throw $PodeLocale.noScriptBlockSuppliedExceptionMessage } if (Test-PodeIsEmpty -Value $Tag) { $Tag = $PodeContext.Server.OpenAPI.DefaultDefinitionTag @@ -3403,7 +3454,8 @@ function Test-PodeOADefinitionTag { if ($Tag -and $Tag.Count -gt 0) { foreach ($t in $Tag) { if (! ($PodeContext.Server.OpenApi.Definitions.Keys -ccontains $t)) { - throw "DefinitionTag $t is not defined" + # DefinitionTag does not exist. + throw ($PodeLocale.definitionTagNotDefinedExceptionMessage -f $t) } } return $Tag diff --git a/src/Public/ScopedVariables.ps1 b/src/Public/ScopedVariables.ps1 index 35ade7d2a..413999128 100644 --- a/src/Public/ScopedVariables.ps1 +++ b/src/Public/ScopedVariables.ps1 @@ -116,7 +116,8 @@ function Convert-PodeScopedVariable { # check if scoped var defined if (!(Test-PodeScopedVariable -Name $Name)) { - throw "Scoped Variable not found: $($Name)" + # Scoped Variable not found + throw ($PodeLocale.scopedVariableNotFoundExceptionMessage -f $Name) } # get the scoped var metadata diff --git a/src/Public/Secrets.ps1 b/src/Public/Secrets.ps1 index 9425ae00b..ac87f3fa3 100644 --- a/src/Public/Secrets.ps1 +++ b/src/Public/Secrets.ps1 @@ -131,7 +131,7 @@ function Register-PodeSecretVault { $autoImported = ' from auto-importing' } # A Secret Vault with the name {0} has already been registered{1} - throw ($PodeLocal.secretVaultAlreadyRegisteredAutoImportExceptionMessage -f $Name, $autoImported) + throw ($PodeLocale.secretVaultAlreadyRegisteredAutoImportExceptionMessage -f $Name, $autoImported) } # base vault config @@ -262,7 +262,7 @@ function Unlock-PodeSecretVault { # has the vault been registered? if (!(Test-PodeSecretVault -Name $Name)) { # No Secret Vault with the name has been registered - throw ($PodeLocal.noSecretVaultRegisteredExceptionMessage -f $Vault) + throw ($PodeLocale.noSecretVaultRegisteredExceptionMessage -f $Vault) } # get vault @@ -292,7 +292,7 @@ function Unlock-PodeSecretVault { $expiry = ([datetime]$expiry).ToUniversalTime() if ($expiry -le [datetime]::UtcNow) { # Secret Vault unlock expiry date is in the past (UTC) - throw ($PodeLocal.secretVaultUnlockExpiryDateInPastExceptionMessage -f $expiry) + throw ($PodeLocale.secretVaultUnlockExpiryDateInPastExceptionMessage -f $expiry) } $vault.Unlock.Expiry = $expiry @@ -438,18 +438,19 @@ function Mount-PodeSecret { # has the secret been mounted already? if (Test-PodeSecret -Name $Name) { # A Secret with the name has already been mounted - throw ($PodeLocal.secretAlreadyMountedExceptionMessage -f $Name) + throw ($PodeLocale.secretAlreadyMountedExceptionMessage -f $Name) } # does the vault exist? if (!(Test-PodeSecretVault -Name $Vault)) { # No Secret Vault with the name has been registered - throw ($PodeLocal.noSecretVaultRegisteredExceptionMessage -f $Vault) + throw ($PodeLocale.noSecretVaultRegisteredExceptionMessage -f $Vault) } # check properties if (!(Test-PodeIsEmpty $Property) -and !(Test-PodeIsEmpty $ExpandProperty)) { - throw 'You can only provide one of either Property or ExpandPropery, but not both' + # Parameters 'Property' and 'ExpandPropery' are mutually exclusive + throw ($PodeLocale.parametersMutuallyExclusiveExceptionMessage -f 'Property' , 'ExpandPropery') } # which cache value? @@ -513,7 +514,7 @@ function Dismount-PodeSecret { if (!(Test-PodeSecret -Name $Name)) { if ($Remove) { # No Secret named has been mounted - throw ($PodeLocal.noSecretNamedMountedExceptionMessage -f $Name) + throw ($PodeLocale.noSecretNamedMountedExceptionMessage -f $Name) } return @@ -556,7 +557,7 @@ function Get-PodeSecret { # has the secret been mounted? if (!(Test-PodeSecret -Name $Name)) { # No Secret named has been mounted - throw ($PodeLocal.noSecretNamedMountedExceptionMessage -f $Name) + throw ($PodeLocale.noSecretNamedMountedExceptionMessage -f $Name) } # get the secret and vault @@ -671,7 +672,7 @@ function Update-PodeSecret { # has the secret been mounted? if (!(Test-PodeSecret -Name $Name)) { # No Secret named has been mounted - throw ($PodeLocal.noSecretNamedMountedExceptionMessage -f $Name) + throw ($PodeLocale.noSecretNamedMountedExceptionMessage -f $Name) } # make sure the value type is correct @@ -745,7 +746,8 @@ function Remove-PodeSecret { # has the vault been registered? if (!(Test-PodeSecretVault -Name $Vault)) { - throw "No Secret Vault with the name '$($Vault)' has been registered" + # No Secret Vault with the name has been registered + throw ($PodeLocale.noSecretVaultRegisteredExceptionMessage -f $Vault) } # remove the secret depending on vault type @@ -817,7 +819,8 @@ function Read-PodeSecret { # has the vault been registered? if (!(Test-PodeSecretVault -Name $Vault)) { - throw "No Secret Vault with the name '$($Vault)' has been registered" + # No Secret Vault with the name has been registered + throw ($PodeLocale.noSecretVaultRegisteredExceptionMessage -f $Vault) } # fetch the secret depending on vault type @@ -902,7 +905,8 @@ function Set-PodeSecret { # has the vault been registered? if (!(Test-PodeSecretVault -Name $Vault)) { - throw "No Secret Vault with the name '$($Vault)' has been registered" + # No Secret Vault with the name has been registered + throw ($PodeLocale.noSecretVaultRegisteredExceptionMessage -f $Vault) } # make sure the value type is correct diff --git a/src/Public/Security.ps1 b/src/Public/Security.ps1 index 3d7f1ecd4..18aa8eae7 100644 --- a/src/Public/Security.ps1 +++ b/src/Public/Security.ps1 @@ -1258,7 +1258,8 @@ function Set-PodeSecurityStrictTransportSecurity { ) if ($Duration -le 0) { - throw "Invalid Strict-Transport-Security duration supplied: $($Duration). Should be greater than 0" + # Invalid Strict-Transport-Security duration supplied + throw ($PodeLocale.invalidStrictTransportSecurityDurationExceptionMessage -f $Duration) } $value = "max-age=$($Duration)" @@ -1454,7 +1455,7 @@ function Set-PodeSecurityAccessControl { if ($Headers -icontains '*') { if ($Credentials) { # When Credentials is passed, The * wildcard for Headers will be taken as a literal string and not a wildcard - throw $PodeLocal.credentialsPassedWildcardForHeadersLiteralExceptionMessage + throw $PodeLocale.credentialsPassedWildcardForHeadersLiteralExceptionMessage } $Headers = @('*') @@ -1480,7 +1481,7 @@ function Set-PodeSecurityAccessControl { if ($AutoHeaders) { if ($Headers -icontains '*') { # The * wildcard for Headers is incompatible with the AutoHeaders switch - throw $PodeLocal.wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage + throw $PodeLocale.wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage } Add-PodeSecurityHeader -Name 'Access-Control-Allow-Headers' -Value 'content-type' -Append @@ -1490,7 +1491,7 @@ function Set-PodeSecurityAccessControl { if ($AutoMethods) { if ($Methods -icontains '*') { # The * wildcard for Methods is incompatible with the AutoMethods switch - throw $PodeLocal.wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage + throw $PodeLocale.wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage } if ($WithOptions) { Add-PodeSecurityHeader -Name 'Access-Control-Allow-Methods' -Value 'Options' -Append @@ -1501,7 +1502,7 @@ function Set-PodeSecurityAccessControl { # duration if ($Duration -le 0) { # Invalid Access-Control-Max-Age duration supplied - throw ($PodeLocal.invalidAccessControlMaxAgeDurationExceptionMessage -f $Duration) + throw ($PodeLocale.invalidAccessControlMaxAgeDurationExceptionMessage -f $Duration) } Add-PodeSecurityHeader -Name 'Access-Control-Max-Age' -Value $Duration diff --git a/src/Public/Sessions.ps1 b/src/Public/Sessions.ps1 index 0585ea366..a04b4c106 100644 --- a/src/Public/Sessions.ps1 +++ b/src/Public/Sessions.ps1 @@ -66,7 +66,8 @@ function Enable-PodeSessionMiddleware { [Parameter()] [ValidateScript({ if ($_ -lt 0) { - throw "Duration must be 0 or greater, but got: $($_)s" + # Duration must be 0 or greater, but got + throw ($PodeLocale.durationMustBeZeroOrGreaterExceptionMessage -f $_) } return $true diff --git a/src/Public/Tasks.ps1 b/src/Public/Tasks.ps1 index e8ac3e70c..8d5900cfc 100644 --- a/src/Public/Tasks.ps1 +++ b/src/Public/Tasks.ps1 @@ -44,7 +44,8 @@ function Add-PodeTask { ) # ensure the task doesn't already exist if ($PodeContext.Tasks.Items.ContainsKey($Name)) { - throw "[Task] $($Name): Task already defined" + # [Task] Task already defined + throw ($PodeLocale.taskAlreadyDefinedExceptionMessage -f $Name) } # if we have a file path supplied, load that path as a scriptblock @@ -88,7 +89,9 @@ function Set-PodeTaskConcurrency { # error if <=0 if ($Maximum -le 0) { - throw "Maximum concurrent tasks must be >=1 but got: $($Maximum)" + # Maximum concurrent tasks must be >=1 but got + throw ($PodeLocale.maximumConcurrentTasksInvalidExceptionMessage -f $Maximum) + } # ensure max > min @@ -98,7 +101,8 @@ function Set-PodeTaskConcurrency { } if ($_min -gt $Maximum) { - throw "Maximum concurrent tasks cannot be less than the minimum of $($_min) but got: $($Maximum)" + # Maximum concurrent tasks cannot be less than the minimum of $_min but got $Maximum + throw ($PodeLocale.maximumConcurrentTasksLessThanMinimumExceptionMessage -f $_min, $Maximum) } # set the max tasks @@ -157,7 +161,8 @@ function Invoke-PodeTask { # ensure the task exists if (!$PodeContext.Tasks.Items.ContainsKey($Name)) { - throw "Task '$($Name)' does not exist" + # Task does not exist + throw ($PodeLocale.taskDoesNotExistExceptionMessage -f $Name) } # run task logic @@ -250,7 +255,8 @@ function Edit-PodeTask { # ensure the task exists if (!$PodeContext.Tasks.Items.ContainsKey($Name)) { - throw "Task '$($Name)' does not exist" + # Task does not exist + throw ($PodeLocale.taskDoesNotExistExceptionMessage -f $Name) } $_task = $PodeContext.Tasks.Items[$Name] diff --git a/src/Public/Utilities.ps1 b/src/Public/Utilities.ps1 index 5657caad1..c89fda2d5 100644 --- a/src/Public/Utilities.ps1 +++ b/src/Public/Utilities.ps1 @@ -192,7 +192,8 @@ function Use-PodeScript { # check if the path exists if (!(Test-PodePath $_path -NoStatus)) { - throw "The script path does not exist: $(Protect-PodeValue -Value $_path -Default $Path)" + # The script path does not exist + throw ($PodeLocale.scriptPathDoesNotExistExceptionMessage -f (Protect-PodeValue -Value $_path -Default 'DefaultPath')) } # dot-source the script @@ -350,12 +351,14 @@ function Import-PodeModule { # if it's still empty, error if ([string]::IsNullOrWhiteSpace($Path)) { - throw "Failed to import module: $(Protect-PodeValue -Value $Path -Default $Name)" + # Failed to import module + throw ($PodeLocale.failedToImportModuleExceptionMessage -f (Protect-PodeValue -Value $Path -Default $Name)) } # check if the path exists if (!(Test-PodePath $Path -NoStatus)) { - throw "The module path does not exist: $(Protect-PodeValue -Value $Path -Default $Name)" + # The module path does not exist + throw ($PodeLocale.modulePathDoesNotExistExceptionMessage -f (Protect-PodeValue -Value $Path -Default $Name)) } $null = Import-Module $Path -Force -DisableNameChecking -Scope Global -ErrorAction Stop diff --git a/src/Public/Verbs.ps1 b/src/Public/Verbs.ps1 index 63cd58b9c..762d971d5 100644 --- a/src/Public/Verbs.ps1 +++ b/src/Public/Verbs.ps1 @@ -82,7 +82,8 @@ function Add-PodeVerb { # if scriptblock and file path are all null/empty, error if ((Test-PodeIsEmpty $ScriptBlock) -and (Test-PodeIsEmpty $FilePath) -and !$Close -and !$UpgradeToSsl) { - throw "[Verb] $($Verb): No logic passed" + # [Verb] Verb: No logic passed + throw ($PodeLocale.verbNoLogicPassedExceptionMessage -f $Verb) } # if we have a file path supplied, load that path as a scriptblock diff --git a/src/Public/WebSockets.ps1 b/src/Public/WebSockets.ps1 index 3b6eab478..0fcf5f3d7 100644 --- a/src/Public/WebSockets.ps1 +++ b/src/Public/WebSockets.ps1 @@ -23,7 +23,9 @@ function Set-PodeWebSocketConcurrency { # error if <=0 if ($Maximum -le 0) { - throw "Maximum concurrent WebSocket threads must be >=1 but got: $($Maximum)" + # Maximum concurrent WebSocket threads must be >=1 but got + throw ($PodeLocale.maximumConcurrentWebSocketThreadsInvalidExceptionMessage -f $Maximum) + } # add 1, for the waiting script @@ -36,7 +38,8 @@ function Set-PodeWebSocketConcurrency { } if ($_min -gt $Maximum) { - throw "Maximum concurrent WebSocket threads cannot be less than the minimum of $($_min) but got: $($Maximum)" + # Maximum concurrent WebSocket threads cannot be less than the minimum of $_min but got $Maximum + throw ($PodeLocale.maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage -f $_min, $Maximum) } # set the max tasks @@ -116,7 +119,8 @@ function Connect-PodeWebSocket { # fail if already exists if (Test-PodeWebSocket -Name $Name) { - throw "Already connected to websocket with name '$($Name)'" + # Already connected to websocket with name + throw ($PodeLocale.alreadyConnectedToWebSocketExceptionMessage -f $Name) } # if we have a file path supplied, load that path as a scriptblock @@ -132,7 +136,8 @@ function Connect-PodeWebSocket { $PodeContext.Server.WebSockets.Receiver.ConnectWebSocket($Name, $Url, $ContentType) } catch { - throw "Failed to connect to websocket: $($_.Exception.Message)" + # Failed to connect to websocket + throw ($PodeLocale.failedToConnectToWebSocketExceptionMessage -f $ErrorMessage) } $PodeContext.Server.WebSockets.Connections[$Name] = @{ @@ -171,7 +176,7 @@ function Disconnect-PodeWebSocket { if ([string]::IsNullOrWhiteSpace($Name)) { # No Name for a WebSocket to disconnect from supplied - throw $PodeLocal.noNameForWebSocketDisconnectExceptionMessage + throw $PodeLocale.noNameForWebSocketDisconnectExceptionMessage } if (Test-PodeWebSocket -Name $Name) { @@ -206,7 +211,7 @@ function Remove-PodeWebSocket { if ([string]::IsNullOrWhiteSpace($Name)) { # No Name for a WebSocket to remove supplied - throw $PodeLocal.noNameForWebSocketRemoveExceptionMessage + throw $PodeLocale.noNameForWebSocketRemoveExceptionMessage } @@ -264,7 +269,7 @@ function Send-PodeWebSocket { # do we have a name? if ([string]::IsNullOrWhiteSpace($Name)) { # No Name for a WebSocket to send message to supplied - throw $PodeLocal.noNameForWebSocketSendMessageExceptionMessage + throw $PodeLocale.noNameForWebSocketSendMessageExceptionMessage } # do the socket exist? @@ -320,7 +325,7 @@ function Reset-PodeWebSocket { if ([string]::IsNullOrWhiteSpace($Name)) { # No Name for a WebSocket to reset supplied - throw $PodeLocal.noNameForWebSocketResetExceptionMessage + throw $PodeLocale.noNameForWebSocketResetExceptionMessage } if (Test-PodeWebSocket -Name $Name) { diff --git a/tests/unit/Localization.Tests.ps1 b/tests/unit/Localization.Tests.ps1 index 8ab0b9baf..5c178e8c4 100644 --- a/tests/unit/Localization.Tests.ps1 +++ b/tests/unit/Localization.Tests.ps1 @@ -2,7 +2,30 @@ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')] param() -Describe 'Localization Files Key Check' { +Describe 'Localization Check' { + + + # Function to extract hashtable keys from a file + function Export-KeysFromFile { + param ( + [string]$filePath + ) + + $content = Get-Content -Path $filePath -Raw + $keys = @() + $regex = '\$PodeLocale\["([^"]+)"\]|\$PodeLocale\.([a-zA-Z_][a-zA-Z0-9_]*)' + foreach ($match in [regex]::Matches($content, $regex)) { + if ($match.Groups[1].Value) { + $keys += $match.Groups[1].Value + } + elseif ($match.Groups[2].Value) { + $keys += $match.Groups[2].Value + } + } + return $keys + } + + $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src' # All language directories @@ -17,13 +40,25 @@ Describe 'Localization Files Key Check' { # Discover all language directories $languageDirs = Get-ChildItem -Path $localizationDir -Directory | Where-Object { $_.Name -ne 'en' } - Describe 'Language [<_.Name>]' -ForEach ($languageDirs) { + + # Get all source code files recursively from the specified directory + $sourceFiles = Get-ChildItem -Path $src -Recurse -Include *.ps1, *.psm1 + + Describe 'Verify Invalid Hashtable Keys in [<_.Name>]' -ForEach ($sourceFiles) { + $keysInFile = Export-KeysFromFile -filePath $_.FullName + It "should find the key '[<_>]' in the hashtable" -ForEach ($keysInFile) { + $global:localizationKeys -contains $_ | Should -BeTrue + } + } + + + Describe 'Verifying Language [<_.Name>]' -ForEach ($languageDirs) { it 'Language resource file exist' { Test-Path -Path "$($_.FullName)/Pode.psd1" | Should -BeTrue } $podeFileContent = Get-Content -Path "$($_.FullName)/Pode.psd1" -Raw $global:content = Invoke-Expression $podeFileContent - it 'Total number of keys equal to the [en]' { + it 'Number of entry equal to the [en]' { $global:content.Keys.Count | Should -be $global:localizationKeys.Count } It -ForEach ($global:localizationKeys) -Name 'Resource File contain <_>' { diff --git a/tests/unit/OpenApi.Tests.ps1 b/tests/unit/OpenApi.Tests.ps1 index d0d2fbfec..777367ecf 100644 --- a/tests/unit/OpenApi.Tests.ps1 +++ b/tests/unit/OpenApi.Tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } -Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture "en-us" -FileName "Pode" + Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -UICulture 'en-us' -FileName 'Pode' } Describe 'OpenApi' { @@ -2094,7 +2094,7 @@ Describe 'OpenApi' { It 'AllOf and ObjectDefinitions not an object' { { Merge-PodeOAProperty -Type AllOf -DiscriminatorProperty 'name' -ObjectDefinitions @('Pet', ((New-PodeOAIntProperty -Name 'id'), (New-PodeOAStringProperty -Name 'name')) - ) } | Should -Throw -ExpectedMessage 'Only properties of type Object can be associated with allof' + ) } | Should -Throw -ExpectedMessage ($PodeLocale.propertiesTypeObjectAssociationExceptionMessage -f 'allOf') # Only properties of type Object can be associated with allOf } } @@ -2409,7 +2409,8 @@ Describe 'OpenApi' { } It 'Path - ContentSchema - Exception -Required' { - { ConvertTo-PodeOAParameter -In Path -Description 'Feline description' -ContentType 'application/json' -Schema 'Cat' } | Should -Throw -ExpectedMessage '*the switch parameter `-Required*' + { ConvertTo-PodeOAParameter -In Path -Description 'Feline description' -ContentType 'application/json' -Schema 'Cat' } | + Should -Throw -ExpectedMessage $PodeLocale.pathParameterRequiresRequiredSwitchExceptionMessage # If the parameter location is 'Path', the switch parameter 'Required' is mandatory } } } From 04e151bfbf54ac1db99c39262adfa4992b259b29 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sun, 2 Jun 2024 09:21:23 -0700 Subject: [PATCH 025/177] Update Authentication.Tests.ps1 --- tests/integration/Authentication.Tests.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/integration/Authentication.Tests.ps1 b/tests/integration/Authentication.Tests.ps1 index c924f0445..67f4147c3 100644 --- a/tests/integration/Authentication.Tests.ps1 +++ b/tests/integration/Authentication.Tests.ps1 @@ -1,7 +1,11 @@ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseUsingScopeModifierInNewRunspaces', '')] param() - +BeforeAll { + $path = $PSCommandPath + $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]integration', '/src/' + Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } +} Describe 'Authentication Requests' { BeforeAll { From cd5641176c4d68ac2289fd1cfe46ef6c371e0074 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sun, 2 Jun 2024 15:14:26 -0700 Subject: [PATCH 026/177] Update Helpers.ps1 --- src/Private/Helpers.ps1 | 62 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index cb6c42578..287f0e7d3 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -3950,4 +3950,66 @@ function Open-PodeRunspace { # Rethrowing the error to be handled further up the call stack. throw } +} + +<# +.SYNOPSIS + Resolves various types of object arrays into PowerShell objects. + +.DESCRIPTION + This function takes an input property and determines its type. + It then resolves the property into a PowerShell object or an array of objects, + depending on whether the property is a hashtable, array, or single object. + +.PARAMETER Property + The property to be resolved. It can be a hashtable, an object array, or a single object. + +.RETURNS + Returns a PowerShell object or an array of PowerShell objects, depending on the input property type. + +.EXAMPLE + $result = Resolve-PodeObjectArray -Property $myProperty + This example resolves the $myProperty into a PowerShell object or an array of objects. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Resolve-PodeObjectArray { + [CmdletBinding()] + [OutputType([object[]])] + [OutputType([psobject])] + param ( + [AllowNull()] + [object] + $Property + ) + + # Check if the property is a hashtable + if ($Property -is [hashtable]) { + # If the hashtable has only one item, convert it to a PowerShell object + if ($Property.Count -eq 1) { + return New-Object psobject -Property $Property + } + else { + # If the hashtable has more than one item, recursively resolve each item + return @(foreach ($p in $Property) { + Resolve-PodeObjectArray -Property $p + }) + } + } + # Check if the property is an array of objects + elseif ($Property -is [object[]]) { + # Recursively resolve each item in the array + return @(foreach ($p in $Property) { + Resolve-PodeObjectArray -Property $p + }) + } + # Check if the property is already a PowerShell object + elseif ($Property -is [psobject]) { + return $Property + } + else { + # For any other type, convert it to a PowerShell object + return New-Object psobject -Property $Property + } } \ No newline at end of file From 0b3dd2240e718f13e2452e6e206fe9873c7b4ac7 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sun, 2 Jun 2024 15:24:22 -0700 Subject: [PATCH 027/177] Update OpenApi.ps1 --- src/Private/OpenApi.ps1 | 146 ++++++++++++++++++++++++---------------- 1 file changed, 89 insertions(+), 57 deletions(-) diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index 571ec1dc1..a07c4f559 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -1431,30 +1431,33 @@ function Set-PodeOAGlobalAuth { <# .SYNOPSIS - Resolves references in a Pode OpenAPI component schema. + Resolves references in an OpenAPI schema component based on definitions within a specified definition tag context. .DESCRIPTION - This internal function resolves `$ref` references in a Pode OpenAPI component schema, replacing them with the actual schema definitions. - It supports `allOf` references and ensures that nested objects and references are resolved appropriately. + This function navigates through a schema's properties and resolves `$ref` references to actual schemas defined within the specified definition context. + It handles complex constructs such as 'allOf', 'oneOf', and 'anyOf', merging properties and ensuring the schema is fully resolved without unresolved references. .PARAMETER ComponentSchema - The hashtable representing the component schema with potential references to be resolved. This parameter is mandatory and accepts values from the pipeline. + A hashtable representing the schema of a component where references need to be resolved. .PARAMETER DefinitionTag - The tag used to identify the OpenAPI definition in the Pode context. This parameter is mandatory. + A string identifier for the specific set of schema definitions under which references should be resolved. .EXAMPLE $schema = @{ + type = 'object'; properties = @{ - prop1 = @{ - '$ref' = '#/components/schemas/ReferencedSchema' + name = @{ + type = 'string' + }; + details = @{ + '$ref' = '#/components/schemas/UserDetails' } - } + }; } - Resolve-PodeOAReference -ComponentSchema $schema -DefinitionTag 'MyDefinition' + Resolve-PodeOAReference -ComponentSchema $schema -DefinitionTag 'v1' -.NOTES - This is an internal function and may change in future releases of Pode. + This example demonstrates resolving a reference to 'UserDetails' within a given component schema. #> function Resolve-PodeOAReference { param( @@ -1468,79 +1471,77 @@ function Resolve-PodeOAReference { ) begin { - # Retrieve the schema definitions from the Pode context + # Initialize schema storage and a list to track keys that need resolution $Schemas = $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.schemaJson - # Initialize an array to store the keys of the properties to process $Keys = @() } process { - # If the schema has properties, add their keys to the $Keys array + # Gather all keys from properties and directly from the schema that might have references if ($ComponentSchema.properties) { foreach ($item in $ComponentSchema.properties.Keys) { $Keys += $item } } - - # Add keys for any 'allOf', 'oneOf', or 'anyOf' properties to the $Keys array foreach ($item in $ComponentSchema.Keys) { if ( @('allof', 'oneof', 'anyof') -icontains $item ) { $Keys += $item } } - # Process each key in the $Keys array + # Process each key to resolve references or merge schema definitions foreach ($key in $Keys) { if ( @('allof', 'oneof', 'anyof') -icontains $key ) { - if ($key -ieq 'allof') { - # Initialize an array to hold temporary properties - $tmpProp = @() - # Process each component in the 'allOf' array - foreach ( $comp in $ComponentSchema[$key] ) { - # If the component is a reference, resolve it - if ($comp.'$ref') { - if (($comp.'$ref').StartsWith('#/components/schemas/')) { - $refName = ($comp.'$ref') -replace '#/components/schemas/', '' - if ($Schemas.ContainsKey($refName)) { - $tmpProp += $Schemas[$refName].schema + # Handle complex schema constructs like allOf, oneOf, and anyOf + switch ($key.ToLower()) { + 'allof' { + $tmpProp = @() + foreach ( $comp in $ComponentSchema[$key] ) { + if ($comp.'$ref') { + # Resolve $ref to a schema if it starts with the expected path + if (($comp.'$ref').StartsWith('#/components/schemas/')) { + $refName = ($comp.'$ref') -replace '#/components/schemas/', '' + if ($Schemas.ContainsKey($refName)) { + $tmpProp += $Schemas[$refName].schema + } } } - } - elseif ( $comp.properties) { - # If the component has properties, resolve them recursively - if ($comp.type -eq 'object') { - $tmpProp += Resolve-PodeOAReference -DefinitionTag $DefinitionTag -ComponentSchema$comp + elseif ( $comp.properties) { + # Recursively resolve nested schemas + if ($comp.type -eq 'object') { + $tmpProp += Resolve-PodeOAReference -DefinitionTag $DefinitionTag -ComponentSchema$comp + } + else { + throw 'Unsupported object' + } } - else { - throw 'Unsupported object' + } + # Update the main schema to be an object and add resolved properties + $ComponentSchema.type = 'object' + $ComponentSchema.remove('allOf') + if ($tmpProp.count -gt 0) { + foreach ($t in $tmpProp) { + $ComponentSchema.properties += $t.properties } } - } - # Set the schema type to 'object' and remove the 'allOf' key - $ComponentSchema.type = 'object' - $ComponentSchema.remove('allOf') - # Add the properties from the resolved components - if ($tmpProp.count -gt 0) { - foreach ($t in $tmpProp) { - $ComponentSchema.properties += $t.properties - } } - - } - elseif ($key -ieq 'oneof') { - throw 'Validation of schema with oneof is not supported' - } - elseif ($key -ieq 'anyof') { - throw 'Validation of schema with anyof is not supported' + 'oneof' { + # Throw an error for unsupported schema constructs to notify the user + throw "Validation of schema with $key is not supported" + } + 'anyof' { + # Throw an error for unsupported schema constructs to notify the user + throw "Validation of schema with $key is not supported" + } } } - # If the property type is 'object', resolve its properties recursively elseif ($ComponentSchema.properties[$key].type -eq 'object') { + # Recursively resolve object-type properties $ComponentSchema.properties[$key].properties = Resolve-PodeOAReference -DefinitionTag $DefinitionTag -ComponentSchema $ComponentSchema.properties[$key].properties } - # If the property is a reference, resolve it elseif ($ComponentSchema.properties[$key].'$ref') { + # Resolve property references within the main properties of the schema if (($ComponentSchema.properties[$key].'$ref').StartsWith('#/components/schemas/')) { $refName = ($ComponentSchema.properties[$key].'$ref') -replace '#/components/schemas/', '' if ($Schemas.ContainsKey($refName)) { @@ -1548,7 +1549,6 @@ function Resolve-PodeOAReference { } } } - # If the property has items and the items are references, resolve them elseif ($ComponentSchema.properties[$key].items -and $ComponentSchema.properties[$key].items.'$ref' ) { if (($ComponentSchema.properties[$key].items.'$ref').StartsWith('#/components/schemas/')) { $refName = ($ComponentSchema.properties[$key].items.'$ref') -replace '#/components/schemas/', '' @@ -1561,12 +1561,11 @@ function Resolve-PodeOAReference { } end { - # Return the resolved component schema + # Return the fully resolved component schema return $ComponentSchema } } - <# .SYNOPSIS Creates a new OpenAPI property object based on provided parameters. @@ -2128,4 +2127,37 @@ function Test-PodeOAComponentInternal { return $true } } -} \ No newline at end of file +} + + + +<# +.SYNOPSIS + Resolves references in an OpenAPI schema component based on definitions within a specified definition tag context. + +.DESCRIPTION + This function navigates through a schema's properties and resolves `$ref` references to actual schemas defined within the specified definition context. + It handles complex constructs such as 'allOf', 'oneOf', and 'anyOf', merging properties and ensuring the schema is fully resolved without unresolved references. + +.PARAMETER ComponentSchema + A hashtable representing the schema of a component where references need to be resolved. + +.PARAMETER DefinitionTag + A string identifier for the specific set of schema definitions under which references should be resolved. + +.EXAMPLE + $schema = @{ + type = 'object'; + properties = @{ + name = @{ + type = 'string' + }; + details = @{ + '$ref' = '#/components/schemas/UserDetails' + } + }; + } + Resolve-PodeOAReference -ComponentSchema $schema -DefinitionTag 'v1' + + This example demonstrates resolving a reference to 'UserDetails' within a given component schema. +#> \ No newline at end of file From dd2d4c021361d3f9a24c260c07538c62a4f51968 Mon Sep 17 00:00:00 2001 From: mdaneri <17148649+mdaneri@users.noreply.github.com> Date: Sun, 2 Jun 2024 15:39:43 -0700 Subject: [PATCH 028/177] Update OpenApi.ps1 --- src/Private/OpenApi.ps1 | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index fe07ee73b..ada70c012 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -2150,36 +2150,3 @@ function Test-PodeOAComponentInternal { } } } - - - -<# -.SYNOPSIS - Resolves references in an OpenAPI schema component based on definitions within a specified definition tag context. - -.DESCRIPTION - This function navigates through a schema's properties and resolves `$ref` references to actual schemas defined within the specified definition context. - It handles complex constructs such as 'allOf', 'oneOf', and 'anyOf', merging properties and ensuring the schema is fully resolved without unresolved references. - -.PARAMETER ComponentSchema - A hashtable representing the schema of a component where references need to be resolved. - -.PARAMETER DefinitionTag - A string identifier for the specific set of schema definitions under which references should be resolved. - -.EXAMPLE - $schema = @{ - type = 'object'; - properties = @{ - name = @{ - type = 'string' - }; - details = @{ - '$ref' = '#/components/schemas/UserDetails' - } - }; - } - Resolve-PodeOAReference -ComponentSchema $schema -DefinitionTag 'v1' - - This example demonstrates resolving a reference to 'UserDetails' within a given component schema. -#> \ No newline at end of file From 14da0d5976d58d9cbb32ca3a8117c47f1637e1ff Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sun, 2 Jun 2024 21:01:49 -0700 Subject: [PATCH 029/177] additional messages --- src/Locales/ar/Pode.psd1 | 13 ++++++++++++- src/Locales/de/Pode.psd1 | 15 ++++++++++++--- src/Locales/en/Pode.psd1 | 11 +++++++++++ src/Locales/es/Pode.psd1 | 13 ++++++++++++- src/Locales/fr/Pode.psd1 | 13 ++++++++++++- src/Locales/it/Pode.psd1 | 13 ++++++++++++- src/Locales/ja/Pode.psd1 | 13 ++++++++++++- src/Locales/kr/Pode.psd1 | 13 ++++++++++++- src/Locales/pl/Pode.psd1 | 11 +++++++++++ src/Locales/pt/Pode.psd1 | 13 ++++++++++++- src/Locales/zn/Pode.psd1 | 13 ++++++++++++- src/Pode.psm1 | 2 +- src/Public/Caching.ps1 | 18 ++++++++++++------ src/Public/Core.ps1 | 18 ++++++++++++------ tests/unit/Localization.Tests.ps1 | 2 +- 15 files changed, 156 insertions(+), 25 deletions(-) diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 9e4d9e05c..52c18f946 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -212,4 +212,15 @@ taskAlreadyDefinedExceptionMessage = [المهمة] {0}: المهمة معرفة maximumConcurrentTasksInvalidExceptionMessage = يجب أن يكون الحد الأقصى للمهام المتزامنة >=1، ولكن تم الحصول عليه: {0} maximumConcurrentTasksLessThanMinimumExceptionMessage = لا يمكن أن يكون الحد الأقصى للمهام المتزامنة أقل من الحد الأدنى {0}، ولكن تم الحصول عليه: {1} taskDoesNotExistExceptionMessage = المهمة '{0}' غير موجودة. -'@ +cacheStorageNotFoundForRetrieveExceptionMessage = لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة استرجاع العنصر المخزن مؤقتًا '{1}' +cacheStorageNotFoundForSetExceptionMessage = لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة تعيين العنصر المخزن مؤقتًا '{1}' +cacheStorageNotFoundForExistsExceptionMessage = لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة التحقق مما إذا كان العنصر المخزن مؤقتًا '{1}' موجودًا. +cacheStorageNotFoundForRemoveExceptionMessage = لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة إزالة العنصر المخزن مؤقتًا '{1}' +cacheStorageNotFoundForClearExceptionMessage = لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة مسح الذاكرة المؤقتة. +cacheStorageAlreadyExistsExceptionMessage = مخزن ذاكرة التخزين المؤقت بالاسم '{0}' موجود بالفعل. +pathToIconForGuiDoesNotExistExceptionMessage = المسار إلى الأيقونة للواجهة الرسومية غير موجود: {0} +invalidHostnameSuppliedExceptionMessage = اسم المضيف المقدم غير صالح: {0} +endpointAlreadyDefinedExceptionMessage = تم تعريف نقطة نهاية باسم '{0}' بالفعل. +certificateExpiredExceptionMessage = الشهادة '{0}' منتهية الصلاحية: {1} +endpointNotDefinedForRedirectingExceptionMessage = لم يتم تعريف نقطة نهاية باسم '{0}' لإعادة التوجيه. +'@ \ No newline at end of file diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index 553f86447..9432c4d0a 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -212,6 +212,15 @@ taskAlreadyDefinedExceptionMessage = [Aufgabe] {0}: Aufgabe bereits definiert. maximumConcurrentTasksInvalidExceptionMessage = Die maximale Anzahl gleichzeitiger Aufgaben muss >=1 sein, aber erhalten: {0} maximumConcurrentTasksLessThanMinimumExceptionMessage = Die maximale Anzahl gleichzeitiger Aufgaben darf nicht kleiner als das Minimum von {0} sein, aber erhalten: {1} taskDoesNotExistExceptionMessage = Aufgabe '{0}' existiert nicht. -'@ - - +cacheStorageNotFoundForRetrieveExceptionMessage = Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde, das zwischengespeicherte Element '{1}' abzurufen. +cacheStorageNotFoundForSetExceptionMessage = Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde, das zwischengespeicherte Element '{1}' zu setzen. +cacheStorageNotFoundForExistsExceptionMessage = Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde zu überprüfen, ob das zwischengespeicherte Element '{1}' existiert. +cacheStorageNotFoundForRemoveExceptionMessage = Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde, das zwischengespeicherte Element '{1}' zu entfernen. +cacheStorageNotFoundForClearExceptionMessage = Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde, den Cache zu leeren. +cacheStorageAlreadyExistsExceptionMessage = Ein Cache-Speicher mit dem Namen '{0}' existiert bereits. +pathToIconForGuiDoesNotExistExceptionMessage = Der Pfad zum Symbol für die GUI existiert nicht: {0} +invalidHostnameSuppliedExceptionMessage = Der angegebene Hostname ist ungültig: {0} +endpointAlreadyDefinedExceptionMessage = Ein Endpunkt mit dem Namen '{0}' wurde bereits definiert. +certificateExpiredExceptionMessage = Das Zertifikat '{0}' ist abgelaufen: {1} +endpointNotDefinedForRedirectingExceptionMessage = Ein Endpunkt mit dem Namen '{0}' wurde nicht für die Weiterleitung definiert. +'@ \ No newline at end of file diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 3b6924a07..be481da96 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -212,4 +212,15 @@ taskAlreadyDefinedExceptionMessage = [Task] {0}: Task already defined. maximumConcurrentTasksInvalidExceptionMessage = Maximum concurrent tasks must be >=1 but got: {0} maximumConcurrentTasksLessThanMinimumExceptionMessage = Maximum concurrent tasks cannot be less than the minimum of {0} but got: {1} taskDoesNotExistExceptionMessage = Task '{0}' does not exist. +cacheStorageNotFoundForRetrieveExceptionMessage = Cache storage with name '{0}' not found when attempting to retrieve cached item '{1}' +cacheStorageNotFoundForSetExceptionMessage = Cache storage with name '{0}' not found when attempting to set cached item '{1}' +cacheStorageNotFoundForExistsExceptionMessage = Cache storage with name '{0}' not found when attempting to check if cached item '{1}' exists. +cacheStorageNotFoundForRemoveExceptionMessage = Cache storage with name '{0}' not found when attempting to remove cached item '{1}' +cacheStorageNotFoundForClearExceptionMessage = Cache storage with name '{0}' not found when attempting to clear the cache. +cacheStorageAlreadyExistsExceptionMessage = Cache Storage with name '{0}' already exists. +pathToIconForGuiDoesNotExistExceptionMessage = Path to the icon for GUI does not exist: {0} +invalidHostnameSuppliedExceptionMessage = Invalid hostname supplied: {0} +endpointAlreadyDefinedExceptionMessage = An endpoint named '{0}' has already been defined. +certificateExpiredExceptionMessage = The certificate '{0}' has expired: {1} +endpointNotDefinedForRedirectingExceptionMessage = An endpoint named '{0}' has not been defined for redirecting. '@ \ No newline at end of file diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 1569a419c..55c93fcb9 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -212,4 +212,15 @@ taskAlreadyDefinedExceptionMessage = [Tarea] {0}: Tarea ya definida. maximumConcurrentTasksInvalidExceptionMessage = El número máximo de tareas concurrentes debe ser >=1, pero se obtuvo: {0} maximumConcurrentTasksLessThanMinimumExceptionMessage = El número máximo de tareas concurrentes no puede ser menor que el mínimo de {0}, pero se obtuvo: {1} taskDoesNotExistExceptionMessage = La tarea '{0}' no existe. -'@ +cacheStorageNotFoundForRetrieveExceptionMessage = No se encontró el almacenamiento en caché con el nombre '{0}' al intentar recuperar el elemento en caché '{1}'. +cacheStorageNotFoundForSetExceptionMessage = No se encontró el almacenamiento en caché con el nombre '{0}' al intentar establecer el elemento en caché '{1}'. +cacheStorageNotFoundForExistsExceptionMessage = No se encontró el almacenamiento en caché con el nombre '{0}' al intentar comprobar si el elemento en caché '{1}' existe. +cacheStorageNotFoundForRemoveExceptionMessage = No se encontró el almacenamiento en caché con el nombre '{0}' al intentar eliminar el elemento en caché '{1}'. +cacheStorageNotFoundForClearExceptionMessage = No se encontró el almacenamiento en caché con el nombre '{0}' al intentar vaciar la caché. +cacheStorageAlreadyExistsExceptionMessage = Ya existe un almacenamiento en caché con el nombre '{0}'. +pathToIconForGuiDoesNotExistExceptionMessage = La ruta del icono para la GUI no existe: {0} +invalidHostnameSuppliedExceptionMessage = Nombre de host no válido proporcionado: {0} +endpointAlreadyDefinedExceptionMessage = Ya se ha definido un punto de conexión llamado '{0}'. +certificateExpiredExceptionMessage = El certificado '{0}' ha expirado: {1} +endpointNotDefinedForRedirectingExceptionMessage = No se ha definido un punto de conexión llamado '{0}' para la redirección. +'@ \ No newline at end of file diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index 7dd7e8a5e..543933edb 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -212,4 +212,15 @@ taskAlreadyDefinedExceptionMessage = [Tâche] {0} : Tâche déjà définie. maximumConcurrentTasksInvalidExceptionMessage = Le nombre maximum de tâches simultanées doit être >=1, mais a obtenu : {0} maximumConcurrentTasksLessThanMinimumExceptionMessage = Le nombre maximum de tâches simultanées ne peut pas être inférieur au minimum de {0}, mais a obtenu : {1} taskDoesNotExistExceptionMessage = La tâche '{0}' n'existe pas. -'@ +cacheStorageNotFoundForRetrieveExceptionMessage = Le stockage de cache nommé '{0}' est introuvable lors de la tentative de récupération de l'élément mis en cache '{1}'. +cacheStorageNotFoundForSetExceptionMessage = Le stockage de cache nommé '{0}' est introuvable lors de la tentative de définition de l'élément mis en cache '{1}'. +cacheStorageNotFoundForExistsExceptionMessage = Le stockage de cache nommé '{0}' est introuvable lors de la tentative de vérification de l'existence de l'élément mis en cache '{1}'. +cacheStorageNotFoundForRemoveExceptionMessage = Le stockage de cache nommé '{0}' est introuvable lors de la tentative de suppression de l'élément mis en cache '{1}'. +cacheStorageNotFoundForClearExceptionMessage = Le stockage de cache nommé '{0}' est introuvable lors de la tentative de vider le cache. +cacheStorageAlreadyExistsExceptionMessage = Un stockage de cache nommé '{0}' existe déjà. +pathToIconForGuiDoesNotExistExceptionMessage = Le chemin vers l'icône pour l'interface graphique n'existe pas: {0} +invalidHostnameSuppliedExceptionMessage = Nom d'hôte fourni invalide: {0} +endpointAlreadyDefinedExceptionMessage = Un point de terminaison nommé '{0}' a déjà été défini. +certificateExpiredExceptionMessage = Le certificat '{0}' a expiré: {1} +endpointNotDefinedForRedirectingExceptionMessage = Un point de terminaison nommé '{0}' n'a pas été défini pour la redirection. +'@ \ No newline at end of file diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index ea28f0900..dde46a290 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -212,4 +212,15 @@ taskAlreadyDefinedExceptionMessage = [Attività] {0}: Attività già definita. maximumConcurrentTasksInvalidExceptionMessage = Il numero massimo di attività simultanee deve essere >=1, ma è stato ottenuto: {0} maximumConcurrentTasksLessThanMinimumExceptionMessage = Il numero massimo di attività simultanee non può essere inferiore al minimo di {0}, ma è stato ottenuto: {1} taskDoesNotExistExceptionMessage = L'attività '{0}' non esiste. -'@ +cacheStorageNotFoundForRetrieveExceptionMessage = Memoria cache con nome '{0}' non trovata durante il tentativo di recuperare l'elemento memorizzato nella cache '{1}'. +cacheStorageNotFoundForSetExceptionMessage = Memoria cache con nome '{0}' non trovata durante il tentativo di impostare l'elemento memorizzato nella cache '{1}'. +cacheStorageNotFoundForExistsExceptionMessage = Memoria cache con nome '{0}' non trovata durante il tentativo di verificare se l'elemento memorizzato nella cache '{1}' esiste. +cacheStorageNotFoundForRemoveExceptionMessage = Memoria cache con nome '{0}' non trovata durante il tentativo di rimuovere l'elemento memorizzato nella cache '{1}'. +cacheStorageNotFoundForClearExceptionMessage = Memoria cache con nome '{0}' non trovata durante il tentativo di cancellare la cache. +cacheStorageAlreadyExistsExceptionMessage = Memoria cache con nome '{0}' esiste già. +pathToIconForGuiDoesNotExistExceptionMessage = Il percorso dell'icona per la GUI non esiste: {0} +invalidHostnameSuppliedExceptionMessage = Nome host fornito non valido: {0} +endpointAlreadyDefinedExceptionMessage = Un endpoint denominato '{0}' è già stato definito. +certificateExpiredExceptionMessage = Il certificato '{0}' è scaduto: {1} +endpointNotDefinedForRedirectingExceptionMessage = Non è stato definito un endpoint denominato '{0}' per il reindirizzamento. +'@ \ No newline at end of file diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index ca3ca814d..394da2111 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -212,4 +212,15 @@ taskAlreadyDefinedExceptionMessage = [タスク] {0}: タスクは既に定義 maximumConcurrentTasksInvalidExceptionMessage = 最大同時タスク数は >=1 でなければなりませんが、取得した値は: {0} maximumConcurrentTasksLessThanMinimumExceptionMessage = 最大同時タスク数は最小値 {0} より少なくてはいけませんが、取得した値は: {1} taskDoesNotExistExceptionMessage = タスク '{0}' は存在しません。 -'@ +cacheStorageNotFoundForRetrieveExceptionMessage = キャッシュされたアイテム '{1}' を取得しようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。 +cacheStorageNotFoundForSetExceptionMessage = キャッシュされたアイテム '{1}' を設定しようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。 +cacheStorageNotFoundForExistsExceptionMessage = キャッシュされたアイテム '{1}' が存在するかどうかを確認しようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。 +cacheStorageNotFoundForRemoveExceptionMessage = キャッシュされたアイテム '{1}' を削除しようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。 +cacheStorageNotFoundForClearExceptionMessage = キャッシュをクリアしようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。 +cacheStorageAlreadyExistsExceptionMessage = 名前 '{0}' のキャッシュストレージは既に存在します。 +pathToIconForGuiDoesNotExistExceptionMessage = GUI用アイコンのパスが存在しません: {0} +invalidHostnameSuppliedExceptionMessage = 無効なホスト名が指定されました: {0} +endpointAlreadyDefinedExceptionMessage = 名前 '{0}' のエンドポイントは既に定義されています。 +certificateExpiredExceptionMessage = 証明書 '{0}' の有効期限が切れています: {1} +endpointNotDefinedForRedirectingExceptionMessage = リダイレクトのために名前 '{0}' のエンドポイントが定義されていません。 +'@ \ No newline at end of file diff --git a/src/Locales/kr/Pode.psd1 b/src/Locales/kr/Pode.psd1 index b97c3b476..65d83d1f6 100644 --- a/src/Locales/kr/Pode.psd1 +++ b/src/Locales/kr/Pode.psd1 @@ -212,4 +212,15 @@ taskAlreadyDefinedExceptionMessage = [작업] {0}: 작업이 이미 정의되었 maximumConcurrentTasksInvalidExceptionMessage = 최대 동시 작업 수는 >=1이어야 하지만 받은 값: {0} maximumConcurrentTasksLessThanMinimumExceptionMessage = 최대 동시 작업 수는 최소값 {0}보다 작을 수 없지만 받은 값: {1} taskDoesNotExistExceptionMessage = 작업 '{0}'이(가) 존재하지 않습니다. -'@ +cacheStorageNotFoundForRetrieveExceptionMessage = 캐시된 항목 '{1}'을(를) 검색하려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다. +cacheStorageNotFoundForSetExceptionMessage = 캐시된 항목 '{1}'을(를) 설정하려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다. +cacheStorageNotFoundForExistsExceptionMessage = 캐시된 항목 '{1}'이(가) 존재하는지 확인하려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다. +cacheStorageNotFoundForRemoveExceptionMessage = 캐시된 항목 '{1}'을(를) 제거하려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다. +cacheStorageNotFoundForClearExceptionMessage = 캐시를 지우려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다. +cacheStorageAlreadyExistsExceptionMessage = 이름이 '{0}'인 캐시 스토리지가 이미 존재합니다. +pathToIconForGuiDoesNotExistExceptionMessage = GUI용 아이콘의 경로가 존재하지 않습니다: {0} +invalidHostnameSuppliedExceptionMessage = 제공된 호스트 이름이 잘못되었습니다: {0} +endpointAlreadyDefinedExceptionMessage = 이름이 '{0}'인 엔드포인트가 이미 정의되어 있습니다. +certificateExpiredExceptionMessage = 인증서 '{0}'이(가) 만료되었습니다: {1} +endpointNotDefinedForRedirectingExceptionMessage = 리디렉션을 위해 이름이 '{0}'인 엔드포인트가 정의되지 않았습니다. +'@ \ No newline at end of file diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index ebd68c5f2..5d3590ab8 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -212,4 +212,15 @@ taskAlreadyDefinedExceptionMessage = [Zadanie] {0}: Zadanie już zdefiniowane. maximumConcurrentTasksInvalidExceptionMessage = Maksymalna liczba jednoczesnych zadań musi wynosić >=1, ale otrzymano: {0} maximumConcurrentTasksLessThanMinimumExceptionMessage = Maksymalna liczba jednoczesnych zadań nie może być mniejsza niż minimum {0}, ale otrzymano: {1} taskDoesNotExistExceptionMessage = Zadanie '{0}' nie istnieje. +cacheStorageNotFoundForRetrieveExceptionMessage = Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby pobrania elementu z pamięci podręcznej '{1}'. +cacheStorageNotFoundForSetExceptionMessage = Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby ustawienia elementu w pamięci podręcznej '{1}'. +cacheStorageNotFoundForExistsExceptionMessage = Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby sprawdzenia, czy element w pamięci podręcznej '{1}' istnieje. +cacheStorageNotFoundForRemoveExceptionMessage = Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby usunięcia elementu z pamięci podręcznej '{1}'. +cacheStorageNotFoundForClearExceptionMessage = Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby wyczyszczenia pamięci podręcznej. +cacheStorageAlreadyExistsExceptionMessage = Magazyn pamięci podręcznej o nazwie '{0}' już istnieje. +pathToIconForGuiDoesNotExistExceptionMessage = Ścieżka do ikony dla GUI nie istnieje: {0} +invalidHostnameSuppliedExceptionMessage = Podano nieprawidłową nazwę hosta: {0} +endpointAlreadyDefinedExceptionMessage = Punkt końcowy o nazwie '{0}' został już zdefiniowany. +certificateExpiredExceptionMessage = Certyfikat '{0}' wygasł: {1} +endpointNotDefinedForRedirectingExceptionMessage = Nie zdefiniowano punktu końcowego o nazwie '{0}' do przekierowania. '@ diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index 6e3852ce3..f781c1db9 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -212,4 +212,15 @@ taskAlreadyDefinedExceptionMessage = [Tarefa] {0}: Tarefa já definida. maximumConcurrentTasksInvalidExceptionMessage = O número máximo de tarefas concorrentes deve ser >=1, mas foi obtido: {0} maximumConcurrentTasksLessThanMinimumExceptionMessage = O número máximo de tarefas concorrentes não pode ser menor que o mínimo de {0}, mas foi obtido: {1} taskDoesNotExistExceptionMessage = A tarefa '{0}' não existe. -'@ +cacheStorageNotFoundForRetrieveExceptionMessage = Armazenamento em cache com o nome '{0}' não encontrado ao tentar recuperar o item em cache '{1}'. +cacheStorageNotFoundForSetExceptionMessage = Armazenamento em cache com o nome '{0}' não encontrado ao tentar definir o item em cache '{1}'. +cacheStorageNotFoundForExistsExceptionMessage = Armazenamento em cache com o nome '{0}' não encontrado ao tentar verificar se o item em cache '{1}' existe. +cacheStorageNotFoundForRemoveExceptionMessage = Armazenamento em cache com o nome '{0}' não encontrado ao tentar remover o item em cache '{1}'. +cacheStorageNotFoundForClearExceptionMessage = Armazenamento em cache com o nome '{0}' não encontrado ao tentar limpar o cache. +cacheStorageAlreadyExistsExceptionMessage = Armazenamento em cache com o nome '{0}' já existe. +pathToIconForGuiDoesNotExistExceptionMessage = O caminho para o ícone da interface gráfica não existe: {0} +invalidHostnameSuppliedExceptionMessage = Nome de host fornecido inválido: {0} +endpointAlreadyDefinedExceptionMessage = Um ponto de extremidade chamado '{0}' já foi definido. +certificateExpiredExceptionMessage = O certificado '{0}' expirou: {1} +endpointNotDefinedForRedirectingExceptionMessage = Não foi definido um ponto de extremidade chamado '{0}' para redirecionamento. +'@ \ No newline at end of file diff --git a/src/Locales/zn/Pode.psd1 b/src/Locales/zn/Pode.psd1 index 31a057dcd..fb65c72fe 100644 --- a/src/Locales/zn/Pode.psd1 +++ b/src/Locales/zn/Pode.psd1 @@ -212,4 +212,15 @@ taskAlreadyDefinedExceptionMessage = [任务] {0}: 任务已定义。 maximumConcurrentTasksInvalidExceptionMessage = 最大并发任务数必须 >=1,但获得: {0} maximumConcurrentTasksLessThanMinimumExceptionMessage = 最大并发任务数不能小于最小值 {0},但获得: {1} taskDoesNotExistExceptionMessage = 任务 '{0}' 不存在。 -'@ +cacheStorageNotFoundForRetrieveExceptionMessage = 尝试检索缓存项 '{1}' 时,找不到名为 '{0}' 的缓存存储。 +cacheStorageNotFoundForSetExceptionMessage = 尝试设置缓存项 '{1}' 时,找不到名为 '{0}' 的缓存存储。 +cacheStorageNotFoundForExistsExceptionMessage = 尝试检查缓存项 '{1}' 是否存在时,找不到名为 '{0}' 的缓存存储。 +cacheStorageNotFoundForRemoveExceptionMessage = 尝试删除缓存项 '{1}' 时,找不到名为 '{0}' 的缓存存储。 +cacheStorageNotFoundForClearExceptionMessage = 尝试清除缓存时,找不到名为 '{0}' 的缓存存储。 +cacheStorageAlreadyExistsExceptionMessage = 名为 '{0}' 的缓存存储已存在。 +pathToIconForGuiDoesNotExistExceptionMessage = GUI 图标的路径不存在: {0} +invalidHostnameSuppliedExceptionMessage = 提供的主机名无效: {0} +endpointAlreadyDefinedExceptionMessage = 名为 '{0}' 的端点已定义。 +certificateExpiredExceptionMessage = 证书 '{0}' 已过期: {1} +endpointNotDefinedForRedirectingExceptionMessage = 未定义用于重定向的名为 '{0}' 的端点。 +'@ \ No newline at end of file diff --git a/src/Pode.psm1 b/src/Pode.psm1 index 7b19597a3..b5dd14e84 100644 --- a/src/Pode.psm1 +++ b/src/Pode.psm1 @@ -49,7 +49,7 @@ if ($null -eq $tmpPodeLocale) { try { # Create the global msgTable read-only variable - New-Variable -Name 'PodeLocale' -Value $tmpPodeLocale -Scope Global -Option ReadOnly -Force + New-Variable -Name 'PodeLocale' -Value $tmpPodeLocale -Scope script -Option ReadOnly -Force -Description "Localization HashTable" # load assemblies Add-Type -AssemblyName System.Web -ErrorAction Stop diff --git a/src/Public/Caching.ps1 b/src/Public/Caching.ps1 index 30fff5c41..acddbfde1 100644 --- a/src/Public/Caching.ps1 +++ b/src/Public/Caching.ps1 @@ -57,7 +57,8 @@ function Get-PodeCache { } # storage not found! - throw "Cache storage with name '$($Storage)' not found when attempting to retrieve cached item '$($Key)'" + # Cache storage with name not found when attempting to retrieve cached item + throw ($PodeLocale.cacheStorageNotFoundForRetrieveExceptionMessage -f $Storage, $Key) } <# @@ -139,7 +140,8 @@ function Set-PodeCache { # storage not found! else { - throw "Cache storage with name '$($Storage)' not found when attempting to set cached item '$($Key)'" + # Cache storage with name not found when attempting to set cached item + throw ($PodeLocale.cacheStorageNotFoundForSetExceptionMessage -f $Storage, $Key) } } @@ -190,7 +192,8 @@ function Test-PodeCache { } # storage not found! - throw "Cache storage with name '$($Storage)' not found when attempting to check if cached item '$($Key)' exists" + # Cache storage with name not found when attempting to check if cached item exists + throw ($PodeLocale.cacheStorageNotFoundForExistsExceptionMessage -f $Storage, $Key) } <# @@ -241,7 +244,8 @@ function Remove-PodeCache { # storage not found! else { - throw "Cache storage with name '$($Storage)' not found when attempting to remove cached item '$($Key)'" + # Cache storage with name not found when attempting to remove cached item + throw ($PodeLocale.cacheStorageNotFoundForRemoveExceptionMessage -f $Storage, $Key) } } @@ -286,7 +290,8 @@ function Clear-PodeCache { # storage not found! else { - throw "Cache storage with name '$($Storage)' not found when attempting to clear cached" + # Cache storage with name not found when attempting to clear the cache + throw ($PodeLocale.cacheStorageNotFoundForClearExceptionMessage -f $Storage) } } @@ -355,7 +360,8 @@ function Add-PodeCacheStorage { # test if storage already exists if (Test-PodeCacheStorage -Name $Name) { - throw "Cache Storage with name '$($Name) already exists" + # Cache Storage with name already exists + throw ($PodeLocale.cacheStorageAlreadyExistsExceptionMessage -f $Name) } # add cache storage diff --git a/src/Public/Core.ps1 b/src/Public/Core.ps1 index c09fb3c43..3d7f274c6 100644 --- a/src/Public/Core.ps1 +++ b/src/Public/Core.ps1 @@ -658,7 +658,8 @@ function Show-PodeGui { if (![string]::IsNullOrWhiteSpace($Icon)) { $PodeContext.Server.Gui.Icon = Get-PodeRelativePath -Path $Icon -JoinRoot -Resolve if (!(Test-Path $PodeContext.Server.Gui.Icon)) { - throw "Path to icon for GUI does not exist: $($PodeContext.Server.Gui.Icon)" + # Path to icon for GUI does not exist + throw ($PodeLocale.pathToIconForGuiDoesNotExistExceptionMessage -f $PodeContext.Server.Gui.Icon) } } @@ -931,7 +932,8 @@ function Add-PodeEndpoint { # parse the endpoint for host/port info if (![string]::IsNullOrWhiteSpace($Hostname) -and !(Test-PodeHostname -Hostname $Hostname)) { - throw "Invalid hostname supplied: $($Hostname)" + # Invalid hostname supplied + throw ($PodeLocale.invalidHostnameSuppliedExceptionMessage -f $Hostname) } if ((Test-PodeHostname -Hostname $Address) -and ($Address -inotin @('localhost', 'all'))) { @@ -951,7 +953,8 @@ function Add-PodeEndpoint { } if ($PodeContext.Server.Endpoints.ContainsKey($Name)) { - throw "An endpoint with the name '$($Name)' has already been defined" + # An endpoint named has already been defined + throw ($PodeLocale.endpointAlreadyDefinedExceptionMessage -f $Name) } # protocol must be https for client certs, or hosted behind a proxy like iis @@ -1085,7 +1088,8 @@ function Add-PodeEndpoint { # fail if the cert is expired if ($obj.Certificate.Raw.NotAfter -lt [datetime]::Now) { - throw "The certificate '$($obj.Certificate.Raw.Subject)' has expired: $($obj.Certificate.Raw.NotAfter)" + # The certificate has expired + throw ($PodeLocale.certificateExpiredExceptionMessage -f $obj.Certificate.Raw.Subject, $obj.Certificate.Raw.NotAfter) } } @@ -1111,7 +1115,8 @@ function Add-PodeEndpoint { # ensure the name exists if (Test-PodeIsEmpty $redir_endpoint) { - throw "An endpoint with the name '$($RedirectTo)' has not been defined for redirecting" + # An endpoint named has not been defined for redirecting + throw ($PodeLocale.endpointNotDefinedForRedirectingExceptionMessage -f $RedirectTo) } # build the redirect route @@ -1319,7 +1324,8 @@ function Set-PodeDefaultFolder { $PodeContext.Server.DefaultFolders[$Type] = $Path } else { - throw "Folder $Path doesn't exist" + # Path does not exist + throw ($PodeLocale.pathNotExistExceptionMessage -f $Path) } } diff --git a/tests/unit/Localization.Tests.ps1 b/tests/unit/Localization.Tests.ps1 index 5c178e8c4..0c44f77b1 100644 --- a/tests/unit/Localization.Tests.ps1 +++ b/tests/unit/Localization.Tests.ps1 @@ -1,5 +1,5 @@ -# Save this script as Check-LocalizationKeys.Tests.ps1 [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingInvokeExpression', '')] param() Describe 'Localization Check' { From 3eb155e0baf4d0097a08645496966a0f1f0cf13c Mon Sep 17 00:00:00 2001 From: mdaneri Date: Mon, 3 Jun 2024 20:23:05 -0700 Subject: [PATCH 030/177] additional messages --- src/Locales/ar/Pode.psd1 | 15 ++++++++++++++- src/Locales/de/Pode.psd1 | 15 ++++++++++++++- src/Locales/en/Pode.psd1 | 13 +++++++++++++ src/Locales/es/Pode.psd1 | 15 ++++++++++++++- src/Locales/fr/Pode.psd1 | 15 ++++++++++++++- src/Locales/it/Pode.psd1 | 15 ++++++++++++++- src/Locales/ja/Pode.psd1 | 15 ++++++++++++++- src/Locales/kr/Pode.psd1 | 15 ++++++++++++++- src/Locales/pl/Pode.psd1 | 15 ++++++++++++++- src/Locales/pt/Pode.psd1 | 15 ++++++++++++++- src/Locales/zn/Pode.psd1 | 15 ++++++++++++++- src/Public/FileWatchers.ps1 | 3 ++- src/Public/Handlers.ps1 | 3 ++- src/Public/Logging.ps1 | 12 ++++++++---- src/Public/Middleware.ps1 | 10 +++++++--- src/Public/Responses.ps1 | 12 ++++++++---- tests/unit/Middleware.Tests.ps1 | 2 +- 17 files changed, 181 insertions(+), 24 deletions(-) diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 52c18f946..f6c69780f 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -223,4 +223,17 @@ invalidHostnameSuppliedExceptionMessage = اسم المضيف المقدم غي endpointAlreadyDefinedExceptionMessage = تم تعريف نقطة نهاية باسم '{0}' بالفعل. certificateExpiredExceptionMessage = الشهادة '{0}' منتهية الصلاحية: {1} endpointNotDefinedForRedirectingExceptionMessage = لم يتم تعريف نقطة نهاية باسم '{0}' لإعادة التوجيه. -'@ \ No newline at end of file +fileWatcherAlreadyDefinedExceptionMessage = تم تعريف مراقب الملفات باسم '{0}' بالفعل. +handlerAlreadyDefinedExceptionMessage = [{0}] {1}: تم تعريف المعالج بالفعل. +maxDaysInvalidExceptionMessage = يجب أن يكون MaxDays 0 أو أكبر، ولكن تم الحصول على: {0} +maxSizeInvalidExceptionMessage = يجب أن يكون MaxSize 0 أو أكبر، ولكن تم الحصول على: {0} +loggingMethodAlreadyDefinedExceptionMessage = تم تعريف طريقة التسجيل بالفعل: {0} +loggingMethodRequiresValidScriptBlockExceptionMessage = تتطلب طريقة الإخراج المقدمة لطريقة التسجيل '{0}' ScriptBlock صالح. +csrfCookieRequiresSecretExceptionMessage = عند استخدام ملفات تعريف الارتباط لـ CSRF، يكون السر مطلوبًا. يمكنك تقديم سر أو تعيين السر العالمي لملف تعريف الارتباط - (Set-PodeCookieSecret '' -Global) +bodyParserAlreadyDefinedForContentTypeExceptionMessage = تم تعريف محلل الجسم لنوع المحتوى {0} بالفعل. +middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: تم تعريف الوسيط بالفعل. +parameterNotSuppliedInRequestExceptionMessage = لم يتم توفير معلمة باسم '{0}' في الطلب أو لا توجد بيانات متاحة. +noDataForFileUploadedExceptionMessage = لا توجد بيانات للملف '{0}' الذي تم تحميله في الطلب. +viewsFolderNameAlreadyExistsExceptionMessage = اسم مجلد العرض موجود بالفعل: {0} +viewsPathDoesNotExistExceptionMessage = مسار العرض غير موجود: {0} +'@ diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index 9432c4d0a..35843ca23 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -223,4 +223,17 @@ invalidHostnameSuppliedExceptionMessage = Der angegebene Hostname ist ungültig: endpointAlreadyDefinedExceptionMessage = Ein Endpunkt mit dem Namen '{0}' wurde bereits definiert. certificateExpiredExceptionMessage = Das Zertifikat '{0}' ist abgelaufen: {1} endpointNotDefinedForRedirectingExceptionMessage = Ein Endpunkt mit dem Namen '{0}' wurde nicht für die Weiterleitung definiert. -'@ \ No newline at end of file +fileWatcherAlreadyDefinedExceptionMessage = Ein Dateiwächter mit dem Namen '{0}' wurde bereits definiert. +handlerAlreadyDefinedExceptionMessage = [{0}] {1}: Handler bereits definiert. +maxDaysInvalidExceptionMessage = MaxDays muss 0 oder größer sein, aber erhalten: {0} +maxSizeInvalidExceptionMessage = MaxSize muss 0 oder größer sein, aber erhalten: {0} +loggingMethodAlreadyDefinedExceptionMessage = Logging-Methode bereits definiert: {0} +loggingMethodRequiresValidScriptBlockExceptionMessage = Die angegebene Ausgabemethode für die Logging-Methode '{0}' erfordert einen gültigen ScriptBlock. +csrfCookieRequiresSecretExceptionMessage = Beim Verwenden von Cookies für CSRF ist ein Geheimnis erforderlich. Sie können ein Geheimnis angeben oder das globale Cookie-Geheimnis festlegen - (Set-PodeCookieSecret '' -Global) +bodyParserAlreadyDefinedForContentTypeExceptionMessage = Für den Inhaltstyp {0} ist bereits ein Body-Parser definiert. +middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: Middleware bereits definiert. +parameterNotSuppliedInRequestExceptionMessage = Ein Parameter namens '{0}' wurde in der Anfrage nicht angegeben oder es sind keine Daten verfügbar. +noDataForFileUploadedExceptionMessage = Keine Daten für die Datei '{0}' wurden in der Anfrage hochgeladen. +viewsFolderNameAlreadyExistsExceptionMessage = Der Name des Ansichtsordners existiert bereits: {0} +viewsPathDoesNotExistExceptionMessage = Der Ansichtsordnerpfad existiert nicht: {0} +'@ diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index be481da96..39cc9e07c 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -223,4 +223,17 @@ invalidHostnameSuppliedExceptionMessage = Invalid hostname supplied: {0} endpointAlreadyDefinedExceptionMessage = An endpoint named '{0}' has already been defined. certificateExpiredExceptionMessage = The certificate '{0}' has expired: {1} endpointNotDefinedForRedirectingExceptionMessage = An endpoint named '{0}' has not been defined for redirecting. +fileWatcherAlreadyDefinedExceptionMessage = A File Watcher named '{0}' has already been defined. +handlerAlreadyDefinedExceptionMessage = [{0}] {1}: Handler already defined. +maxDaysInvalidExceptionMessage = MaxDays must be 0 or greater, but got: {0} +maxSizeInvalidExceptionMessage = MaxSize must be 0 or greater, but got: {0} +loggingMethodAlreadyDefinedExceptionMessage = Logging method already defined: {0} +loggingMethodRequiresValidScriptBlockExceptionMessage = The supplied output Method for the '{0}' Logging method requires a valid ScriptBlock. +csrfCookieRequiresSecretExceptionMessage = When using cookies for CSRF, a Secret is required. You can either supply a Secret or set the Cookie global secret - (Set-PodeCookieSecret '' -Global) +bodyParserAlreadyDefinedForContentTypeExceptionMessage = A body-parser is already defined for the {0} content-type. +middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: Middleware already defined. +parameterNotSuppliedInRequestExceptionMessage = A parameter called '{0}' was not supplied in the request or has no data available. +noDataForFileUploadedExceptionMessage = No data for file '{0}' was uploaded in the request. +viewsFolderNameAlreadyExistsExceptionMessage = The Views folder name already exists: {0} +viewsPathDoesNotExistExceptionMessage = The Views path does not exist: {0} '@ \ No newline at end of file diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 55c93fcb9..8750ddca8 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -223,4 +223,17 @@ invalidHostnameSuppliedExceptionMessage = Nombre de host no válido proporcionad endpointAlreadyDefinedExceptionMessage = Ya se ha definido un punto de conexión llamado '{0}'. certificateExpiredExceptionMessage = El certificado '{0}' ha expirado: {1} endpointNotDefinedForRedirectingExceptionMessage = No se ha definido un punto de conexión llamado '{0}' para la redirección. -'@ \ No newline at end of file +fileWatcherAlreadyDefinedExceptionMessage = Un Observador de Archivos llamado '{0}' ya ha sido definido. +handlerAlreadyDefinedExceptionMessage = [{0}] {1}: Manejador ya definido. +maxDaysInvalidExceptionMessage = MaxDays debe ser igual o mayor que 0, pero se obtuvo: {0} +maxSizeInvalidExceptionMessage = MaxSize debe ser igual o mayor que 0, pero se obtuvo: {0} +loggingMethodAlreadyDefinedExceptionMessage = Método de registro ya definido: {0} +loggingMethodRequiresValidScriptBlockExceptionMessage = El método de salida proporcionado para el método de registro '{0}' requiere un ScriptBlock válido. +csrfCookieRequiresSecretExceptionMessage = Al usar cookies para CSRF, se requiere un Secreto. Puedes proporcionar un Secreto o establecer el secreto global de la Cookie - (Set-PodeCookieSecret '' -Global) +bodyParserAlreadyDefinedForContentTypeExceptionMessage = Un analizador de cuerpo ya está definido para el tipo de contenido {0}. +middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: Middleware ya definido. +parameterNotSuppliedInRequestExceptionMessage = No se ha proporcionado un parámetro llamado '{0}' en la solicitud o no hay datos disponibles. +noDataForFileUploadedExceptionMessage = No se han subido datos para el archivo '{0}' en la solicitud. +viewsFolderNameAlreadyExistsExceptionMessage = El nombre de la carpeta Views ya existe: {0} +viewsPathDoesNotExistExceptionMessage = La ruta de las Views no existe: {0} +'@ diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index 543933edb..f57a8c05a 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -223,4 +223,17 @@ invalidHostnameSuppliedExceptionMessage = Nom d'hôte fourni invalide: {0} endpointAlreadyDefinedExceptionMessage = Un point de terminaison nommé '{0}' a déjà été défini. certificateExpiredExceptionMessage = Le certificat '{0}' a expiré: {1} endpointNotDefinedForRedirectingExceptionMessage = Un point de terminaison nommé '{0}' n'a pas été défini pour la redirection. -'@ \ No newline at end of file +fileWatcherAlreadyDefinedExceptionMessage = Un Observateur de fichiers nommé '{0}' a déjà été défini. +handlerAlreadyDefinedExceptionMessage = [{0}] {1}: Handler déjà défini. +maxDaysInvalidExceptionMessage = MaxDays doit être égal ou supérieur à 0, mais a obtenu: {0} +maxSizeInvalidExceptionMessage = MaxSize doit être égal ou supérieur à 0, mais a obtenu: {0} +loggingMethodAlreadyDefinedExceptionMessage = Méthode de journalisation déjà définie: {0} +loggingMethodRequiresValidScriptBlockExceptionMessage = La méthode de sortie fournie pour la méthode de journalisation '{0}' nécessite un ScriptBlock valide. +csrfCookieRequiresSecretExceptionMessage = Lors de l'utilisation de cookies pour CSRF, un Secret est requis. Vous pouvez soit fournir un Secret, soit définir le Secret global du Cookie - (Set-PodeCookieSecret '' -Global) +bodyParserAlreadyDefinedForContentTypeExceptionMessage = Un analyseur de corps est déjà défini pour le type de contenu {0}. +middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: Middleware déjà défini. +parameterNotSuppliedInRequestExceptionMessage = Un paramètre nommé '{0}' n'a pas été fourni dans la demande ou aucune donnée n'est disponible. +noDataForFileUploadedExceptionMessage = Aucune donnée pour le fichier '{0}' n'a été téléchargée dans la demande. +viewsFolderNameAlreadyExistsExceptionMessage = Le nom du dossier Views existe déjà: {0} +viewsPathDoesNotExistExceptionMessage = Le chemin des Views n'existe pas: {0} +'@ diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index dde46a290..492704735 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -223,4 +223,17 @@ invalidHostnameSuppliedExceptionMessage = Nome host fornito non valido: {0} endpointAlreadyDefinedExceptionMessage = Un endpoint denominato '{0}' è già stato definito. certificateExpiredExceptionMessage = Il certificato '{0}' è scaduto: {1} endpointNotDefinedForRedirectingExceptionMessage = Non è stato definito un endpoint denominato '{0}' per il reindirizzamento. -'@ \ No newline at end of file +fileWatcherAlreadyDefinedExceptionMessage = Un File Watcher con il nome '{0}' è già stato definito. +handlerAlreadyDefinedExceptionMessage = [{0}] {1}: Handler già definito. +maxDaysInvalidExceptionMessage = MaxDays deve essere 0 o superiore, ma è stato ottenuto: {0} +maxSizeInvalidExceptionMessage = MaxSize deve essere 0 o superiore, ma è stato ottenuto: {0} +loggingMethodAlreadyDefinedExceptionMessage = Metodo di registrazione già definito: {0} +loggingMethodRequiresValidScriptBlockExceptionMessage = Il metodo di output fornito per il metodo di registrazione '{0}' richiede un ScriptBlock valido. +csrfCookieRequiresSecretExceptionMessage = Quando si usano i cookie per CSRF, è necessario un Segreto. Puoi fornire un Segreto o impostare il segreto globale del Cookie - (Set-PodeCookieSecret '' -Global) +bodyParserAlreadyDefinedForContentTypeExceptionMessage = Un body-parser è già definito per il tipo di contenuto {0}. +middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: Middleware già definito. +parameterNotSuppliedInRequestExceptionMessage = Un parametro chiamato '{0}' non è stato fornito nella richiesta o non ci sono dati disponibili. +noDataForFileUploadedExceptionMessage = Nessun dato per il file '{0}' è stato caricato nella richiesta. +viewsFolderNameAlreadyExistsExceptionMessage = Il nome della cartella Views esiste già: {0} +viewsPathDoesNotExistExceptionMessage = Il percorso delle Views non esiste: {0} +'@ diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index 394da2111..67eb0b99a 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -223,4 +223,17 @@ invalidHostnameSuppliedExceptionMessage = 無効なホスト名が指定され endpointAlreadyDefinedExceptionMessage = 名前 '{0}' のエンドポイントは既に定義されています。 certificateExpiredExceptionMessage = 証明書 '{0}' の有効期限が切れています: {1} endpointNotDefinedForRedirectingExceptionMessage = リダイレクトのために名前 '{0}' のエンドポイントが定義されていません。 -'@ \ No newline at end of file +fileWatcherAlreadyDefinedExceptionMessage = 名前 '{0}' のファイルウォッチャーは既に定義されています。 +handlerAlreadyDefinedExceptionMessage = [{0}] {1}: ハンドラは既に定義されています。 +maxDaysInvalidExceptionMessage = MaxDaysは0以上でなければなりませんが、受け取った値は: {0} +maxSizeInvalidExceptionMessage = MaxSizeは0以上でなければなりませんが、受け取った値は: {0} +loggingMethodAlreadyDefinedExceptionMessage = ログ記録方法は既に定義されています: {0} +loggingMethodRequiresValidScriptBlockExceptionMessage = '{0}' ログ記録方法のために提供された出力方法は、有効なScriptBlockが必要です。 +csrfCookieRequiresSecretExceptionMessage = CSRFのためにクッキーを使用する場合、秘密が必要です。秘密を提供するか、クッキーのグローバル秘密を設定してください - (Set-PodeCookieSecret '' -Global) +bodyParserAlreadyDefinedForContentTypeExceptionMessage = {0} コンテンツタイプ用のボディパーサーは既に定義されています。 +middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: ミドルウェアは既に定義されています。 +parameterNotSuppliedInRequestExceptionMessage = リクエストに '{0}' という名前のパラメータが提供されていないか、データがありません。 +noDataForFileUploadedExceptionMessage = リクエストでアップロードされたファイル '{0}' のデータがありません。 +viewsFolderNameAlreadyExistsExceptionMessage = ビューのフォルダ名は既に存在します: {0} +viewsPathDoesNotExistExceptionMessage = ビューのパスが存在しません: {0} +'@ diff --git a/src/Locales/kr/Pode.psd1 b/src/Locales/kr/Pode.psd1 index 65d83d1f6..8061338e5 100644 --- a/src/Locales/kr/Pode.psd1 +++ b/src/Locales/kr/Pode.psd1 @@ -223,4 +223,17 @@ invalidHostnameSuppliedExceptionMessage = 제공된 호스트 이름이 잘못 endpointAlreadyDefinedExceptionMessage = 이름이 '{0}'인 엔드포인트가 이미 정의되어 있습니다. certificateExpiredExceptionMessage = 인증서 '{0}'이(가) 만료되었습니다: {1} endpointNotDefinedForRedirectingExceptionMessage = 리디렉션을 위해 이름이 '{0}'인 엔드포인트가 정의되지 않았습니다. -'@ \ No newline at end of file +fileWatcherAlreadyDefinedExceptionMessage = '{0}'라는 이름의 파일 감시자가 이미 정의되었습니다. +handlerAlreadyDefinedExceptionMessage = [{0}] {1}: 핸들러가 이미 정의되었습니다. +maxDaysInvalidExceptionMessage = MaxDays는 0 이상이어야 하지만, 받은 값: {0} +maxSizeInvalidExceptionMessage = MaxSize는 0 이상이어야 하지만, 받은 값: {0} +loggingMethodAlreadyDefinedExceptionMessage = 로깅 방법이 이미 정의되었습니다: {0} +loggingMethodRequiresValidScriptBlockExceptionMessage = '{0}' 로깅 방법에 대한 제공된 출력 방법은 유효한 ScriptBlock이 필요합니다. +csrfCookieRequiresSecretExceptionMessage = CSRF에 대해 쿠키를 사용할 때, 비밀이 필요합니다. 비밀을 제공하거나 전역 비밀 쿠키를 설정하십시오 - (Set-PodeCookieSecret '' -Global) +bodyParserAlreadyDefinedForContentTypeExceptionMessage = {0} 콘텐츠 유형에 대한 바디 파서가 이미 정의되어 있습니다. +middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: 미들웨어가 이미 정의되었습니다. +parameterNotSuppliedInRequestExceptionMessage = 요청에 '{0}'라는 이름의 매개변수가 제공되지 않았거나 데이터가 없습니다. +noDataForFileUploadedExceptionMessage = 요청에서 업로드된 파일 '{0}'에 대한 데이터가 없습니다. +viewsFolderNameAlreadyExistsExceptionMessage = 뷰 폴더 이름이 이미 존재합니다: {0} +viewsPathDoesNotExistExceptionMessage = 뷰 경로가 존재하지 않습니다: {0} +'@ diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index 5d3590ab8..ab898006d 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -223,4 +223,17 @@ invalidHostnameSuppliedExceptionMessage = Podano nieprawidłową nazwę hosta: { endpointAlreadyDefinedExceptionMessage = Punkt końcowy o nazwie '{0}' został już zdefiniowany. certificateExpiredExceptionMessage = Certyfikat '{0}' wygasł: {1} endpointNotDefinedForRedirectingExceptionMessage = Nie zdefiniowano punktu końcowego o nazwie '{0}' do przekierowania. -'@ +fileWatcherAlreadyDefinedExceptionMessage = Obserwator plików o nazwie '{0}' został już zdefiniowany. +handlerAlreadyDefinedExceptionMessage = [{0}] {1}: Handler już zdefiniowany. +maxDaysInvalidExceptionMessage = MaxDays musi wynosić 0 lub więcej, ale otrzymano: {0} +maxSizeInvalidExceptionMessage = MaxSize musi wynosić 0 lub więcej, ale otrzymano: {0} +loggingMethodAlreadyDefinedExceptionMessage = Metoda logowania już zdefiniowana: {0} +loggingMethodRequiresValidScriptBlockExceptionMessage = Dostarczona metoda wyjściowa dla metody logowania '{0}' wymaga poprawnego ScriptBlock. +csrfCookieRequiresSecretExceptionMessage = Podczas używania ciasteczek do CSRF, wymagany jest Sekret. Możesz dostarczyć Sekret lub ustawić globalny sekret dla ciasteczek - (Set-PodeCookieSecret '' -Global) +bodyParserAlreadyDefinedForContentTypeExceptionMessage = Parser treści dla typu zawartości {0} jest już zdefiniowany. +middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: Middleware już zdefiniowany. +parameterNotSuppliedInRequestExceptionMessage = Parametr o nazwie '{0}' nie został dostarczony w żądaniu lub nie ma dostępnych danych. +noDataForFileUploadedExceptionMessage = Brak danych dla pliku '{0}' przesłanego w żądaniu. +viewsFolderNameAlreadyExistsExceptionMessage = Nazwa folderu Widoków już istnieje: {0} +viewsPathDoesNotExistExceptionMessage = Ścieżka do Widoków nie istnieje: {0} +'@ \ No newline at end of file diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index f781c1db9..1337c0229 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -223,4 +223,17 @@ invalidHostnameSuppliedExceptionMessage = Nome de host fornecido inválido: {0} endpointAlreadyDefinedExceptionMessage = Um ponto de extremidade chamado '{0}' já foi definido. certificateExpiredExceptionMessage = O certificado '{0}' expirou: {1} endpointNotDefinedForRedirectingExceptionMessage = Não foi definido um ponto de extremidade chamado '{0}' para redirecionamento. -'@ \ No newline at end of file +fileWatcherAlreadyDefinedExceptionMessage = Um Observador de Arquivos chamado '{0}' já foi definido. +handlerAlreadyDefinedExceptionMessage = [{0}] {1}: Manipulador já definido. +maxDaysInvalidExceptionMessage = MaxDays deve ser igual ou maior que 0, mas foi obtido: {0} +maxSizeInvalidExceptionMessage = MaxSize deve ser igual ou maior que 0, mas foi obtido: {0} +loggingMethodAlreadyDefinedExceptionMessage = Método de registro já definido: {0} +loggingMethodRequiresValidScriptBlockExceptionMessage = O método de saída fornecido para o método de registro '{0}' requer um ScriptBlock válido. +csrfCookieRequiresSecretExceptionMessage = Ao usar cookies para CSRF, é necessário um Segredo. Você pode fornecer um Segredo ou definir o segredo global do Cookie - (Set-PodeCookieSecret '' -Global) +bodyParserAlreadyDefinedForContentTypeExceptionMessage = Um body-parser já está definido para o tipo de conteúdo {0}. +middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: Middleware já definido. +parameterNotSuppliedInRequestExceptionMessage = Um parâmetro chamado '{0}' não foi fornecido na solicitação ou não há dados disponíveis. +noDataForFileUploadedExceptionMessage = Nenhum dado para o arquivo '{0}' foi enviado na solicitação. +viewsFolderNameAlreadyExistsExceptionMessage = O nome da pasta Views já existe: {0} +viewsPathDoesNotExistExceptionMessage = O caminho das Views não existe: {0} +'@ diff --git a/src/Locales/zn/Pode.psd1 b/src/Locales/zn/Pode.psd1 index fb65c72fe..11f737bea 100644 --- a/src/Locales/zn/Pode.psd1 +++ b/src/Locales/zn/Pode.psd1 @@ -223,4 +223,17 @@ invalidHostnameSuppliedExceptionMessage = 提供的主机名无效: {0} endpointAlreadyDefinedExceptionMessage = 名为 '{0}' 的端点已定义。 certificateExpiredExceptionMessage = 证书 '{0}' 已过期: {1} endpointNotDefinedForRedirectingExceptionMessage = 未定义用于重定向的名为 '{0}' 的端点。 -'@ \ No newline at end of file +fileWatcherAlreadyDefinedExceptionMessage = 名为 '{0}' 的文件监视器已定义。 +handlerAlreadyDefinedExceptionMessage = [{0}] {1}: 处理程序已定义。 +maxDaysInvalidExceptionMessage = MaxDays 必须大于或等于 0,但得到: {0} +maxSizeInvalidExceptionMessage = MaxSize 必须大于或等于 0,但得到: {0} +loggingMethodAlreadyDefinedExceptionMessage = 日志记录方法已定义: {0} +loggingMethodRequiresValidScriptBlockExceptionMessage = 为 '{0}' 日志记录方法提供的输出方法需要有效的 ScriptBlock。 +csrfCookieRequiresSecretExceptionMessage = 使用 CSRF 的 Cookie 时,需要一个密钥。您可以提供一个密钥或设置全局 Cookie 密钥 - (Set-PodeCookieSecret '' -Global) +bodyParserAlreadyDefinedForContentTypeExceptionMessage = 已为 {0} 内容类型定义了一个 body-parser。 +middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: 中间件已定义。 +parameterNotSuppliedInRequestExceptionMessage = 请求中未提供名为 '{0}' 的参数或没有可用数据。 +noDataForFileUploadedExceptionMessage = 请求中未上传文件 '{0}' 的数据。 +viewsFolderNameAlreadyExistsExceptionMessage = 视图文件夹名称已存在: {0} +viewsPathDoesNotExistExceptionMessage = 视图路径不存在: {0} +'@ diff --git a/src/Public/FileWatchers.ps1 b/src/Public/FileWatchers.ps1 index 027fbfb6a..8b4a4aeca 100644 --- a/src/Public/FileWatchers.ps1 +++ b/src/Public/FileWatchers.ps1 @@ -143,7 +143,8 @@ function Add-PodeFileWatcher { # test if we have the file watcher already if (Test-PodeFileWatcher -Name $Name) { - throw "A File Watcher with the name '$($Name)' has already been defined" + # A File Watcher named has already been defined + throw ($PodeLocale.fileWatcherAlreadyDefinedExceptionMessage -f $Name) } # if we have a file path supplied, load that path as a scriptblock diff --git a/src/Public/Handlers.ps1 b/src/Public/Handlers.ps1 index eb418f2f0..59c31ba58 100644 --- a/src/Public/Handlers.ps1 +++ b/src/Public/Handlers.ps1 @@ -59,7 +59,8 @@ function Add-PodeHandler { # ensure handler isn't already set if ($PodeContext.Server.Handlers[$Type].ContainsKey($Name)) { - throw "[$($Type)] $($Name): Handler already defined" + # [Type] Name: Handler already defined + throw ($PodeLocale.handlerAlreadyDefinedExceptionMessage -f $Type, $Name) } # if we have a file path supplied, load that path as a scriptblock diff --git a/src/Public/Logging.ps1 b/src/Public/Logging.ps1 index 65f4cb739..9420fe53a 100644 --- a/src/Public/Logging.ps1 +++ b/src/Public/Logging.ps1 @@ -106,7 +106,8 @@ function New-PodeLoggingMethod { [Parameter(ParameterSetName = 'File')] [ValidateScript({ if ($_ -lt 0) { - throw "MaxDays must be 0 or greater, but got: $($_)s" + # MaxDays must be 0 or greater, but got + throw ($PodeLocale.maxDaysInvalidExceptionMessage -f $MaxDays) } return $true @@ -117,7 +118,8 @@ function New-PodeLoggingMethod { [Parameter(ParameterSetName = 'File')] [ValidateScript({ if ($_ -lt 0) { - throw "MaxSize must be 0 or greater, but got: $($_)s" + # MaxSize must be 0 or greater, but got + throw ($PodeLocale.maxSizeInvalidExceptionMessage -f $MaxSize) } return $true @@ -442,12 +444,14 @@ function Add-PodeLogger { # ensure the name doesn't already exist if ($PodeContext.Server.Logging.Types.ContainsKey($Name)) { - throw "Logging method already defined: $($Name)" + # Logging method already defined + throw ($PodeLocale.loggingMethodAlreadyDefinedExceptionMessage -f $Name) } # ensure the Method contains a scriptblock if (Test-PodeIsEmpty $Method.ScriptBlock) { - throw "The supplied output Method for the '$($Name)' Logging method requires a valid ScriptBlock" + # The supplied output Method for the Logging method requires a valid ScriptBlock + throw ($PodeLocale.loggingMethodRequiresValidScriptBlockExceptionMessage -f $Name) } # check for scoped vars diff --git a/src/Public/Middleware.ps1 b/src/Public/Middleware.ps1 index 6d36795ad..0cb9f3c30 100644 --- a/src/Public/Middleware.ps1 +++ b/src/Public/Middleware.ps1 @@ -250,7 +250,8 @@ function Initialize-PodeCsrf { $Secret = (Protect-PodeValue -Value $Secret -Default (Get-PodeCookieSecret -Global)) if (Test-PodeIsEmpty $Secret) { - throw "When using cookies for CSRF, a Secret is required. You can either supply a Secret, or set the Cookie global secret - (Set-PodeCookieSecret '' -Global)" + # When using cookies for CSRF, a Secret is required + throw $PodeLocale.csrfCookieRequiresSecretExceptionMessage } } @@ -361,7 +362,8 @@ function Add-PodeBodyParser { # if a parser for the type already exists, fail if ($PodeContext.Server.BodyParsers.ContainsKey($ContentType)) { - throw "There is already a body parser defined for the $($ContentType) content-type" + # A body-parser is already defined for the content-type + throw ($PodeLocale.bodyParserAlreadyDefinedForContentTypeExceptionMessage -f $ContentType) } # check for scoped vars @@ -460,7 +462,9 @@ function Add-PodeMiddleware { # ensure name doesn't already exist if (($PodeContext.Server.Middleware | Where-Object { $_.Name -ieq $Name } | Measure-Object).Count -gt 0) { - throw "[Middleware] $($Name): Middleware already defined" + # [Middleware] Name: Middleware already defined + throw ($PodeLocale.middlewareAlreadyDefinedExceptionMessage -f $Name) + } # if it's a script - call New-PodeMiddleware diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index 46b55ad1e..1a577b9ff 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -1297,7 +1297,8 @@ function Save-PodeRequestFile { # ensure the parameter name exists in data if (!(Test-PodeRequestFile -Key $Key)) { - throw "A parameter called '$($Key)' was not supplied in the request, or has no data available" + # A parameter called was not supplied in the request or has no data available + throw ($PodeLocale.parameterNotSuppliedInRequestExceptionMessage -f $Key) } # get the file names @@ -1313,7 +1314,8 @@ function Save-PodeRequestFile { # ensure the file data exists foreach ($file in $files) { if (!$WebEvent.Files.ContainsKey($file)) { - throw "No data for file '$($file)' was uploaded in the request" + # No data for file was uploaded in the request + throw ($PodeLocale.noDataForFileUploadedExceptionMessage -f $file) } } @@ -1639,13 +1641,15 @@ function Add-PodeViewFolder { # ensure the folder doesn't already exist if ($PodeContext.Server.Views.ContainsKey($Name)) { - throw "The Views folder name already exists: $($Name)" + # The Views folder name already exists + throw ($PodeLocale.viewsFolderNameAlreadyExistsExceptionMessage -f $Name) } # ensure the path exists at server root $Source = Get-PodeRelativePath -Path $Source -JoinRoot if (!(Test-PodePath -Path $Source -NoStatus)) { - throw "The Views path does not exist: $($Source)" + # The Views path does not exist + throw ($PodeLocale.viewsPathDoesNotExistExceptionMessage -f $Source) } # setup a temp drive for the path diff --git a/tests/unit/Middleware.Tests.ps1 b/tests/unit/Middleware.Tests.ps1 index ef168eefe..85e8cca5f 100644 --- a/tests/unit/Middleware.Tests.ps1 +++ b/tests/unit/Middleware.Tests.ps1 @@ -902,7 +902,7 @@ Describe 'Add-PodeBodyParser' { It 'Fails because a script is already defined' { $PodeContext = @{ 'Server' = @{ 'BodyParsers' = @{} } } { Add-PodeBodyParser -ContentType 'text/xml' -ScriptBlock {} } | Should -Not -Throw - { Add-PodeBodyParser -ContentType 'text/xml' -ScriptBlock {} } | Should -Throw -ExpectedMessage '*already a body parser*' + { Add-PodeBodyParser -ContentType 'text/xml' -ScriptBlock {} } | Should -Throw -ExpectedMessage ($PodeLocale.bodyParserAlreadyDefinedForContentTypeExceptionMessage -f 'text/xml') # A body-parser is already defined for the {0} content-type. } It 'Fails on an invalid content-type' { From 4dc45a5ce230fee3da29e05f8b8d57c6724a5ccb Mon Sep 17 00:00:00 2001 From: mdaneri Date: Tue, 4 Jun 2024 10:02:12 -0700 Subject: [PATCH 031/177] Improve Module import and added documentation regarding localization --- docs/Tutorials/Basics.md | 44 ++++++++++-- examples/FileBrowser/FileBrowser.ps1 | 19 ++--- src/Locales/{kr => ko}/Pode.psd1 | 0 src/Pode.psm1 | 104 +++++++++++++++------------ tests/unit/Middleware.Tests.ps1 | 1 + 5 files changed, 110 insertions(+), 58 deletions(-) rename src/Locales/{kr => ko}/Pode.psd1 (100%) diff --git a/docs/Tutorials/Basics.md b/docs/Tutorials/Basics.md index 482ba68ae..e35bf2217 100644 --- a/docs/Tutorials/Basics.md +++ b/docs/Tutorials/Basics.md @@ -1,15 +1,25 @@ # Basics +!!! Warning +It’s important to note that you can initiate only one server per PowerShell instance. This means that within a single PowerShell or pwsh session, you can only run one server at a time. If you need to run multiple servers, you’ll need to start additional PowerShell or pwsh instances. Each instance of PowerShell or pwsh can then run its own server. This is a fundamental aspect of how Pode operates. Please keep this in mind when designing your scripts and infrastructure. -!!! warning - You can only start one server in your script - -Although not required, it is recommended to import the Pode module using a maximum version, to avoid any breaking changes from new major versions: +While it’s not mandatory, we strongly recommend importing the Pode module with a specified maximum version. This practice helps to prevent potential issues arising from breaking changes introduced in new major versions: ```powershell Import-Module -Name Pode -MaximumVersion 2.99.99 ``` +To further enhance the robustness of your code, consider wrapping the import statement within a try/catch block. This way, if the module fails to load, your script won’t proceed, preventing possible errors or unexpected behavior: + +```powershell +try { + Import-Module -Name Pode -MaximumVersion 2.99.99 +} catch { + Write-Error "Failed to load the Pode module" + throw +} +``` + The script for your server should be set in the [`Start-PodeServer`](../../Functions/Core/Start-PodeServer) function, via the `-ScriptBlock` parameter. The following example will listen over HTTP on port 8080, and expose a simple HTML page of running processes at `http://localhost:8080/processes`: ```powershell @@ -72,3 +82,29 @@ PS> Start-PodeServer -FilePath './File.ps1' !!! tip Normally when you restart your Pode server any changes to the main scriptblock don't reflect. However, if you reference a file instead, then restarting the server will reload the scriptblock from that file - so any changes will reflect. + +## Localization + +Pode has built-in support for internationalization (i18n). + +You can enforce a specific localization when importing the Pode module by using the UICulture argument. This argument accepts a culture code, which specifies the language and regional settings to use. + +Here’s an example of how to enforce Korean localization: + +```powershell +Import-Module -Name Pode -ArgumentList @{ UICulture = 'ko-KR' } +``` + +In this example, 'ko-KR' is the culture code for Korean as used in South Korea. You can replace 'ko-KR' with the culture code for any other language or region. + +As an alternative to specifying the UICulture when importing the Pode module, you can also change the UICulture within the PowerShell environment itself. + +This can be done using the following command: + +```powershell +[System.Threading.Thread]::CurrentThread.CurrentUICulture = 'ko-KR' +``` + +This command changes the UICulture for the current PowerShell session to Korean as used in South Korea. + +Please note that this change is temporary and will only affect the current session. If you open a new PowerShell session, it will use the default UICulture. \ No newline at end of file diff --git a/examples/FileBrowser/FileBrowser.ps1 b/examples/FileBrowser/FileBrowser.ps1 index ab94f1977..03a1cd929 100644 --- a/examples/FileBrowser/FileBrowser.ps1 +++ b/examples/FileBrowser/FileBrowser.ps1 @@ -1,11 +1,14 @@ -$FileBrowserPath = Split-Path -Parent -Path $MyInvocation.MyCommand.Path -$podePath = Split-Path -Parent -Path (Split-Path -Parent -Path $FileBrowserPath) -if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { - Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop -} -else { - Import-Module -Name 'Pode' -} + try { + $FileBrowserPath = Split-Path -Parent -Path $MyInvocation.MyCommand.Path + $podePath = Split-Path -Parent -Path (Split-Path -Parent -Path $FileBrowserPath) + if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { + Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop + } + else { + Import-Module -Name 'Pode' -ErrorAction Stop + } + } + catch { throw } $directoryPath = $podePath # Start Pode server diff --git a/src/Locales/kr/Pode.psd1 b/src/Locales/ko/Pode.psd1 similarity index 100% rename from src/Locales/kr/Pode.psd1 rename to src/Locales/ko/Pode.psd1 diff --git a/src/Pode.psm1 b/src/Pode.psm1 index b5dd14e84..1142e5353 100644 --- a/src/Pode.psm1 +++ b/src/Pode.psm1 @@ -21,8 +21,19 @@ Import-Module -Name "Pode" -ArgumentList 'it-SM' Uses the Italian San Marino region culture. -.NOTES +.EXAMPLE + try { + Import-Module -Name Pode -MaximumVersion 2.99.99 + } catch { + Write-Error "Failed to load the Pode module" + throw + } + The import statement is within a try/catch block. + This way, if the module fails to load, your script won’t proceed, preventing possible errors or unexpected behavior. + + .NOTES This is the entry point for the Pode module. + #> param( @@ -31,25 +42,30 @@ param( # root path $root = Split-Path -Parent -Path $MyInvocation.MyCommand.Path +$localesPath = (Join-Path -Path $root -ChildPath 'Locales') + # Import localized messages if ([string]::IsNullOrEmpty($UICulture)) { $UICulture = $PsUICulture } -#Culture list available here https://azuliadesigns.com/c-sharp-tutorials/list-net-culture-country-codes/ -Import-LocalizedData -BindingVariable tmpPodeLocale -BaseDirectory (Join-Path -Path $root -ChildPath 'Locales') -UICulture $UICulture -ErrorAction:SilentlyContinue -if ($null -eq $tmpPodeLocale) { +try { try { - Import-LocalizedData -BindingVariable tmpPodeLocale -BaseDirectory (Join-Path -Path $root -ChildPath 'Locales') -UICulture 'en' -ErrorAction:Stop + #The list of all available supported culture is available here https://azuliadesigns.com/c-sharp-tutorials/list-net-culture-country-codes/ + + # ErrorAction:SilentlyContinue is not sufficient to avoid Import-LocalizedData to generate an exception when the Culture file is not the right format + Import-LocalizedData -BindingVariable tmpPodeLocale -BaseDirectory $localesPath -UICulture $UICulture -ErrorAction:SilentlyContinue + if ($null -eq $tmpPodeLocale) { + $UICulture = 'en' + Import-LocalizedData -BindingVariable tmpPodeLocale -BaseDirectory $localesPath -UICulture $UICulture -ErrorAction:Stop + } } catch { - throw + throw "Failed to Import Localized Data $(Join-Path -Path $localesPath -ChildPath $UICulture -AdditionalChildPath 'Pode.psd1') $_" } -} -try { # Create the global msgTable read-only variable - New-Variable -Name 'PodeLocale' -Value $tmpPodeLocale -Scope script -Option ReadOnly -Force -Description "Localization HashTable" + New-Variable -Name 'PodeLocale' -Value $tmpPodeLocale -Scope script -Option ReadOnly -Force -Description 'Localization HashTable' # load assemblies Add-Type -AssemblyName System.Web -ErrorAction Stop @@ -60,24 +76,20 @@ try { # Import the module manifest to access its properties $moduleManifest = Import-PowerShellDataFile -Path $moduleManifestPath -ErrorAction Stop -} -catch { - throw -} -$podeDll = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq 'Pode' } -if ($podeDll) { - if ( $moduleManifest.ModuleVersion -ne '$version$') { - $moduleVersion = ([version]::new($moduleManifest.ModuleVersion + '.0')) - if ($podeDll.GetName().Version -ne $moduleVersion) { - # An existing incompatible Pode.DLL version {0} is loaded. Version {1} is required. Open a new Powershell/pwsh session and retry. - throw ($PodeLocale.incompatiblePodeDllExceptionMessage -f $podeDll.GetName().Version, $moduleVersion) + $podeDll = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq 'Pode' } + + if ($podeDll) { + if ( $moduleManifest.ModuleVersion -ne '$version$') { + $moduleVersion = ([version]::new($moduleManifest.ModuleVersion + '.0')) + if ($podeDll.GetName().Version -ne $moduleVersion) { + # An existing incompatible Pode.DLL version {0} is loaded. Version {1} is required. Open a new Powershell/pwsh session and retry. + throw ($PodeLocale.incompatiblePodeDllExceptionMessage -f $podeDll.GetName().Version, $moduleVersion) + } } } -} -else { - try { + else { if ($PSVersionTable.PSVersion -ge [version]'7.4.0') { Add-Type -LiteralPath "$($root)/Libs/net8.0/Pode.dll" -ErrorAction Stop } @@ -88,33 +100,33 @@ else { Add-Type -LiteralPath "$($root)/Libs/netstandard2.0/Pode.dll" -ErrorAction Stop } } - catch { - throw - } -} - -# load private functions -Get-ChildItem "$($root)/Private/*.ps1" | ForEach-Object { . ([System.IO.Path]::GetFullPath($_)) } + # load private functions + Get-ChildItem "$($root)/Private/*.ps1" | ForEach-Object { . ([System.IO.Path]::GetFullPath($_)) } -# only import public functions -$sysfuncs = Get-ChildItem Function: + # only import public functions + $sysfuncs = Get-ChildItem Function: -# only import public alias -$sysaliases = Get-ChildItem Alias: + # only import public alias + $sysaliases = Get-ChildItem Alias: -# load public functions -Get-ChildItem "$($root)/Public/*.ps1" | ForEach-Object { . ([System.IO.Path]::GetFullPath($_)) } + # load public functions + Get-ChildItem "$($root)/Public/*.ps1" | ForEach-Object { . ([System.IO.Path]::GetFullPath($_)) } -# get functions from memory and compare to existing to find new functions added -$funcs = Get-ChildItem Function: | Where-Object { $sysfuncs -notcontains $_ } -$aliases = Get-ChildItem Alias: | Where-Object { $sysaliases -notcontains $_ } -# export the module's public functions -if ($funcs) { - if ($aliases) { - Export-ModuleMember -Function ($funcs.Name) -Alias $aliases.Name - } - else { - Export-ModuleMember -Function ($funcs.Name) + # get functions from memory and compare to existing to find new functions added + $funcs = Get-ChildItem Function: | Where-Object { $sysfuncs -notcontains $_ } + $aliases = Get-ChildItem Alias: | Where-Object { $sysaliases -notcontains $_ } + # export the module's public functions + if ($funcs) { + if ($aliases) { + Export-ModuleMember -Function ($funcs.Name) -Alias $aliases.Name + } + else { + Export-ModuleMember -Function ($funcs.Name) + } } } +catch { + throw "Failed to load the Pode module. $_" +} + diff --git a/tests/unit/Middleware.Tests.ps1 b/tests/unit/Middleware.Tests.ps1 index 85e8cca5f..7a96151ca 100644 --- a/tests/unit/Middleware.Tests.ps1 +++ b/tests/unit/Middleware.Tests.ps1 @@ -1,4 +1,5 @@ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] param() BeforeAll { From 2d12ce6d6e7243b832183dc5b8c775003704033f Mon Sep 17 00:00:00 2001 From: mdaneri Date: Wed, 5 Jun 2024 09:23:32 -0700 Subject: [PATCH 032/177] Additional Messages --- src/Locales/ar/Pode.psd1 | 20 +++++++++++++++++++- src/Locales/de/Pode.psd1 | 20 +++++++++++++++++++- src/Locales/en/Pode.psd1 | 18 ++++++++++++++++++ src/Locales/es/Pode.psd1 | 18 ++++++++++++++++++ src/Locales/fr/Pode.psd1 | 20 +++++++++++++++++++- src/Locales/it/Pode.psd1 | 20 +++++++++++++++++++- src/Locales/ja/Pode.psd1 | 20 +++++++++++++++++++- src/Locales/ko/Pode.psd1 | 20 +++++++++++++++++++- src/Locales/pl/Pode.psd1 | 18 ++++++++++++++++++ src/Locales/pt/Pode.psd1 | 18 ++++++++++++++++++ src/Locales/zn/Pode.psd1 | 20 +++++++++++++++++++- src/Public/Responses.ps1 | 3 ++- src/Public/Schedules.ps1 | 33 ++++++++++++++++++++++----------- src/Public/Threading.ps1 | 24 ++++++++++++++++-------- src/Public/Timers.ps1 | 18 ++++++++++++------ tests/unit/Responses.Tests.ps1 | 2 +- tests/unit/Schedules.Tests.ps1 | 3 ++- tests/unit/Timers.Tests.ps1 | 6 ++++-- 18 files changed, 264 insertions(+), 37 deletions(-) diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index f6c69780f..860c0f7c3 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -236,4 +236,22 @@ parameterNotSuppliedInRequestExceptionMessage = لم يتم توفير معلم noDataForFileUploadedExceptionMessage = لا توجد بيانات للملف '{0}' الذي تم تحميله في الطلب. viewsFolderNameAlreadyExistsExceptionMessage = اسم مجلد العرض موجود بالفعل: {0} viewsPathDoesNotExistExceptionMessage = مسار العرض غير موجود: {0} -'@ +timerAlreadyDefinedExceptionMessage = [المؤقت] {0}: المؤقت معرف بالفعل. +timerParameterMustBeGreaterThanZeroExceptionMessage = [المؤقت] {0}: {1} يجب أن يكون أكبر من 0. +timerDoesNotExistExceptionMessage = المؤقت '{0}' غير موجود. +mutexAlreadyExistsExceptionMessage = يوجد بالفعل Mutex بالاسم التالي: {0} +noMutexFoundExceptionMessage = لم يتم العثور على Mutex باسم '{0}' +failedToAcquireMutexOwnershipExceptionMessage = فشل في الحصول على ملكية Mutex. اسم Mutex: {0} +semaphoreAlreadyExistsExceptionMessage = يوجد بالفعل Semaphore بالاسم التالي: {0} +failedToAcquireSemaphoreOwnershipExceptionMessage = فشل في الحصول على ملكية Semaphore. اسم Semaphore: {0} +scheduleAlreadyDefinedExceptionMessage = [الجدول الزمني] {0}: الجدول الزمني معرف بالفعل. +scheduleCannotHaveNegativeLimitExceptionMessage = [الجدول الزمني] {0}: لا يمكن أن يكون له حد سلبي. +scheduleEndTimeMustBeInFutureExceptionMessage = [الجدول الزمني] {0}: يجب أن تكون قيمة EndTime في المستقبل. +scheduleStartTimeAfterEndTimeExceptionMessage = [الجدول الزمني] {0}: لا يمكن أن يكون 'StartTime' بعد 'EndTime' +maximumConcurrentSchedulesInvalidExceptionMessage = يجب أن تكون الجداول الزمنية المتزامنة القصوى >=1 ولكن تم الحصول على: {0} +maximumConcurrentSchedulesLessThanMinimumExceptionMessage = لا يمكن أن تكون الجداول الزمنية المتزامنة القصوى أقل من الحد الأدنى {0} ولكن تم الحصول على: {1} +scheduleDoesNotExistExceptionMessage = الجدول الزمني '{0}' غير موجود. +suppliedDateBeforeScheduleStartTimeExceptionMessage = التاريخ المقدم قبل وقت بدء الجدول الزمني في {0} +suppliedDateAfterScheduleEndTimeExceptionMessage = التاريخ المقدم بعد وقت انتهاء الجدول الزمني في {0} +noSemaphoreFoundExceptionMessage = لم يتم العثور على Semaphore باسم '{0}' +'@ \ No newline at end of file diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index 35843ca23..f5ef28281 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -236,4 +236,22 @@ parameterNotSuppliedInRequestExceptionMessage = Ein Parameter namens '{0}' wurde noDataForFileUploadedExceptionMessage = Keine Daten für die Datei '{0}' wurden in der Anfrage hochgeladen. viewsFolderNameAlreadyExistsExceptionMessage = Der Name des Ansichtsordners existiert bereits: {0} viewsPathDoesNotExistExceptionMessage = Der Ansichtsordnerpfad existiert nicht: {0} -'@ +timerAlreadyDefinedExceptionMessage = [Timer] {0}: Timer bereits definiert. +timerParameterMustBeGreaterThanZeroExceptionMessage = [Timer] {0}: {1} muss größer als 0 sein. +timerDoesNotExistExceptionMessage = Timer '{0}' existiert nicht. +mutexAlreadyExistsExceptionMessage = Ein Mutex mit folgendem Namen existiert bereits: {0} +noMutexFoundExceptionMessage = Kein Mutex mit dem Namen '{0}' gefunden. +failedToAcquireMutexOwnershipExceptionMessage = Fehler beim Erwerb des Mutex-Besitzes. Mutex-Name: {0} +semaphoreAlreadyExistsExceptionMessage = Ein Semaphor mit folgendem Namen existiert bereits: {0} +failedToAcquireSemaphoreOwnershipExceptionMessage = Fehler beim Erwerb des Semaphor-Besitzes. Semaphor-Name: {0} +scheduleAlreadyDefinedExceptionMessage = [Zeitplan] {0}: Zeitplan bereits definiert. +scheduleCannotHaveNegativeLimitExceptionMessage = [Zeitplan] {0}: Kann kein negatives Limit haben. +scheduleEndTimeMustBeInFutureExceptionMessage = [Zeitplan] {0}: Der Wert für EndTime muss in der Zukunft liegen. +scheduleStartTimeAfterEndTimeExceptionMessage = [Zeitplan] {0}: StartTime kann nicht nach EndTime liegen. +maximumConcurrentSchedulesInvalidExceptionMessage = Maximale gleichzeitige Zeitpläne müssen >=1 sein, aber erhalten: {0} +maximumConcurrentSchedulesLessThanMinimumExceptionMessage = Maximale gleichzeitige Zeitpläne dürfen nicht kleiner als das Minimum von {0} sein, aber erhalten: {1} +scheduleDoesNotExistExceptionMessage = Zeitplan '{0}' existiert nicht. +suppliedDateBeforeScheduleStartTimeExceptionMessage = Das angegebene Datum liegt vor der Startzeit des Zeitplans bei {0} +suppliedDateAfterScheduleEndTimeExceptionMessage = Das angegebene Datum liegt nach der Endzeit des Zeitplans bei {0} +noSemaphoreFoundExceptionMessage = Kein Semaphor mit dem Namen '{0}' gefunden. +'@ \ No newline at end of file diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 39cc9e07c..75b0e7d63 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -236,4 +236,22 @@ parameterNotSuppliedInRequestExceptionMessage = A parameter called '{0}' was not noDataForFileUploadedExceptionMessage = No data for file '{0}' was uploaded in the request. viewsFolderNameAlreadyExistsExceptionMessage = The Views folder name already exists: {0} viewsPathDoesNotExistExceptionMessage = The Views path does not exist: {0} +timerAlreadyDefinedExceptionMessage = [Timer] {0}: Timer already defined. +timerParameterMustBeGreaterThanZeroExceptionMessage = [Timer] {0}: {1} must be greater than 0. +timerDoesNotExistExceptionMessage = Timer '{0}' does not exist. +mutexAlreadyExistsExceptionMessage = A mutex with the following name already exists: {0} +noMutexFoundExceptionMessage = No mutex found called '{0}' +failedToAcquireMutexOwnershipExceptionMessage = Failed to acquire mutex ownership. Mutex name: {0} +semaphoreAlreadyExistsExceptionMessage = A semaphore with the following name already exists: {0} +failedToAcquireSemaphoreOwnershipExceptionMessage = Failed to acquire semaphore ownership. Semaphore name: {0} +scheduleAlreadyDefinedExceptionMessage = [Schedule] {0}: Schedule already defined. +scheduleCannotHaveNegativeLimitExceptionMessage = [Schedule] {0}: Cannot have a negative limit. +scheduleEndTimeMustBeInFutureExceptionMessage = [Schedule] {0}: The EndTime value must be in the future. +scheduleStartTimeAfterEndTimeExceptionMessage = [Schedule] {0}: Cannot have a StartTime after the EndTime +maximumConcurrentSchedulesInvalidExceptionMessage = Maximum concurrent schedules must be >=1 but got: {0} +maximumConcurrentSchedulesLessThanMinimumExceptionMessage = Maximum concurrent schedules cannot be less than the minimum of {0} but got: {1} +scheduleDoesNotExistExceptionMessage = Schedule '{0}' does not exist. +suppliedDateBeforeScheduleStartTimeExceptionMessage = Supplied date is before the start time of the schedule at {0} +suppliedDateAfterScheduleEndTimeExceptionMessage = Supplied date is after the end time of the schedule at {0} +noSemaphoreFoundExceptionMessage = No semaphore found called '{0}' '@ \ No newline at end of file diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 8750ddca8..c35c47a85 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -236,4 +236,22 @@ parameterNotSuppliedInRequestExceptionMessage = No se ha proporcionado un parám noDataForFileUploadedExceptionMessage = No se han subido datos para el archivo '{0}' en la solicitud. viewsFolderNameAlreadyExistsExceptionMessage = El nombre de la carpeta Views ya existe: {0} viewsPathDoesNotExistExceptionMessage = La ruta de las Views no existe: {0} +timerAlreadyDefinedExceptionMessage = [Temporizador] {0}: Temporizador ya definido. +timerParameterMustBeGreaterThanZeroExceptionMessage = [Temporizador] {0}: {1} debe ser mayor que 0. +timerDoesNotExistExceptionMessage = El temporizador '{0}' no existe. +mutexAlreadyExistsExceptionMessage = Ya existe un mutex con el siguiente nombre: {0} +noMutexFoundExceptionMessage = No se encontró ningún mutex llamado '{0}' +failedToAcquireMutexOwnershipExceptionMessage = No se pudo adquirir la propiedad del mutex. Nombre del mutex: {0} +semaphoreAlreadyExistsExceptionMessage = Ya existe un semáforo con el siguiente nombre: {0} +failedToAcquireSemaphoreOwnershipExceptionMessage = No se pudo adquirir la propiedad del semáforo. Nombre del semáforo: {0} +scheduleAlreadyDefinedExceptionMessage = [Horario] {0}: Horario ya definido. +scheduleCannotHaveNegativeLimitExceptionMessage = [Horario] {0}: No puede tener un límite negativo. +scheduleEndTimeMustBeInFutureExceptionMessage = [Horario] {0}: El valor de EndTime debe estar en el futuro. +scheduleStartTimeAfterEndTimeExceptionMessage = [Horario] {0}: No puede tener un 'StartTime' después del 'EndTime' +maximumConcurrentSchedulesInvalidExceptionMessage = Los horarios simultáneos máximos deben ser >=1 pero se obtuvo: {0} +maximumConcurrentSchedulesLessThanMinimumExceptionMessage = Los horarios simultáneos máximos no pueden ser inferiores al mínimo de {0} pero se obtuvo: {1} +scheduleDoesNotExistExceptionMessage = El horario '{0}' no existe. +suppliedDateBeforeScheduleStartTimeExceptionMessage = La fecha proporcionada es anterior a la hora de inicio del horario en {0} +suppliedDateAfterScheduleEndTimeExceptionMessage = La fecha proporcionada es posterior a la hora de finalización del horario en {0} +noSemaphoreFoundExceptionMessage = No se encontró ningún semáforo llamado '{0}' '@ diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index f57a8c05a..deb46d92d 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -236,4 +236,22 @@ parameterNotSuppliedInRequestExceptionMessage = Un paramètre nommé '{0}' n'a p noDataForFileUploadedExceptionMessage = Aucune donnée pour le fichier '{0}' n'a été téléchargée dans la demande. viewsFolderNameAlreadyExistsExceptionMessage = Le nom du dossier Views existe déjà: {0} viewsPathDoesNotExistExceptionMessage = Le chemin des Views n'existe pas: {0} -'@ +timerAlreadyDefinedExceptionMessage = [Minuteur] {0}: Minuteur déjà défini. +timerParameterMustBeGreaterThanZeroExceptionMessage = [Minuteur] {0}: {1} doit être supérieur à 0. +timerDoesNotExistExceptionMessage = Minuteur '{0}' n'existe pas. +mutexAlreadyExistsExceptionMessage = Un mutex avec le nom suivant existe déjà: {0} +noMutexFoundExceptionMessage = Aucun mutex trouvé appelé '{0}' +failedToAcquireMutexOwnershipExceptionMessage = Échec de l'acquisition de la propriété du mutex. Nom du mutex: {0} +semaphoreAlreadyExistsExceptionMessage = Un sémaphore avec le nom suivant existe déjà: {0} +failedToAcquireSemaphoreOwnershipExceptionMessage = Échec de l'acquisition de la propriété du sémaphore. Nom du sémaphore: {0} +scheduleAlreadyDefinedExceptionMessage = [Calendrier] {0}: Calendrier déjà défini. +scheduleCannotHaveNegativeLimitExceptionMessage = [Calendrier] {0}: Ne peut pas avoir de limite négative. +scheduleEndTimeMustBeInFutureExceptionMessage = [Calendrier] {0}: La valeur de EndTime doit être dans le futur. +scheduleStartTimeAfterEndTimeExceptionMessage = [Calendrier] {0}: Ne peut pas avoir un 'StartTime' après 'EndTime' +maximumConcurrentSchedulesInvalidExceptionMessage = Les calendriers simultanés maximum doivent être >=1 mais obtenu: {0} +maximumConcurrentSchedulesLessThanMinimumExceptionMessage = Les calendriers simultanés maximum ne peuvent pas être inférieurs au minimum de {0} mais obtenu: {1} +scheduleDoesNotExistExceptionMessage = Le calendrier '{0}' n'existe pas. +suppliedDateBeforeScheduleStartTimeExceptionMessage = La date fournie est antérieure à l'heure de début du calendrier à {0} +suppliedDateAfterScheduleEndTimeExceptionMessage = La date fournie est postérieure à l'heure de fin du calendrier à {0} +noSemaphoreFoundExceptionMessage = Aucun sémaphore trouvé appelé '{0}' +'@ \ No newline at end of file diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index 492704735..6f73d09c9 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -236,4 +236,22 @@ parameterNotSuppliedInRequestExceptionMessage = Un parametro chiamato '{0}' non noDataForFileUploadedExceptionMessage = Nessun dato per il file '{0}' è stato caricato nella richiesta. viewsFolderNameAlreadyExistsExceptionMessage = Il nome della cartella Views esiste già: {0} viewsPathDoesNotExistExceptionMessage = Il percorso delle Views non esiste: {0} -'@ +timerAlreadyDefinedExceptionMessage = [Timer] {0}: Timer già definito. +timerParameterMustBeGreaterThanZeroExceptionMessage = [Timer] {0}: {1} deve essere maggiore di 0. +timerDoesNotExistExceptionMessage = Timer '{0}' non esiste. +mutexAlreadyExistsExceptionMessage = Un mutex con il seguente nome esiste già: {0} +noMutexFoundExceptionMessage = Nessun mutex trovato chiamato '{0}' +failedToAcquireMutexOwnershipExceptionMessage = Impossibile acquisire la proprietà del mutex. Nome del mutex: {0} +semaphoreAlreadyExistsExceptionMessage = Un semaforo con il seguente nome esiste già: {0} +failedToAcquireSemaphoreOwnershipExceptionMessage = Impossibile acquisire la proprietà del semaforo. Nome del semaforo: {0} +scheduleAlreadyDefinedExceptionMessage = [Pianificazione] {0}: Pianificazione già definita. +scheduleCannotHaveNegativeLimitExceptionMessage = [Pianificazione] {0}: Non può avere un limite negativo. +scheduleEndTimeMustBeInFutureExceptionMessage = [Pianificazione] {0}: Il valore di EndTime deve essere nel futuro. +scheduleStartTimeAfterEndTimeExceptionMessage = [Pianificazione] {0}: Non può avere un 'StartTime' dopo 'EndTime' +maximumConcurrentSchedulesInvalidExceptionMessage = I programmi concorrenti massimi devono essere >=1 ma ottenuto: {0} +maximumConcurrentSchedulesLessThanMinimumExceptionMessage = I programmi concorrenti massimi non possono essere inferiori al minimo di {0} ma ottenuto: {1} +scheduleDoesNotExistExceptionMessage = Il programma '{0}' non esiste. +suppliedDateBeforeScheduleStartTimeExceptionMessage = La data fornita è precedente all'ora di inizio del programma a {0} +suppliedDateAfterScheduleEndTimeExceptionMessage = La data fornita è successiva all'ora di fine del programma a {0} +noSemaphoreFoundExceptionMessage = Nessun semaforo trovato chiamato '{0}' +'@ \ No newline at end of file diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index 67eb0b99a..7d3d73bf3 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -236,4 +236,22 @@ parameterNotSuppliedInRequestExceptionMessage = リクエストに '{0}' とい noDataForFileUploadedExceptionMessage = リクエストでアップロードされたファイル '{0}' のデータがありません。 viewsFolderNameAlreadyExistsExceptionMessage = ビューのフォルダ名は既に存在します: {0} viewsPathDoesNotExistExceptionMessage = ビューのパスが存在しません: {0} -'@ +timerAlreadyDefinedExceptionMessage = [タイマー] {0}: タイマーはすでに定義されています。 +timerParameterMustBeGreaterThanZeroExceptionMessage = [タイマー] {0}: {1} は 0 より大きくなければなりません。 +timerDoesNotExistExceptionMessage = タイマー '{0}' は存在しません。 +mutexAlreadyExistsExceptionMessage = 次の名前のミューテックスはすでに存在します: {0} +noMutexFoundExceptionMessage = 名前 '{0}' のミューテックスが見つかりません +failedToAcquireMutexOwnershipExceptionMessage = ミューテックスの所有権を取得できませんでした。ミューテックス名: {0} +semaphoreAlreadyExistsExceptionMessage = 次の名前のセマフォはすでに存在します: {0} +failedToAcquireSemaphoreOwnershipExceptionMessage = セマフォの所有権を取得できませんでした。セマフォ名: {0} +scheduleAlreadyDefinedExceptionMessage = [スケジュール] {0}: スケジュールはすでに定義されています。 +scheduleCannotHaveNegativeLimitExceptionMessage = [スケジュール] {0}: 負の制限を持つことはできません。 +scheduleEndTimeMustBeInFutureExceptionMessage = [スケジュール] {0}: EndTime 値は未来に設定する必要があります。 +scheduleStartTimeAfterEndTimeExceptionMessage = [スケジュール] {0}: 'StartTime' が 'EndTime' の後であることはできません +maximumConcurrentSchedulesInvalidExceptionMessage = 最大同時スケジュール数は 1 以上でなければなりませんが、受け取った値: {0} +maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 最大同時スケジュール数は最小 {0} 未満にすることはできませんが、受け取った値: {1} +scheduleDoesNotExistExceptionMessage = スケジュール '{0}' は存在しません。 +suppliedDateBeforeScheduleStartTimeExceptionMessage = 提供された日付はスケジュールの開始時間 {0} より前です +suppliedDateAfterScheduleEndTimeExceptionMessage = 提供された日付はスケジュールの終了時間 {0} の後です +noSemaphoreFoundExceptionMessage = 名前 '{0}' のセマフォが見つかりません +'@ \ No newline at end of file diff --git a/src/Locales/ko/Pode.psd1 b/src/Locales/ko/Pode.psd1 index 8061338e5..99b918e4a 100644 --- a/src/Locales/ko/Pode.psd1 +++ b/src/Locales/ko/Pode.psd1 @@ -236,4 +236,22 @@ parameterNotSuppliedInRequestExceptionMessage = 요청에 '{0}'라는 이름의 noDataForFileUploadedExceptionMessage = 요청에서 업로드된 파일 '{0}'에 대한 데이터가 없습니다. viewsFolderNameAlreadyExistsExceptionMessage = 뷰 폴더 이름이 이미 존재합니다: {0} viewsPathDoesNotExistExceptionMessage = 뷰 경로가 존재하지 않습니다: {0} -'@ +timerAlreadyDefinedExceptionMessage = [타이머] {0}: 타이머가 이미 정의되어 있습니다. +timerParameterMustBeGreaterThanZeroExceptionMessage = [타이머] {0}: {1}은(는) 0보다 커야 합니다. +timerDoesNotExistExceptionMessage = 타이머 '{0}'이(가) 존재하지 않습니다. +mutexAlreadyExistsExceptionMessage = 이름이 '{0}'인 뮤텍스가 이미 존재합니다. +noMutexFoundExceptionMessage = 이름이 '{0}'인 뮤텍스를 찾을 수 없습니다. +failedToAcquireMutexOwnershipExceptionMessage = 뮤텍스 소유권을 획득하지 못했습니다. 뮤텍스 이름: {0} +semaphoreAlreadyExistsExceptionMessage = 이름이 '{0}'인 세마포어가 이미 존재합니다. +failedToAcquireSemaphoreOwnershipExceptionMessage = 세마포어 소유권을 획득하지 못했습니다. 세마포어 이름: {0} +scheduleAlreadyDefinedExceptionMessage = [스케줄] {0}: 스케줄이 이미 정의되어 있습니다. +scheduleCannotHaveNegativeLimitExceptionMessage = [스케줄] {0}: 음수 한도를 가질 수 없습니다. +scheduleEndTimeMustBeInFutureExceptionMessage = [스케줄] {0}: 종료 시간 값은 미래에 있어야 합니다. +scheduleStartTimeAfterEndTimeExceptionMessage = [스케줄] {0}: 'StartTime'이 'EndTime' 이후일 수 없습니다. +maximumConcurrentSchedulesInvalidExceptionMessage = 최대 동시 스케줄 수는 1 이상이어야 하지만 받은 값: {0} +maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 최대 동시 스케줄 수는 최소 {0}보다 작을 수 없지만 받은 값: {1} +scheduleDoesNotExistExceptionMessage = 스케줄 '{0}'이(가) 존재하지 않습니다. +suppliedDateBeforeScheduleStartTimeExceptionMessage = 제공된 날짜가 스케줄 시작 시간 {0} 이전입니다. +suppliedDateAfterScheduleEndTimeExceptionMessage = 제공된 날짜가 스케줄 종료 시간 {0} 이후입니다. +noSemaphoreFoundExceptionMessage = 이름이 '{0}'인 세마포어를 찾을 수 없습니다. +'@ \ No newline at end of file diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index ab898006d..74ce29cfb 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -236,4 +236,22 @@ parameterNotSuppliedInRequestExceptionMessage = Parametr o nazwie '{0}' nie zost noDataForFileUploadedExceptionMessage = Brak danych dla pliku '{0}' przesłanego w żądaniu. viewsFolderNameAlreadyExistsExceptionMessage = Nazwa folderu Widoków już istnieje: {0} viewsPathDoesNotExistExceptionMessage = Ścieżka do Widoków nie istnieje: {0} +timerAlreadyDefinedExceptionMessage = [Timer] {0}: Timer już zdefiniowany. +timerParameterMustBeGreaterThanZeroExceptionMessage = [Timer] {0}: {1} musi być większy od 0. +timerDoesNotExistExceptionMessage = Timer '{0}' nie istnieje. +mutexAlreadyExistsExceptionMessage = Muteks o nazwie '{0}' już istnieje. +noMutexFoundExceptionMessage = Nie znaleziono muteksu o nazwie '{0}'. +failedToAcquireMutexOwnershipExceptionMessage = Nie udało się przejąć własności muteksu. Nazwa muteksu: {0} +semaphoreAlreadyExistsExceptionMessage = Semafor o nazwie '{0}' już istnieje. +failedToAcquireSemaphoreOwnershipExceptionMessage = Nie udało się przejąć własności semaforu. Nazwa semaforu: {0} +scheduleAlreadyDefinedExceptionMessage = [Harmonogram] {0}: Harmonogram już zdefiniowany. +scheduleCannotHaveNegativeLimitExceptionMessage = [Harmonogram] {0}: Nie może mieć ujemnego limitu. +scheduleEndTimeMustBeInFutureExceptionMessage = [Harmonogram] {0}: Wartość EndTime musi być w przyszłości. +scheduleStartTimeAfterEndTimeExceptionMessage = [Harmonogram] {0}: Nie może mieć 'StartTime' po 'EndTime'. +maximumConcurrentSchedulesInvalidExceptionMessage = Maksymalna liczba równoczesnych harmonogramów musi wynosić >=1, ale otrzymano: {0} +maximumConcurrentSchedulesLessThanMinimumExceptionMessage = Maksymalna liczba równoczesnych harmonogramów nie może być mniejsza niż minimalna liczba {0}, ale otrzymano: {1} +scheduleDoesNotExistExceptionMessage = Harmonogram '{0}' nie istnieje. +suppliedDateBeforeScheduleStartTimeExceptionMessage = Podana data jest wcześniejsza niż czas rozpoczęcia harmonogramu o {0} +suppliedDateAfterScheduleEndTimeExceptionMessage = Podana data jest późniejsza niż czas zakończenia harmonogramu o {0} +noSemaphoreFoundExceptionMessage = Nie znaleziono semaforu o nazwie '{0}' '@ \ No newline at end of file diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index 1337c0229..2d85dcd3e 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -236,4 +236,22 @@ parameterNotSuppliedInRequestExceptionMessage = Um parâmetro chamado '{0}' não noDataForFileUploadedExceptionMessage = Nenhum dado para o arquivo '{0}' foi enviado na solicitação. viewsFolderNameAlreadyExistsExceptionMessage = O nome da pasta Views já existe: {0} viewsPathDoesNotExistExceptionMessage = O caminho das Views não existe: {0} +timerAlreadyDefinedExceptionMessage = [Temporizador] {0}: Temporizador já definido. +timerParameterMustBeGreaterThanZeroExceptionMessage = [Temporizador] {0}: {1} deve ser maior que 0. +timerDoesNotExistExceptionMessage = O temporizador '{0}' não existe. +mutexAlreadyExistsExceptionMessage = Já existe um mutex com o seguinte nome: {0} +noMutexFoundExceptionMessage = Nenhum mutex encontrado chamado '{0}' +failedToAcquireMutexOwnershipExceptionMessage = Falha ao adquirir a propriedade do mutex. Nome do mutex: {0} +semaphoreAlreadyExistsExceptionMessage = Já existe um semáforo com o seguinte nome: {0} +failedToAcquireSemaphoreOwnershipExceptionMessage = Falha ao adquirir a propriedade do semáforo. Nome do semáforo: {0} +scheduleAlreadyDefinedExceptionMessage = [Agenda] {0}: Agenda já definida. +scheduleCannotHaveNegativeLimitExceptionMessage = [Agenda] {0}: Não pode ter um limite negativo. +scheduleEndTimeMustBeInFutureExceptionMessage = [Agenda] {0}: O valor de EndTime deve estar no futuro. +scheduleStartTimeAfterEndTimeExceptionMessage = [Agenda] {0}: Não pode ter um 'StartTime' após o 'EndTime' +maximumConcurrentSchedulesInvalidExceptionMessage = As agendas simultâneas máximas devem ser >=1, mas obtidas: {0} +maximumConcurrentSchedulesLessThanMinimumExceptionMessage = As agendas simultâneas máximas não podem ser inferiores ao mínimo de {0}, mas obtidas: {1} +scheduleDoesNotExistExceptionMessage = A agenda '{0}' não existe. +suppliedDateBeforeScheduleStartTimeExceptionMessage = A data fornecida é anterior ao horário de início da agenda em {0} +suppliedDateAfterScheduleEndTimeExceptionMessage = A data fornecida é posterior ao horário de término da agenda em {0} +noSemaphoreFoundExceptionMessage = Nenhum semáforo encontrado chamado '{0}' '@ diff --git a/src/Locales/zn/Pode.psd1 b/src/Locales/zn/Pode.psd1 index 11f737bea..b97c1e808 100644 --- a/src/Locales/zn/Pode.psd1 +++ b/src/Locales/zn/Pode.psd1 @@ -236,4 +236,22 @@ parameterNotSuppliedInRequestExceptionMessage = 请求中未提供名为 '{0}' noDataForFileUploadedExceptionMessage = 请求中未上传文件 '{0}' 的数据。 viewsFolderNameAlreadyExistsExceptionMessage = 视图文件夹名称已存在: {0} viewsPathDoesNotExistExceptionMessage = 视图路径不存在: {0} -'@ +timerAlreadyDefinedExceptionMessage = [计时器] {0}: 计时器已定义。 +timerParameterMustBeGreaterThanZeroExceptionMessage = [计时器] {0}: {1} 必须大于 0。 +timerDoesNotExistExceptionMessage = 计时器 '{0}' 不存在。 +mutexAlreadyExistsExceptionMessage = 名为 '{0}' 的互斥量已存在。 +noMutexFoundExceptionMessage = 找不到名为 '{0}' 的互斥量 +failedToAcquireMutexOwnershipExceptionMessage = 未能获得互斥量的所有权。互斥量名称: {0} +semaphoreAlreadyExistsExceptionMessage = 名为 '{0}' 的信号量已存在。 +failedToAcquireSemaphoreOwnershipExceptionMessage = 未能获得信号量的所有权。信号量名称: {0} +scheduleAlreadyDefinedExceptionMessage = [计划] {0}: 计划已定义。 +scheduleCannotHaveNegativeLimitExceptionMessage = [计划] {0}: 不能有负数限制。 +scheduleEndTimeMustBeInFutureExceptionMessage = [计划] {0}: EndTime 值必须在将来。 +scheduleStartTimeAfterEndTimeExceptionMessage = [计划] {0}: 'StartTime' 不能在 'EndTime' 之后 +maximumConcurrentSchedulesInvalidExceptionMessage = 最大并发计划数必须 >=1,但得到: {0} +maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 最大并发计划数不能小于最小值 {0},但得到: {1} +scheduleDoesNotExistExceptionMessage = 计划 '{0}' 不存在。 +suppliedDateBeforeScheduleStartTimeExceptionMessage = 提供的日期早于计划的开始时间 {0} +suppliedDateAfterScheduleEndTimeExceptionMessage = 提供的日期晚于计划的结束时间 {0} +noSemaphoreFoundExceptionMessage = 找不到名为 '{0}' 的信号量 +'@ \ No newline at end of file diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index 1a577b9ff..3d7cf7576 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -1502,7 +1502,8 @@ function Use-PodePartialView { # test the file path, and set status accordingly if (!(Test-PodePath $Path -NoStatus)) { - throw "File not found at path: $($Path)" + # The Views path does not exist + throw ($PodeLocale.viewsPathDoesNotExistExceptionMessage -f $Path) } # run any engine logic diff --git a/src/Public/Schedules.ps1 b/src/Public/Schedules.ps1 index 28eaa7d74..2b74cb538 100644 --- a/src/Public/Schedules.ps1 +++ b/src/Public/Schedules.ps1 @@ -88,21 +88,25 @@ function Add-PodeSchedule { # ensure the schedule doesn't already exist if ($PodeContext.Schedules.Items.ContainsKey($Name)) { - throw "[Schedule] $($Name): Schedule already defined" + # [Schedule] Name: Schedule already defined + throw ($PodeLocale.scheduleAlreadyDefinedExceptionMessage -f $Name) } # ensure the limit is valid if ($Limit -lt 0) { - throw "[Schedule] $($Name): Cannot have a negative limit" + # [Schedule] Name: Cannot have a negative limit + throw ($PodeLocale.scheduleCannotHaveNegativeLimitExceptionMessage -f $Name) } # ensure the start/end dates are valid if (($null -ne $EndTime) -and ($EndTime -lt [DateTime]::Now)) { - throw "[Schedule] $($Name): The EndTime value must be in the future" + # [Schedule] Name: The EndTime value must be in the future + throw ($PodeLocale.scheduleEndTimeMustBeInFutureExceptionMessage -f $Name) } if (($null -ne $StartTime) -and ($null -ne $EndTime) -and ($EndTime -le $StartTime)) { - throw "[Schedule] $($Name): Cannot have a StartTime after the EndTime" + # [Schedule] Name: Cannot have a 'StartTime' after the 'EndTime' + throw ($PodeLocale.scheduleStartTimeAfterEndTimeExceptionMessage -f $Name) } # if we have a file path supplied, load that path as a scriptblock @@ -159,7 +163,8 @@ function Set-PodeScheduleConcurrency { # error if <=0 if ($Maximum -le 0) { - throw "Maximum concurrent schedules must be >=1 but got: $($Maximum)" + # Maximum concurrent schedules must be >=1 but got + throw ($PodeLocale.maximumConcurrentSchedulesInvalidExceptionMessage -f $Maximum) } # ensure max > min @@ -169,7 +174,8 @@ function Set-PodeScheduleConcurrency { } if ($_min -gt $Maximum) { - throw "Maximum concurrent schedules cannot be less than the minimum of $($_min) but got: $($Maximum)" + # Maximum concurrent schedules cannot be less than the minimum of $_min but got $Maximum + throw ($PodeLocale.maximumConcurrentSchedulesLessThanMinimumExceptionMessage -f $_min, $Maximum) } # set the max schedules @@ -209,7 +215,8 @@ function Invoke-PodeSchedule { # ensure the schedule exists if (!$PodeContext.Schedules.Items.ContainsKey($Name)) { - throw "Schedule '$($Name)' does not exist" + # Schedule 'Name' does not exist + throw ($PodeLocale.scheduleDoesNotExistExceptionMessage -f $Name) } # run schedule logic @@ -304,7 +311,8 @@ function Edit-PodeSchedule { # ensure the schedule exists if (!$PodeContext.Schedules.Items.ContainsKey($Name)) { - throw "Schedule '$($Name)' does not exist" + # Schedule 'Name' does not exist + throw ($PodeLocale.scheduleDoesNotExistExceptionMessage -f $Name) } $_schedule = $PodeContext.Schedules.Items[$Name] @@ -487,18 +495,21 @@ function Get-PodeScheduleNextTrigger { # ensure the schedule exists if (!$PodeContext.Schedules.Items.ContainsKey($Name)) { - throw "Schedule '$($Name)' does not exist" + # Schedule 'Name' does not exist + throw ($PodeLocale.scheduleDoesNotExistExceptionMessage -f $Name) } $_schedule = $PodeContext.Schedules.Items[$Name] # ensure date is after start/before end if (($null -ne $DateTime) -and ($null -ne $_schedule.StartTime) -and ($DateTime -lt $_schedule.StartTime)) { - throw "Supplied date is before the start time of the schedule at $($_schedule.StartTime)" + # Supplied date is before the start time of the schedule at $_schedule.StartTime + throw ($PodeLocale.suppliedDateBeforeScheduleStartTimeExceptionMessage -f $_schedule.StartTime) } if (($null -ne $DateTime) -and ($null -ne $_schedule.EndTime) -and ($DateTime -gt $_schedule.EndTime)) { - throw "Supplied date is after the end time of the schedule at $($_schedule.EndTime)" + # Supplied date is after the end time of the schedule at $_schedule.EndTime + throw ($PodeLocale.suppliedDateAfterScheduleEndTimeExceptionMessage -f $_schedule.EndTime) } # get the next trigger diff --git a/src/Public/Threading.ps1 b/src/Public/Threading.ps1 index 5cb4779df..015b03e50 100644 --- a/src/Public/Threading.ps1 +++ b/src/Public/Threading.ps1 @@ -391,7 +391,8 @@ function New-PodeMutex { ) if (Test-PodeMutex -Name $Name) { - throw "A mutex with the following name already exists: $($Name)" + # A mutex with the following name already exists + throw ($PodeLocale.mutexAlreadyExistsExceptionMessage -f $Name) } $mutex = $null @@ -579,11 +580,13 @@ function Enter-PodeMutex { $mutex = Get-PodeMutex -Name $Name if ($null -eq $mutex) { - throw "No mutex found called '$($Name)'" + # No mutex found called 'Name' + throw ($PodeLocale.noMutexFoundExceptionMessage -f $Name) } if (!$mutex.WaitOne($Timeout)) { - throw "Failed to acquire mutex ownership. Mutex name: $($Name)" + # Failed to acquire mutex ownership. Mutex name: Name + throw ($PodeLocale.failedToAcquireMutexOwnershipExceptionMessage -f $Name) } } @@ -610,7 +613,8 @@ function Exit-PodeMutex { $mutex = Get-PodeMutex -Name $Name if ($null -eq $mutex) { - throw "No mutex found called '$($Name)'" + # No mutex found called 'Name' + throw ($PodeLocale.noMutexFoundExceptionMessage -f $Name) } $mutex.ReleaseMutex() @@ -685,7 +689,8 @@ function New-PodeSemaphore { ) if (Test-PodeSemaphore -Name $Name) { - throw "A semaphore with the following name already exists: $($Name)" + # A semaphore with the following name already exists + throw ($PodeLocale.semaphoreAlreadyExistsExceptionMessage -f $Name) } if ($Count -le 0) { @@ -877,11 +882,13 @@ function Enter-PodeSemaphore { $semaphore = Get-PodeSemaphore -Name $Name if ($null -eq $semaphore) { - throw "No semaphore found called '$($Name)'" + # No semaphore found called 'Name' + throw ($PodeLocale.noSemaphoreFoundExceptionMessage -f $Name) } if (!$semaphore.WaitOne($Timeout)) { - throw "Failed to acquire semaphore ownership. Semaphore name: $($Name)" + # Failed to acquire semaphore ownership. Semaphore name: Name + throw ($PodeLocale.failedToAcquireSemaphoreOwnershipExceptionMessage -f $Name) } } @@ -915,7 +922,8 @@ function Exit-PodeSemaphore { $semaphore = Get-PodeSemaphore -Name $Name if ($null -eq $semaphore) { - throw "No semaphore found called '$($Name)'" + # No semaphore found called 'Name' + throw ($PodeLocale.noSemaphoreFoundExceptionMessage -f $Name) } if ($ReleaseCount -lt 1) { diff --git a/src/Public/Timers.ps1 b/src/Public/Timers.ps1 index 84ef29dd7..8042bca71 100644 --- a/src/Public/Timers.ps1 +++ b/src/Public/Timers.ps1 @@ -81,22 +81,26 @@ function Add-PodeTimer { # ensure the timer doesn't already exist if ($PodeContext.Timers.Items.ContainsKey($Name)) { - throw "[Timer] $($Name): Timer already defined" + # [Timer] Name: Timer already defined + throw ($PodeLocale.timerAlreadyDefinedExceptionMessage -f $Name) } # is the interval valid? if ($Interval -le 0) { - throw "[Timer] $($Name): Interval must be greater than 0" + # [Timer] Name: parameter must be greater than 0 + throw ($PodeLocale.timerParameterMustBeGreaterThanZeroExceptionMessage -f $Name, 'Interval') } # is the limit valid? if ($Limit -lt 0) { - throw "[Timer] $($Name): Cannot have a negative limit" + # [Timer] Name: parameter must be greater than 0 + throw ($PodeLocale.timerParameterMustBeGreaterThanZeroExceptionMessage -f $Name, 'Limit') } # is the skip valid? if ($Skip -lt 0) { - throw "[Timer] $($Name): Cannot have a negative skip value" + # [Timer] Name: parameter must be greater than 0 + throw ($PodeLocale.timerParameterMustBeGreaterThanZeroExceptionMessage -f $Name, 'Skip') } # if we have a file path supplied, load that path as a scriptblock @@ -162,7 +166,8 @@ function Invoke-PodeTimer { # ensure the timer exists if (!$PodeContext.Timers.Items.ContainsKey($Name)) { - throw "Timer '$($Name)' does not exist" + # Timer 'Name' does not exist + throw ($PodeLocale.timerDoesNotExistExceptionMessage -f $Name) } # run timer logic @@ -254,7 +259,8 @@ function Edit-PodeTimer { # ensure the timer exists if (!$PodeContext.Timers.Items.ContainsKey($Name)) { - throw "Timer '$($Name)' does not exist" + # Timer 'Name' does not exist + throw ($PodeLocale.timerDoesNotExistExceptionMessage -f $Name) } $_timer = $PodeContext.Timers.Items[$Name] diff --git a/tests/unit/Responses.Tests.ps1 b/tests/unit/Responses.Tests.ps1 index 73c28e745..5394a7909 100644 --- a/tests/unit/Responses.Tests.ps1 +++ b/tests/unit/Responses.Tests.ps1 @@ -398,7 +398,7 @@ Describe 'Use-PodePartialView' { It 'Throws an error for a path that does not exist' { Mock Test-PodePath { return $false } - { Use-PodePartialView -Path 'sub-view.pode' } | Should -Throw -ExpectedMessage '*File not found*' + { Use-PodePartialView -Path 'sub-view.pode' } | Should -Throw -ExpectedMessage ($PodeLocale.viewsPathDoesNotExistExceptionMessage -f '*' ) # The Views path does not exist: sub-view.pode' } diff --git a/tests/unit/Schedules.Tests.ps1 b/tests/unit/Schedules.Tests.ps1 index da3a07cd6..0fabd47e4 100644 --- a/tests/unit/Schedules.Tests.ps1 +++ b/tests/unit/Schedules.Tests.ps1 @@ -53,7 +53,8 @@ Describe 'Add-PodeSchedule' { $PodeContext = @{ 'Schedules' = @{ Items = @{} }; } $start = ([DateTime]::Now.AddHours(3)) $end = ([DateTime]::Now.AddHours(1)) - { Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock {} -StartTime $start -EndTime $end } | Should -Throw -ExpectedMessage '*starttime after the endtime*' + $expectedMessage = ($PodeLocale.scheduleStartTimeAfterEndTimeExceptionMessage -f 'test') -replace '\[', '`[' -replace '\]', '`]' + { Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock {} -StartTime $start -EndTime $end } | Should -Throw -ExpectedMessage $expectedMessage # [Schedule] {0}: Cannot have a 'StartTime' after the 'EndTime' } It 'Adds new schedule supplying everything' { diff --git a/tests/unit/Timers.Tests.ps1 b/tests/unit/Timers.Tests.ps1 index 9e5567f5b..4926f36ca 100644 --- a/tests/unit/Timers.Tests.ps1 +++ b/tests/unit/Timers.Tests.ps1 @@ -55,12 +55,14 @@ Describe 'Add-PodeTimer' { It 'Throws error because limit is negative' { $PodeContext = @{ 'Timers' = @{ Items = @{} }; } - { Add-PodeTimer -Name 'test' -Interval 1 -ScriptBlock {} -Limit -1 } | Should -Throw -ExpectedMessage '*negative limit*' + $expectedMessage = ($PodeLocale.timerParameterMustBeGreaterThanZeroExceptionMessage -f 'test', 'Limit') -replace '\[', '`[' -replace '\]', '`]' + { Add-PodeTimer -Name 'test' -Interval 1 -ScriptBlock {} -Limit -1 } | Should -Throw -ExpectedMessage $expectedMessage #[Timer] {0}: {1} must be greater than 0. } It 'Throws error because skip is negative' { $PodeContext = @{ 'Timers' = @{ Items = @{} }; } - { Add-PodeTimer -Name 'test' -Interval 1 -ScriptBlock {} -Skip -1 } | Should -Throw -ExpectedMessage '*negative skip*' + $expectedMessage = ($PodeLocale.timerParameterMustBeGreaterThanZeroExceptionMessage -f 'test', 'skip') -replace '\[', '`[' -replace '\]', '`]' + { Add-PodeTimer -Name 'test' -Interval 1 -ScriptBlock {} -Skip -1 } | Should -Throw -ExpectedMessage $expectedMessage #[Timer] {0}: {1} must be greater than 0. } It 'Adds new timer to session with no limit' { From e91ddc411ee3c85e6594115b53870e2bbb6c35cb Mon Sep 17 00:00:00 2001 From: mdaneri Date: Wed, 5 Jun 2024 10:09:57 -0700 Subject: [PATCH 033/177] final exception messages --- src/Locales/ar/Pode.psd1 | 6 ++++++ src/Locales/de/Pode.psd1 | 6 ++++++ src/Locales/en/Pode.psd1 | 6 ++++++ src/Locales/es/Pode.psd1 | 10 ++++++++-- src/Locales/fr/Pode.psd1 | 6 ++++++ src/Locales/it/Pode.psd1 | 6 ++++++ src/Locales/ja/Pode.psd1 | 8 +++++++- src/Locales/ko/Pode.psd1 | 6 ++++++ src/Locales/pl/Pode.psd1 | 6 ++++++ src/Locales/pt/Pode.psd1 | 8 +++++++- src/Locales/zn/Pode.psd1 | 6 ++++++ src/Public/Routes.ps1 | 24 ++++++++++++++---------- 12 files changed, 84 insertions(+), 14 deletions(-) diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 860c0f7c3..091cfccd7 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -254,4 +254,10 @@ scheduleDoesNotExistExceptionMessage = الجدول الزمني '{0}' غير م suppliedDateBeforeScheduleStartTimeExceptionMessage = التاريخ المقدم قبل وقت بدء الجدول الزمني في {0} suppliedDateAfterScheduleEndTimeExceptionMessage = التاريخ المقدم بعد وقت انتهاء الجدول الزمني في {0} noSemaphoreFoundExceptionMessage = لم يتم العثور على Semaphore باسم '{0}' +noLogicPassedForRouteExceptionMessage = لم يتم تمرير منطق للمسار: {0} +noPathSuppliedForStaticRouteExceptionMessage = [{0}]: لم يتم توفير مسار للمسار الثابت. +sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: مسار المصدر المقدم للمسار الثابت غير موجود: {2} +noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: لم يتم تمرير منطق. +moduleDoesNotContainFunctionExceptionMessage = الوحدة {0} لا تحتوي على الوظيفة {1} لتحويلها إلى مسار. +pageNameShouldBeAlphaNumericExceptionMessage = يجب أن يكون اسم الصفحة قيمة أبجدية رقمية صالحة: {0} '@ \ No newline at end of file diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index f5ef28281..f1faf5562 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -254,4 +254,10 @@ scheduleDoesNotExistExceptionMessage = Zeitplan '{0}' existiert nicht. suppliedDateBeforeScheduleStartTimeExceptionMessage = Das angegebene Datum liegt vor der Startzeit des Zeitplans bei {0} suppliedDateAfterScheduleEndTimeExceptionMessage = Das angegebene Datum liegt nach der Endzeit des Zeitplans bei {0} noSemaphoreFoundExceptionMessage = Kein Semaphor mit dem Namen '{0}' gefunden. +noLogicPassedForRouteExceptionMessage = Keine Logik für Route übergeben: {0} +noPathSuppliedForStaticRouteExceptionMessage = [{0}]: Kein Pfad für statische Route angegeben. +sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: Der angegebene Quellpfad für die statische Route existiert nicht: {2} +noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Keine Logik übergeben. +moduleDoesNotContainFunctionExceptionMessage = Modul {0} enthält keine Funktion {1} zur Umwandlung in eine Route. +pageNameShouldBeAlphaNumericExceptionMessage = Der Seitenname sollte einen gültigen alphanumerischen Wert haben: {0} '@ \ No newline at end of file diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 75b0e7d63..13867bbb5 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -254,4 +254,10 @@ scheduleDoesNotExistExceptionMessage = Schedule '{0}' does not exist. suppliedDateBeforeScheduleStartTimeExceptionMessage = Supplied date is before the start time of the schedule at {0} suppliedDateAfterScheduleEndTimeExceptionMessage = Supplied date is after the end time of the schedule at {0} noSemaphoreFoundExceptionMessage = No semaphore found called '{0}' +noLogicPassedForRouteExceptionMessage = No logic passed for Route: {0} +noPathSuppliedForStaticRouteExceptionMessage = [{0}]: No Path supplied for Static Route. +sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: The Source path supplied for Static Route does not exist: {2} +noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: No logic passed. +moduleDoesNotContainFunctionExceptionMessage = Module {0} does not contain function {1} to convert to a Route. +pageNameShouldBeAlphaNumericExceptionMessage = The Page name should be a valid AlphaNumeric value: {0} '@ \ No newline at end of file diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index c35c47a85..771006059 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -253,5 +253,11 @@ maximumConcurrentSchedulesLessThanMinimumExceptionMessage = Los horarios simult scheduleDoesNotExistExceptionMessage = El horario '{0}' no existe. suppliedDateBeforeScheduleStartTimeExceptionMessage = La fecha proporcionada es anterior a la hora de inicio del horario en {0} suppliedDateAfterScheduleEndTimeExceptionMessage = La fecha proporcionada es posterior a la hora de finalización del horario en {0} -noSemaphoreFoundExceptionMessage = No se encontró ningún semáforo llamado '{0}' -'@ +noSemaphoreFoundExceptionMessage = No se encontró ningún semáforo llamado '{0}' +noLogicPassedForRouteExceptionMessage = No se pasó lógica para la Ruta: {0} +noPathSuppliedForStaticRouteExceptionMessage = [{0}]: No se proporcionó una ruta para la Ruta estática. +sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: La ruta de origen proporcionada para la Ruta estática no existe: {2} +noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: No se pasó lógica. +moduleDoesNotContainFunctionExceptionMessage = El módulo {0} no contiene la función {1} para convertir en una Ruta. +pageNameShouldBeAlphaNumericExceptionMessage = El nombre de la página debe ser un valor alfanumérico válido: {0} +'@ \ No newline at end of file diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index deb46d92d..d1576c63c 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -254,4 +254,10 @@ scheduleDoesNotExistExceptionMessage = Le calendrier '{0}' n'existe pas. suppliedDateBeforeScheduleStartTimeExceptionMessage = La date fournie est antérieure à l'heure de début du calendrier à {0} suppliedDateAfterScheduleEndTimeExceptionMessage = La date fournie est postérieure à l'heure de fin du calendrier à {0} noSemaphoreFoundExceptionMessage = Aucun sémaphore trouvé appelé '{0}' +noLogicPassedForRouteExceptionMessage = Aucune logique passée pour la Route: {0} +noPathSuppliedForStaticRouteExceptionMessage = [{0}]: Aucun chemin fourni pour la Route statique. +sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: Le chemin source fourni pour la Route statique n'existe pas: {2} +noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Aucune logique passée. +moduleDoesNotContainFunctionExceptionMessage = Le module {0} ne contient pas la fonction {1} à convertir en une Route. +pageNameShouldBeAlphaNumericExceptionMessage = Le nom de la page doit être une valeur alphanumérique valide: {0} '@ \ No newline at end of file diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index 6f73d09c9..4340db63e 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -254,4 +254,10 @@ scheduleDoesNotExistExceptionMessage = Il programma '{0}' non esiste. suppliedDateBeforeScheduleStartTimeExceptionMessage = La data fornita è precedente all'ora di inizio del programma a {0} suppliedDateAfterScheduleEndTimeExceptionMessage = La data fornita è successiva all'ora di fine del programma a {0} noSemaphoreFoundExceptionMessage = Nessun semaforo trovato chiamato '{0}' +noLogicPassedForRouteExceptionMessage = Nessuna logica passata per la rotta: {0} +noPathSuppliedForStaticRouteExceptionMessage = [{0}]: Nessun percorso fornito per la rotta statica. +sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: Il percorso sorgente fornito per la rotta statica non esiste: {2} +noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Nessuna logica passata. +moduleDoesNotContainFunctionExceptionMessage = Il modulo {0} non contiene la funzione {1} da convertire in una rotta. +pageNameShouldBeAlphaNumericExceptionMessage = Il nome della pagina dovrebbe essere un valore alfanumerico valido: {0} '@ \ No newline at end of file diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index 7d3d73bf3..911b60557 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -253,5 +253,11 @@ maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 最大同時スケ scheduleDoesNotExistExceptionMessage = スケジュール '{0}' は存在しません。 suppliedDateBeforeScheduleStartTimeExceptionMessage = 提供された日付はスケジュールの開始時間 {0} より前です suppliedDateAfterScheduleEndTimeExceptionMessage = 提供された日付はスケジュールの終了時間 {0} の後です -noSemaphoreFoundExceptionMessage = 名前 '{0}' のセマフォが見つかりません +noSemaphoreFoundExceptionMessage = 名前 '{0}' のセマフォが見つかりません +noLogicPassedForRouteExceptionMessage = ルートに対してロジックが渡されませんでした: {0} +noPathSuppliedForStaticRouteExceptionMessage = [{0}]: 静的ルートに対して提供されたパスがありません。 +sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: 静的ルートに対して提供されたソースパスが存在しません: {2} +noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: ロジックが渡されませんでした。 +moduleDoesNotContainFunctionExceptionMessage = モジュール {0} にはルートに変換する関数 {1} が含まれていません。 +pageNameShouldBeAlphaNumericExceptionMessage = ページ名は有効な英数字である必要があります: {0} '@ \ No newline at end of file diff --git a/src/Locales/ko/Pode.psd1 b/src/Locales/ko/Pode.psd1 index 99b918e4a..22afef2b5 100644 --- a/src/Locales/ko/Pode.psd1 +++ b/src/Locales/ko/Pode.psd1 @@ -254,4 +254,10 @@ scheduleDoesNotExistExceptionMessage = 스케줄 '{0}'이(가) 존재하지 않 suppliedDateBeforeScheduleStartTimeExceptionMessage = 제공된 날짜가 스케줄 시작 시간 {0} 이전입니다. suppliedDateAfterScheduleEndTimeExceptionMessage = 제공된 날짜가 스케줄 종료 시간 {0} 이후입니다. noSemaphoreFoundExceptionMessage = 이름이 '{0}'인 세마포어를 찾을 수 없습니다. +noLogicPassedForRouteExceptionMessage = 경로에 대한 논리가 전달되지 않았습니다: {0} +noPathSuppliedForStaticRouteExceptionMessage = [{0}]: 정적 경로에 대한 경로가 제공되지 않았습니다. +sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: 정적 경로에 대한 제공된 소스 경로가 존재하지 않습니다: {2} +noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: 논리가 전달되지 않았습니다. +moduleDoesNotContainFunctionExceptionMessage = 모듈 {0}에 경로로 변환할 함수 {1}이(가) 포함되어 있지 않습니다. +pageNameShouldBeAlphaNumericExceptionMessage = 페이지 이름은 유효한 알파벳 숫자 값이어야 합니다: {0} '@ \ No newline at end of file diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index 74ce29cfb..fa7fe75b6 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -254,4 +254,10 @@ scheduleDoesNotExistExceptionMessage = Harmonogram '{0}' nie istnieje. suppliedDateBeforeScheduleStartTimeExceptionMessage = Podana data jest wcześniejsza niż czas rozpoczęcia harmonogramu o {0} suppliedDateAfterScheduleEndTimeExceptionMessage = Podana data jest późniejsza niż czas zakończenia harmonogramu o {0} noSemaphoreFoundExceptionMessage = Nie znaleziono semaforu o nazwie '{0}' +noLogicPassedForRouteExceptionMessage = Brak logiki przekazanej dla trasy: {0} +noPathSuppliedForStaticRouteExceptionMessage = [{0}]: Brak dostarczonej ścieżki dla trasy statycznej. +sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: Dostarczona ścieżka źródłowa dla trasy statycznej nie istnieje: {2} +noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Brak logiki przekazanej. +moduleDoesNotContainFunctionExceptionMessage = Moduł {0} nie zawiera funkcji {1} do konwersji na trasę. +pageNameShouldBeAlphaNumericExceptionMessage = Nazwa strony powinna być poprawną wartością alfanumeryczną: {0} '@ \ No newline at end of file diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index 2d85dcd3e..9180d3c8a 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -254,4 +254,10 @@ scheduleDoesNotExistExceptionMessage = A agenda '{0}' não existe. suppliedDateBeforeScheduleStartTimeExceptionMessage = A data fornecida é anterior ao horário de início da agenda em {0} suppliedDateAfterScheduleEndTimeExceptionMessage = A data fornecida é posterior ao horário de término da agenda em {0} noSemaphoreFoundExceptionMessage = Nenhum semáforo encontrado chamado '{0}' -'@ +noLogicPassedForRouteExceptionMessage = Nenhuma lógica passada para a Rota: {0} +noPathSuppliedForStaticRouteExceptionMessage = [{0}]: Nenhum caminho fornecido para a Rota Estática. +sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: O caminho de origem fornecido para a Rota Estática não existe: {2} +noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Nenhuma lógica passada. +moduleDoesNotContainFunctionExceptionMessage = O módulo {0} não contém a função {1} para converter em uma Rota. +pageNameShouldBeAlphaNumericExceptionMessage = O nome da página deve ser um valor alfanumérico válido: {0} +'@ \ No newline at end of file diff --git a/src/Locales/zn/Pode.psd1 b/src/Locales/zn/Pode.psd1 index b97c1e808..90d6727e1 100644 --- a/src/Locales/zn/Pode.psd1 +++ b/src/Locales/zn/Pode.psd1 @@ -254,4 +254,10 @@ scheduleDoesNotExistExceptionMessage = 计划 '{0}' 不存在。 suppliedDateBeforeScheduleStartTimeExceptionMessage = 提供的日期早于计划的开始时间 {0} suppliedDateAfterScheduleEndTimeExceptionMessage = 提供的日期晚于计划的结束时间 {0} noSemaphoreFoundExceptionMessage = 找不到名为 '{0}' 的信号量 +noLogicPassedForRouteExceptionMessage = 没有为路径传递逻辑: {0} +noPathSuppliedForStaticRouteExceptionMessage = [{0}]: 没有为静态路径提供路径。 +sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: 为静态路径提供的源路径不存在: {2} +noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: 没有传递逻辑。 +moduleDoesNotContainFunctionExceptionMessage = 模块 {0} 不包含要转换为路径的函数 {1}。 +pageNameShouldBeAlphaNumericExceptionMessage = 页面名称应为有效的字母数字值: {0} '@ \ No newline at end of file diff --git a/src/Public/Routes.ps1 b/src/Public/Routes.ps1 index a3452f838..1d93990ae 100644 --- a/src/Public/Routes.ps1 +++ b/src/Public/Routes.ps1 @@ -303,7 +303,8 @@ function Add-PodeRoute { # if middleware, scriptblock and file path are all null/empty, error if ((Test-PodeIsEmpty $Middleware) -and (Test-PodeIsEmpty $ScriptBlock) -and (Test-PodeIsEmpty $FilePath) -and (Test-PodeIsEmpty $Authentication)) { - throw "No logic passed for Route: $($Path)" + # [Method] Path: No logic passed + throw ($PodeLocale.noLogicPassedForMethodRouteExceptionMessage -f $Method, $Path) } # if we have a file path supplied, load that path as a scriptblock @@ -734,7 +735,8 @@ function Add-PodeStaticRoute { # split route on '?' for query $Path = Split-PodeRouteQuery -Path $Path if ([string]::IsNullOrWhiteSpace($Path)) { - throw "[$($Method)]: No Path supplied for Static Route" + # No Path supplied for the Route. + throw $PodeLocale.noPathSuppliedForRouteExceptionMessage } # ensure the route has appropriate slashes @@ -774,7 +776,8 @@ function Add-PodeStaticRoute { # if static, ensure the path exists at server root $Source = Get-PodeRelativePath -Path $Source -JoinRoot if (!(Test-PodePath -Path $Source -NoStatus)) { - throw "[$($Method))] $($Path): The Source path supplied for Static Route does not exist: $($Source)" + # [Method)] Path: The Source path supplied for Static Route does not exist + throw ($PodeLocale.sourcePathDoesNotExistForStaticRouteExceptionMessage -f $Method, $Path, $Source) } # setup a temp drive for the path @@ -814,7 +817,8 @@ function Add-PodeStaticRoute { # if an auth name was supplied, setup the auth as the first middleware if (![string]::IsNullOrWhiteSpace($Authentication)) { if (!(Test-PodeAuthExists -Name $Authentication)) { - throw "Authentication method does not exist: $($Authentication)" + # Authentication method does not exist + throw $PodeLocale.authenticationMethodDoesNotExistExceptionMessage } $options = @{ @@ -1007,7 +1011,8 @@ function Add-PodeSignalRoute { # if scriptblock and file path are all null/empty, error if ((Test-PodeIsEmpty $ScriptBlock) -and (Test-PodeIsEmpty $FilePath)) { - throw "[$($Method)] $($Path): No logic passed" + # [Method] Path: No logic passed + throw ($PodeLocale.noLogicPassedForMethodRouteExceptionMessage -f $Method, $Path) } # if we have a file path supplied, load that path as a scriptblock @@ -1677,9 +1682,6 @@ function Remove-PodeRoute { # split route on '?' for query $Path = Split-PodeRouteQuery -Path $Path - if ([string]::IsNullOrWhiteSpace($Path)) { - throw "[$($Method)]: No Route path supplied for removing a Route" - } # ensure the route has appropriate slashes and replace parameters $Path = Update-PodeRouteSlash -Path $Path @@ -2013,7 +2015,8 @@ function ConvertTo-PodeRoute { Write-Verbose "Validating supplied commands against module's exported commands" foreach ($cmd in $Commands) { if ($ModuleCommands -inotcontains $cmd) { - throw "Module $($Module) does not contain function $($cmd) to convert to a Route" + # Module Module does not contain function cmd to convert to a Route + throw ($PodeLocale.moduleDoesNotContainFunctionExceptionMessage -f $Module, $cmd) } } } @@ -2256,7 +2259,8 @@ function Add-PodePage { # ensure the name is a valid alphanumeric if ($Name -inotmatch '^[a-z0-9\-_]+$') { - throw "The Page name should be a valid AlphaNumeric value: $($Name)" + # The Page name should be a valid AlphaNumeric value + throw ($PodeLocale.pageNameShouldBeAlphaNumericExceptionMessage -f $Name) } # trim end trailing slashes from the path From e9898b7be5fde6ed8775f5dda9293022e91abacd Mon Sep 17 00:00:00 2001 From: mdaneri Date: Wed, 5 Jun 2024 21:53:19 -0700 Subject: [PATCH 034/177] Last messages --- docs/Tutorials/Basics.md | 6 +++--- examples/FileBrowser/FileBrowser.ps1 | 2 +- src/Locales/ar/Pode.psd1 | 21 +++++++++++++++++++++ src/Locales/de/Pode.psd1 | 21 +++++++++++++++++++++ src/Locales/en/Pode.psd1 | 21 +++++++++++++++++++++ src/Locales/es/Pode.psd1 | 23 ++++++++++++++++++++++- src/Locales/fr/Pode.psd1 | 21 +++++++++++++++++++++ src/Locales/it/Pode.psd1 | 21 +++++++++++++++++++++ src/Locales/ja/Pode.psd1 | 23 ++++++++++++++++++++++- src/Locales/ko/Pode.psd1 | 21 +++++++++++++++++++++ src/Locales/pl/Pode.psd1 | 21 +++++++++++++++++++++ src/Locales/pt/Pode.psd1 | 21 +++++++++++++++++++++ src/Locales/zn/Pode.psd1 | 21 +++++++++++++++++++++ src/Private/FileMonitor.ps1 | 3 ++- src/Private/Gui.ps1 | 6 ++++-- src/Private/Helpers.ps1 | 12 +++++++----- src/Private/OpenApi.ps1 | 18 ++++++++++++------ src/Private/Server.ps1 | 23 +++++++++++++++-------- src/Private/ServiceServer.ps1 | 3 ++- src/Public/Core.ps1 | 8 +++++--- src/Public/OpenApi.ps1 | 3 ++- 21 files changed, 286 insertions(+), 33 deletions(-) diff --git a/docs/Tutorials/Basics.md b/docs/Tutorials/Basics.md index e35bf2217..ac8094b76 100644 --- a/docs/Tutorials/Basics.md +++ b/docs/Tutorials/Basics.md @@ -83,7 +83,7 @@ PS> Start-PodeServer -FilePath './File.ps1' !!! tip Normally when you restart your Pode server any changes to the main scriptblock don't reflect. However, if you reference a file instead, then restarting the server will reload the scriptblock from that file - so any changes will reflect. -## Localization +## Internationalization Pode has built-in support for internationalization (i18n). @@ -92,7 +92,7 @@ You can enforce a specific localization when importing the Pode module by using Here’s an example of how to enforce Korean localization: ```powershell -Import-Module -Name Pode -ArgumentList @{ UICulture = 'ko-KR' } +Import-Module -Name Pode -ArgumentList 'ko-KR' ``` In this example, 'ko-KR' is the culture code for Korean as used in South Korea. You can replace 'ko-KR' with the culture code for any other language or region. @@ -105,6 +105,6 @@ This can be done using the following command: [System.Threading.Thread]::CurrentThread.CurrentUICulture = 'ko-KR' ``` -This command changes the UICulture for the current PowerShell session to Korean as used in South Korea. +This command changes the UICulture for the current PowerShell session to Korean as used in South Korea. Please note that this change is temporary and will only affect the current session. If you open a new PowerShell session, it will use the default UICulture. \ No newline at end of file diff --git a/examples/FileBrowser/FileBrowser.ps1 b/examples/FileBrowser/FileBrowser.ps1 index 03a1cd929..b38befb8f 100644 --- a/examples/FileBrowser/FileBrowser.ps1 +++ b/examples/FileBrowser/FileBrowser.ps1 @@ -2,7 +2,7 @@ $FileBrowserPath = Split-Path -Parent -Path $MyInvocation.MyCommand.Path $podePath = Split-Path -Parent -Path (Split-Path -Parent -Path $FileBrowserPath) if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { - Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop + Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop -ArgumentList 'ja' } else { Import-Module -Name 'Pode' -ErrorAction Stop diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 091cfccd7..0940a3697 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -260,4 +260,25 @@ sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: مسار ال noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: لم يتم تمرير منطق. moduleDoesNotContainFunctionExceptionMessage = الوحدة {0} لا تحتوي على الوظيفة {1} لتحويلها إلى مسار. pageNameShouldBeAlphaNumericExceptionMessage = يجب أن يكون اسم الصفحة قيمة أبجدية رقمية صالحة: {0} +filesHaveChangedMessage = تم تغيير الملفات التالية: +multipleEndpointsForGuiMessage = تم تعريف نقاط نهاية متعددة، سيتم استخدام الأولى فقط للواجهة الرسومية. +openingGuiMessage = جارٍ فتح الواجهة الرسومية. +listeningOnEndpointsMessage = الاستماع على {0} نقطة(نقاط) النهاية التالية [{1} خيط(خيوط)]: +specificationMessage = مواصفات +documentationMessage = توثيق +restartingServerMessage = إعادة تشغيل الخادم... +doneMessage = تم +deprecatedTitleVersionDescriptionWarningMessage = تحذير: العنوان، الإصدار والوصف في 'Enable-PodeOpenApi' مهمل. يرجى استخدام 'Add-PodeOAInfo' بدلاً من ذلك. +undefinedOpenApiReferencesMessage = مراجع OpenAPI غير معرّفة: +definitionTagMessage = تعريف {0}: +openApiGenerationDocumentErrorMessage = خطأ في مستند إنشاء OpenAPI: +infoTitleMandatoryMessage = info.title إلزامي. +infoVersionMandatoryMessage = info.version إلزامي. +missingComponentsMessage = المكون (المكونات) المفقود +openApiInfoMessage = معلومات OpenAPI: +serverLoopingMessage = تكرار الخادم كل {0} ثانية +iisShutdownMessage = (إيقاف تشغيل IIS) +terminatingMessage = إنهاء... +eolPowerShellWarningMessage = [تحذير] لم يتم اختبار Pode {0} على PowerShell {1}، حيث أنه نهاية العمر. +untestedPowerShellVersionWarningMessage = [تحذير] لم يتم اختبار Pode {0} على PowerShell {1}، حيث لم يكن متاحًا عند إصدار Pode. '@ \ No newline at end of file diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index f1faf5562..dcfd18c46 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -260,4 +260,25 @@ sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: Der angegeben noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Keine Logik übergeben. moduleDoesNotContainFunctionExceptionMessage = Modul {0} enthält keine Funktion {1} zur Umwandlung in eine Route. pageNameShouldBeAlphaNumericExceptionMessage = Der Seitenname sollte einen gültigen alphanumerischen Wert haben: {0} +filesHaveChangedMessage = Die folgenden Dateien wurden geändert: +multipleEndpointsForGuiMessage = Mehrere Endpunkte definiert, es wird nur der erste für die GUI verwendet. +openingGuiMessage = Die GUI wird geöffnet. +listeningOnEndpointsMessage = Lauschen auf den folgenden {0} Endpunkt(en) [{1} Thread(s)]: +specificationMessage = Spezifikation +documentationMessage = Dokumentation +restartingServerMessage = Server wird neu gestartet... +doneMessage = Fertig +deprecatedTitleVersionDescriptionWarningMessage = WARNUNG: Titel, Version und Beschreibung in 'Enable-PodeOpenApi' sind veraltet. Bitte verwenden Sie stattdessen 'Add-PodeOAInfo'. +undefinedOpenApiReferencesMessage = Nicht definierte OpenAPI-Referenzen: +definitionTagMessage = Definition {0}: +openApiGenerationDocumentErrorMessage = Fehler beim Generieren des OpenAPI-Dokuments: +infoTitleMandatoryMessage = info.title ist obligatorisch. +infoVersionMandatoryMessage = info.version ist obligatorisch. +missingComponentsMessage = Fehlende Komponente(n) +openApiInfoMessage = OpenAPI-Informationen: +serverLoopingMessage = Server-Schleife alle {0} Sekunden +iisShutdownMessage = (IIS Herunterfahren) +terminatingMessage = Beenden... +eolPowerShellWarningMessage = [WARNUNG] Pode {0} wurde nicht auf PowerShell {1} getestet, da es das Ende des Lebenszyklus erreicht hat. +untestedPowerShellVersionWarningMessage = [WARNUNG] Pode {0} wurde nicht auf PowerShell {1} getestet, da diese Version bei der Veröffentlichung von Pode nicht verfügbar war. '@ \ No newline at end of file diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 13867bbb5..80ded57b6 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -260,4 +260,25 @@ sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: The Source pa noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: No logic passed. moduleDoesNotContainFunctionExceptionMessage = Module {0} does not contain function {1} to convert to a Route. pageNameShouldBeAlphaNumericExceptionMessage = The Page name should be a valid AlphaNumeric value: {0} +filesHaveChangedMessage = The following files have changed: +multipleEndpointsForGuiMessage = Multiple endpoints defined, only the first will be used for the GUI. +openingGuiMessage = Opening the GUI. +listeningOnEndpointsMessage = Listening on the following {0} endpoint(s) [{1} thread(s)]: +specificationMessage = Specification +documentationMessage = Documentation +restartingServerMessage = Restarting server... +doneMessage = Done +deprecatedTitleVersionDescriptionWarningMessage = WARNING: Title, Version, and Description on 'Enable-PodeOpenApi' are deprecated. Please use 'Add-PodeOAInfo' instead. +undefinedOpenApiReferencesMessage = Undefined OpenAPI References: +definitionTagMessage = Definition {0}: +openApiGenerationDocumentErrorMessage = OpenAPI generation document error: +infoTitleMandatoryMessage = info.title is mandatory. +infoVersionMandatoryMessage = info.version is mandatory. +missingComponentsMessage = Missing component(s) +openApiInfoMessage = OpenAPI Info: +serverLoopingMessage = Server looping every {0}secs +iisShutdownMessage = (IIS Shutdown) +terminatingMessage = Terminating... +eolPowerShellWarningMessage = [WARNING] Pode {0} has not been tested on PowerShell {1}, as it is EOL. +untestedPowerShellVersionWarningMessage = [WARNING] Pode {0} has not been tested on PowerShell {1}, as it was not available when Pode was released. '@ \ No newline at end of file diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 771006059..70b79a29a 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -253,11 +253,32 @@ maximumConcurrentSchedulesLessThanMinimumExceptionMessage = Los horarios simult scheduleDoesNotExistExceptionMessage = El horario '{0}' no existe. suppliedDateBeforeScheduleStartTimeExceptionMessage = La fecha proporcionada es anterior a la hora de inicio del horario en {0} suppliedDateAfterScheduleEndTimeExceptionMessage = La fecha proporcionada es posterior a la hora de finalización del horario en {0} -noSemaphoreFoundExceptionMessage = No se encontró ningún semáforo llamado '{0}' +noSemaphoreFoundExceptionMessage = No se encontró ningún semáforo llamado '{0}' noLogicPassedForRouteExceptionMessage = No se pasó lógica para la Ruta: {0} noPathSuppliedForStaticRouteExceptionMessage = [{0}]: No se proporcionó una ruta para la Ruta estática. sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: La ruta de origen proporcionada para la Ruta estática no existe: {2} noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: No se pasó lógica. moduleDoesNotContainFunctionExceptionMessage = El módulo {0} no contiene la función {1} para convertir en una Ruta. pageNameShouldBeAlphaNumericExceptionMessage = El nombre de la página debe ser un valor alfanumérico válido: {0} +filesHaveChangedMessage = Los siguientes archivos han cambiado: +multipleEndpointsForGuiMessage = Se han definido múltiples puntos de conexión, solo se usará el primero para la GUI. +openingGuiMessage = Abriendo la GUI. +listeningOnEndpointsMessage = Escuchando en los siguientes {0} punto(s) de conexión [{1} hilo(s)]: +specificationMessage = Especificación +documentationMessage = Documentación +restartingServerMessage = Reiniciando el servidor... +doneMessage = Hecho +deprecatedTitleVersionDescriptionWarningMessage = ADVERTENCIA: Título, Versión y Descripción en 'Enable-PodeOpenApi' están obsoletos. Utilice 'Add-PodeOAInfo' en su lugar. +undefinedOpenApiReferencesMessage = Referencias OpenAPI indefinidas: +definitionTagMessage = Definición {0}: +openApiGenerationDocumentErrorMessage = Error en el documento de generación de OpenAPI: +infoTitleMandatoryMessage = info.title es obligatorio. +infoVersionMandatoryMessage = info.version es obligatorio. +missingComponentsMessage = Componente(s) faltante(s) +openApiInfoMessage = Información OpenAPI: +serverLoopingMessage = Bucle del servidor cada {0} segundos +iisShutdownMessage = (Apagado de IIS) +terminatingMessage = Terminando... +eolPowerShellWarningMessage = [ADVERTENCIA] Pode {0} no se ha probado en PowerShell {1}, ya que está en fin de vida. +untestedPowerShellVersionWarningMessage = [ADVERTENCIA] Pode {0} no se ha probado en PowerShell {1}, ya que no estaba disponible cuando se lanzó Pode. '@ \ No newline at end of file diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index d1576c63c..b9dddc8e3 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -260,4 +260,25 @@ sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: Le chemin sou noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Aucune logique passée. moduleDoesNotContainFunctionExceptionMessage = Le module {0} ne contient pas la fonction {1} à convertir en une Route. pageNameShouldBeAlphaNumericExceptionMessage = Le nom de la page doit être une valeur alphanumérique valide: {0} +filesHaveChangedMessage = Les fichiers suivants ont été modifiés : +multipleEndpointsForGuiMessage = Plusieurs points de terminaison définis, seul le premier sera utilisé pour l'interface graphique. +openingGuiMessage = Ouverture de l'interface graphique. +listeningOnEndpointsMessage = Écoute sur les {0} point(s) de terminaison suivant(s) [{1} thread(s)] : +specificationMessage = Spécification +documentationMessage = Documentation +restartingServerMessage = Redémarrage du serveur... +doneMessage = Terminé +deprecatedTitleVersionDescriptionWarningMessage = AVERTISSEMENT : Titre, Version et Description sur 'Enable-PodeOpenApi' sont obsolètes. Veuillez utiliser 'Add-PodeOAInfo' à la place. +undefinedOpenApiReferencesMessage = Références OpenAPI non définies : +definitionTagMessage = Définition {0} : +openApiGenerationDocumentErrorMessage = Erreur de génération du document OpenAPI : +infoTitleMandatoryMessage = info.title est obligatoire. +infoVersionMandatoryMessage = info.version est obligatoire. +missingComponentsMessage = Composant(s) manquant(s) +openApiInfoMessage = Informations OpenAPI : +serverLoopingMessage = Boucle du serveur toutes les {0} secondes +iisShutdownMessage = (Arrêt de l'IIS) +terminatingMessage = Terminaison... +eolPowerShellWarningMessage = [AVERTISSEMENT] Pode {0} n'a pas été testé sur PowerShell {1}, car il est en fin de vie. +untestedPowerShellVersionWarningMessage = [AVERTISSEMENT] Pode {0} n'a pas été testé sur PowerShell {1}, car il n'était pas disponible lors de la sortie de Pode. '@ \ No newline at end of file diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index 4340db63e..231ededb4 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -260,4 +260,25 @@ sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: Il percorso s noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Nessuna logica passata. moduleDoesNotContainFunctionExceptionMessage = Il modulo {0} non contiene la funzione {1} da convertire in una rotta. pageNameShouldBeAlphaNumericExceptionMessage = Il nome della pagina dovrebbe essere un valore alfanumerico valido: {0} +filesHaveChangedMessage = I seguenti file sono stati modificati: +multipleEndpointsForGuiMessage = Sono stati definiti più endpoint, solo il primo sarà utilizzato per la GUI. +openingGuiMessage = Apertura della GUI. +listeningOnEndpointsMessage = In ascolto sui seguenti {0} endpoint [{1} thread]: +specificationMessage = Specifica +documentationMessage = Documentazione +restartingServerMessage = Riavvio del server... +doneMessage = Fatto +deprecatedTitleVersionDescriptionWarningMessage = AVVERTENZA: Titolo, Versione e Descrizione su 'Enable-PodeOpenApi' sono deprecati. Si prega di utilizzare 'Add-PodeOAInfo' invece. +undefinedOpenApiReferencesMessage = Riferimenti OpenAPI non definiti: +definitionTagMessage = Definizione {0}: +openApiGenerationDocumentErrorMessage = Errore nella generazione del documento OpenAPI: +infoTitleMandatoryMessage = info.title è obbligatorio. +infoVersionMandatoryMessage = info.version è obbligatorio. +missingComponentsMessage = Componenti mancanti +openApiInfoMessage = Informazioni OpenAPI: +serverLoopingMessage = Ciclo del server ogni {0} secondi +iisShutdownMessage = (Chiusura IIS) +terminatingMessage = Terminazione... +eolPowerShellWarningMessage = [AVVERTENZA] Pode {0} non è stato testato su PowerShell {1}, poiché è EOL. +untestedPowerShellVersionWarningMessage = [AVVERTENZA] Pode {0} non è stato testato su PowerShell {1}, poiché non era disponibile quando Pode è stato rilasciato. '@ \ No newline at end of file diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index 911b60557..793ec1b8c 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -253,11 +253,32 @@ maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 最大同時スケ scheduleDoesNotExistExceptionMessage = スケジュール '{0}' は存在しません。 suppliedDateBeforeScheduleStartTimeExceptionMessage = 提供された日付はスケジュールの開始時間 {0} より前です suppliedDateAfterScheduleEndTimeExceptionMessage = 提供された日付はスケジュールの終了時間 {0} の後です -noSemaphoreFoundExceptionMessage = 名前 '{0}' のセマフォが見つかりません +noSemaphoreFoundExceptionMessage = 名前 '{0}' のセマフォが見つかりません noLogicPassedForRouteExceptionMessage = ルートに対してロジックが渡されませんでした: {0} noPathSuppliedForStaticRouteExceptionMessage = [{0}]: 静的ルートに対して提供されたパスがありません。 sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: 静的ルートに対して提供されたソースパスが存在しません: {2} noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: ロジックが渡されませんでした。 moduleDoesNotContainFunctionExceptionMessage = モジュール {0} にはルートに変換する関数 {1} が含まれていません。 pageNameShouldBeAlphaNumericExceptionMessage = ページ名は有効な英数字である必要があります: {0} +filesHaveChangedMessage = 次のファイルが変更されました: +multipleEndpointsForGuiMessage = 複数のエンドポイントが定義されていますが、GUIには最初のエンドポイントのみが使用されます。 +openingGuiMessage = GUIを開いています。 +listeningOnEndpointsMessage = 次の {0} エンドポイントでリッスンしています [{1} スレッド]: +specificationMessage = 仕様 +documentationMessage = ドキュメント +restartingServerMessage = サーバーを再起動しています... +doneMessage = 完了 +deprecatedTitleVersionDescriptionWarningMessage = 警告: 'Enable-PodeOpenApi' のタイトル、バージョン、および説明は非推奨です。代わりに 'Add-PodeOAInfo' を使用してください。 +undefinedOpenApiReferencesMessage = 未定義のOpenAPI参照: +definitionTagMessage = 定義 {0}: +openApiGenerationDocumentErrorMessage = OpenAPI生成ドキュメントエラー: +infoTitleMandatoryMessage = info.title は必須です。 +infoVersionMandatoryMessage = info.version は必須です。 +missingComponentsMessage = 欠落しているコンポーネント +openApiInfoMessage = OpenAPI情報: +serverLoopingMessage = サーバーループ間隔 {0}秒 +iisShutdownMessage = (IIS シャットダウン) +terminatingMessage = 終了中... +eolPowerShellWarningMessage = [警告] Pode {0} は、EOLであるPowerShell {1} でテストされていません。 +untestedPowerShellVersionWarningMessage = [警告] Pode {0} はリリース時に利用可能でなかったため、PowerShell {1} でテストされていません。 '@ \ No newline at end of file diff --git a/src/Locales/ko/Pode.psd1 b/src/Locales/ko/Pode.psd1 index 22afef2b5..cc040056e 100644 --- a/src/Locales/ko/Pode.psd1 +++ b/src/Locales/ko/Pode.psd1 @@ -260,4 +260,25 @@ sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: 정적 경로 noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: 논리가 전달되지 않았습니다. moduleDoesNotContainFunctionExceptionMessage = 모듈 {0}에 경로로 변환할 함수 {1}이(가) 포함되어 있지 않습니다. pageNameShouldBeAlphaNumericExceptionMessage = 페이지 이름은 유효한 알파벳 숫자 값이어야 합니다: {0} +filesHaveChangedMessage = 다음 파일이 변경되었습니다: +multipleEndpointsForGuiMessage = 여러 엔드포인트가 정의되었으며, GUI에는 첫 번째만 사용됩니다. +openingGuiMessage = GUI 열기. +listeningOnEndpointsMessage = 다음 {0} 엔드포인트에서 수신 중 [{1} 스레드]: +specificationMessage = 사양 +documentationMessage = 문서 +restartingServerMessage = 서버를 재시작 중... +doneMessage = 완료 +deprecatedTitleVersionDescriptionWarningMessage = 경고: 'Enable-PodeOpenApi'의 제목, 버전 및 설명이 더 이상 사용되지 않습니다. 대신 'Add-PodeOAInfo'를 사용하십시오. +undefinedOpenApiReferencesMessage = 정의되지 않은 OpenAPI 참조: +definitionTagMessage = 정의 {0}: +openApiGenerationDocumentErrorMessage = OpenAPI 생성 문서 오류: +infoTitleMandatoryMessage = info.title은 필수 항목입니다. +infoVersionMandatoryMessage = info.version은 필수 항목입니다. +missingComponentsMessage = 누락된 구성 요소 +openApiInfoMessage = OpenAPI 정보: +serverLoopingMessage = 서버 루핑 간격 {0}초 +iisShutdownMessage = (IIS 종료) +terminatingMessage = 종료 중... +eolPowerShellWarningMessage = [경고] Pode {0}은 EOL 상태인 PowerShell {1}에서 테스트되지 않았습니다. +untestedPowerShellVersionWarningMessage = [경고] Pode {0}은 출시 당시 사용 가능하지 않았기 때문에 PowerShell {1}에서 테스트되지 않았습니다. '@ \ No newline at end of file diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index fa7fe75b6..63e256b1c 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -260,4 +260,25 @@ sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: Dostarczona noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Brak logiki przekazanej. moduleDoesNotContainFunctionExceptionMessage = Moduł {0} nie zawiera funkcji {1} do konwersji na trasę. pageNameShouldBeAlphaNumericExceptionMessage = Nazwa strony powinna być poprawną wartością alfanumeryczną: {0} +filesHaveChangedMessage = Następujące pliki zostały zmienione: +multipleEndpointsForGuiMessage = Zdefiniowano wiele punktów końcowych, tylko pierwszy będzie używany dla GUI. +openingGuiMessage = Otwieranie GUI. +listeningOnEndpointsMessage = Nasłuchiwanie na następujących {0} punktach końcowych [{1} wątków]: +specificationMessage = Specyfikacja +documentationMessage = Dokumentacja +restartingServerMessage = Restartowanie serwera... +doneMessage = Gotowe +deprecatedTitleVersionDescriptionWarningMessage = OSTRZEŻENIE: Tytuł, Wersja i Opis w 'Enable-PodeOpenApi' są przestarzałe. Proszę użyć 'Add-PodeOAInfo' zamiast tego. +undefinedOpenApiReferencesMessage = Niezdefiniowane odwołania OpenAPI: +definitionTagMessage = Definicja {0}: +openApiGenerationDocumentErrorMessage = Błąd generowania dokumentu OpenAPI: +infoTitleMandatoryMessage = info.title jest obowiązkowe. +infoVersionMandatoryMessage = info.version jest obowiązkowe. +missingComponentsMessage = Brakujące komponenty +openApiInfoMessage = Informacje OpenAPI: +serverLoopingMessage = Pętla serwera co {0} sekund +iisShutdownMessage = (Zamykanie IIS) +terminatingMessage = Kończenie... +eolPowerShellWarningMessage = [OSTRZEŻENIE] Pode {0} nie był testowany na PowerShell {1}, ponieważ jest to wersja EOL. +untestedPowerShellVersionWarningMessage = [OSTRZEŻENIE] Pode {0} nie był testowany na PowerShell {1}, ponieważ nie był dostępny, gdy Pode został wydany. '@ \ No newline at end of file diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index 9180d3c8a..4f5a79219 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -260,4 +260,25 @@ sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: O caminho de noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Nenhuma lógica passada. moduleDoesNotContainFunctionExceptionMessage = O módulo {0} não contém a função {1} para converter em uma Rota. pageNameShouldBeAlphaNumericExceptionMessage = O nome da página deve ser um valor alfanumérico válido: {0} +filesHaveChangedMessage = Os seguintes arquivos foram alterados: +multipleEndpointsForGuiMessage = Múltiplos endpoints definidos, apenas o primeiro será usado para a GUI. +openingGuiMessage = Abrindo a GUI. +listeningOnEndpointsMessage = Ouvindo nos seguintes {0} endpoint(s) [{1} thread(s)]: +specificationMessage = Especificação +documentationMessage = Documentação +restartingServerMessage = Reiniciando o servidor... +doneMessage = Concluído +deprecatedTitleVersionDescriptionWarningMessage = AVISO: Título, Versão e Descrição em 'Enable-PodeOpenApi' estão obsoletos. Utilize 'Add-PodeOAInfo' em vez disso. +undefinedOpenApiReferencesMessage = Referências OpenAPI indefinidas: +definitionTagMessage = Definição {0}: +openApiGenerationDocumentErrorMessage = Erro no documento de geração do OpenAPI: +infoTitleMandatoryMessage = info.title é obrigatório. +infoVersionMandatoryMessage = info.version é obrigatório. +missingComponentsMessage = Componente(s) ausente(s) +openApiInfoMessage = Informações OpenAPI: +serverLoopingMessage = Looping do servidor a cada {0} segundos +iisShutdownMessage = (Desligamento do IIS) +terminatingMessage = Terminando... +eolPowerShellWarningMessage = [AVISO] Pode {0} não foi testado no PowerShell {1}, pois está em EOL. +untestedPowerShellVersionWarningMessage = [AVISO] Pode {0} não foi testado no PowerShell {1}, pois não estava disponível quando o Pode foi lançado. '@ \ No newline at end of file diff --git a/src/Locales/zn/Pode.psd1 b/src/Locales/zn/Pode.psd1 index 90d6727e1..b51b5f4fa 100644 --- a/src/Locales/zn/Pode.psd1 +++ b/src/Locales/zn/Pode.psd1 @@ -260,4 +260,25 @@ sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: 为静态路 noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: 没有传递逻辑。 moduleDoesNotContainFunctionExceptionMessage = 模块 {0} 不包含要转换为路径的函数 {1}。 pageNameShouldBeAlphaNumericExceptionMessage = 页面名称应为有效的字母数字值: {0} +filesHaveChangedMessage = 以下文件已更改: +multipleEndpointsForGuiMessage = 定义了多个端点,仅第一个将用于 GUI。 +openingGuiMessage = 正在打开 GUI。 +listeningOnEndpointsMessage = 正在监听以下 {0} 个端点 [{1} 个线程]: +specificationMessage = 规格 +documentationMessage = 文档 +restartingServerMessage = 正在重启服务器... +doneMessage = 完成 +deprecatedTitleVersionDescriptionWarningMessage = 警告: 'Enable-PodeOpenApi' 的标题、版本和描述已被弃用。请改用 'Add-PodeOAInfo'。 +undefinedOpenApiReferencesMessage = 未定义的 OpenAPI 引用: +definitionTagMessage = 定义 {0}: +openApiGenerationDocumentErrorMessage = OpenAPI 生成文档错误: +infoTitleMandatoryMessage = info.title 是必填项。 +infoVersionMandatoryMessage = info.version 是必填项。 +missingComponentsMessage = 缺少的组件 +openApiInfoMessage = OpenAPI 信息: +serverLoopingMessage = 服务器每 {0} 秒循环一次 +iisShutdownMessage = (IIS 关闭) +terminatingMessage = 正在终止... +eolPowerShellWarningMessage = [警告] Pode {0} 未在 PowerShell {1} 上测试,因为它已达到 EOL。 +untestedPowerShellVersionWarningMessage = [警告] Pode {0} 未在 PowerShell {1} 上测试,因为 Pode 发布时该版本不可用。 '@ \ No newline at end of file diff --git a/src/Private/FileMonitor.ps1 b/src/Private/FileMonitor.ps1 index 1415b567a..7ebfcdc9d 100644 --- a/src/Private/FileMonitor.ps1 +++ b/src/Private/FileMonitor.ps1 @@ -68,7 +68,8 @@ function Start-PodeFileMonitor { # if enabled, show the files that triggered the restart if ($Event.MessageData.FileSettings.ShowFiles) { if (!$Event.MessageData.Quiet) { - Write-PodeHost 'The following files have changed:' -ForegroundColor Magenta + # The following files have changed + Write-PodeHost $PodeLocale.filesHaveChangedMessage -ForegroundColor Magenta foreach ($file in $Event.MessageData.FileSettings.Files) { Write-PodeHost "> $($file)" -ForegroundColor Magenta diff --git a/src/Private/Gui.ps1 b/src/Private/Gui.ps1 index 38265052c..30ecd0d45 100644 --- a/src/Private/Gui.ps1 +++ b/src/Private/Gui.ps1 @@ -16,7 +16,8 @@ function Start-PodeGuiRunspace { # if there are multiple endpoints, flag warning we're only using the first - unless explicitly set if ($null -eq $PodeContext.Server.Gui.Endpoint) { if ($PodeContext.Server.Endpoints.Values.Count -gt 1) { - Write-PodeHost 'Multiple endpoints defined, only the first will be used for the GUI' -ForegroundColor Yellow + # Multiple endpoints defined, only the first will be used for the GUI + Write-PodeHost $PodeLocale.multipleEndpointsForGuiMessage -ForegroundColor Yellow } } @@ -120,7 +121,8 @@ function Start-PodeGuiRunspace { } # display the form - Write-PodeHost 'Opening GUI' -ForegroundColor Yellow + # Opening the GUI + Write-PodeHost $PodeLocale.openingGuiMessage -ForegroundColor Yellow $null = $form.ShowDialog() Start-Sleep -Seconds 1 } diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index 8b45d1b85..af33276a4 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -879,7 +879,7 @@ function Close-PodeServerInternal { Remove-PodePSDrive if ($ShowDoneMessage -and ($PodeContext.Server.Types.Length -gt 0) -and !$PodeContext.Server.IsServerless) { - Write-PodeHost ' Done' -ForegroundColor Green + Write-PodeHost $PodeLocale.doneMessage -ForegroundColor Green } } @@ -2979,7 +2979,7 @@ function Get-PodeHandler { function Convert-PodeFileToScriptBlock { param( [Parameter(Mandatory = $true)] - [Alias("FilePath")] + [Alias('FilePath')] [string] $Path ) @@ -3027,7 +3027,7 @@ function Convert-PodeQueryStringToHashTable { function Get-PodeAstFromFile { param( [Parameter(Mandatory = $true)] - [Alias("FilePath")] + [Alias('FilePath')] [string] $Path ) @@ -3606,14 +3606,16 @@ function Test-PodeVersionPwshEOL { $isEol = "$($psVersion.Major).$($psVersion.Minor)" -in $eolVersions if ($isEol) { - Write-PodeHost "[WARNING] Pode $(Get-PodeVersion) has not been tested on PowerShell $($PSVersionTable.PSVersion), as it is EOL." -ForegroundColor Yellow + # [WARNING] Pode version has not been tested on PowerShell version, as it is EOL + Write-PodeHost ($PodeLocale.eolPowerShellWarningMessage -f $PodeVersion, $PSVersion) -ForegroundColor Yellow } $SupportedVersions = $moduleManifest.PrivateData.PwshVersions.Supported -split ',' $isSupported = "$($psVersion.Major).$($psVersion.Minor)" -in $SupportedVersions if ((! $isSupported) -and (! $isEol) -and $ReportUntested) { - Write-PodeHost "[WARNING] Pode $(Get-PodeVersion) has not been tested on PowerShell $($PSVersionTable.PSVersion), as it was not available when Pode was released." -ForegroundColor Yellow + # [WARNING] Pode version has not been tested on PowerShell version, as it was not available when Pode was released + Write-PodeHost ($PodeLocale.untestedPowerShellVersionWarningMessage -f $PodeVersion, $PSVersion) -ForegroundColor Yellow } return @{ diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index 1447db4c5..00c4be6a1 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -2038,31 +2038,37 @@ function Test-PodeOADefinitionInternal { # Check if the validation result indicates issues if (! $definitionIssues.valid) { # Print a header for undefined OpenAPI references - Write-PodeHost 'Undefined OpenAPI References :' -ForegroundColor Red + # Undefined OpenAPI References + Write-PodeHost $PodeLocale.undefinedOpenApiReferencesMessage -ForegroundColor Red # Iterate over each issue found in the definitions foreach ($tag in $definitionIssues.issues.keys) { - Write-PodeHost "Definition $tag :" -ForegroundColor Red + # Definition tag + Write-PodeHost ($PodeLocale.definitionTagMessage -f $tag) -ForegroundColor Red # Check and display issues related to OpenAPI document generation error if ($definitionIssues.issues[$tag].definition ) { - Write-PodeHost ' OpenAPI generation document error: ' -ForegroundColor Red + # OpenAPI generation document error + Write-PodeHost $PodeLocale.openApiGenerationDocumentErrorMessage -ForegroundColor Red Write-PodeHost " $($definitionIssues.issues[$tag].definition)" -ForegroundColor Red } # Check for missing mandatory 'title' field if ($definitionIssues.issues[$tag].title ) { - Write-PodeHost ' info.title is mandatory' -ForegroundColor Red + # info.title is mandatory + Write-PodeHost $PodeLocale.infoTitleMandatoryMessage -ForegroundColor Red } # Check for missing mandatory 'version' field if ($definitionIssues.issues[$tag].version ) { - Write-PodeHost ' info.version is mandatory' -ForegroundColor Red + # info.version is mandatory + Write-PodeHost $PodeLocale.infoVersionMandatoryMessage -ForegroundColor Red } # Check for missing components and list them if ($definitionIssues.issues[$tag].components ) { - Write-PodeHost ' Missing component(s)' -ForegroundColor Red + # Missing component(s) + Write-PodeHost $PodeLocale.missingComponentsMessage -ForegroundColor Red foreach ($key in $definitionIssues.issues[$tag].components.keys) { $occurences = $definitionIssues.issues[$tag].components[$key] # Adjust occurrence count based on schema validation setting diff --git a/src/Private/Server.ps1 b/src/Private/Server.ps1 index 60631c411..82a971288 100644 --- a/src/Private/Server.ps1 +++ b/src/Private/Server.ps1 @@ -149,7 +149,9 @@ function Start-PodeInternalServer { # state what endpoints are being listened on if ($endpoints.Length -gt 0) { - Write-PodeHost "Listening on the following $($endpoints.Length) endpoint(s) [$($PodeContext.Threads.General) thread(s)]:" -ForegroundColor Yellow + + # Listening on the following $endpoints.Length endpoint(s) [$PodeContext.Threads.General thread(s)] + Write-PodeHost ($PodeLocale.listeningOnEndpointsMessage -f $endpoints.Length, $PodeContext.Threads.General) -ForegroundColor Yellow $endpoints | ForEach-Object { $flags = @() if ($_.DualMode) { @@ -171,28 +173,32 @@ function Start-PodeInternalServer { if ( $bookmarks) { Write-PodeHost if (!$OpenAPIHeader) { - Write-PodeHost 'OpenAPI Info:' -ForegroundColor Yellow + # OpenAPI Info + Write-PodeHost $PodeLocale.openApiInfoMessage -ForegroundColor Yellow $OpenAPIHeader = $true } Write-PodeHost " '$key':" -ForegroundColor Yellow if ($bookmarks.route.count -gt 1 -or $bookmarks.route.Endpoint.Name) { - Write-PodeHost ' - Specification:' -ForegroundColor Yellow + # Specification + Write-PodeHost " - $($PodeLocale.specificationMessage):" -ForegroundColor Yellow foreach ($endpoint in $bookmarks.route.Endpoint) { Write-PodeHost " . $($endpoint.Protocol)://$($endpoint.Address)$($bookmarks.openApiUrl)" -ForegroundColor Yellow } - Write-PodeHost ' - Documentation:' -ForegroundColor Yellow + # Documentation + Write-PodeHost " - $($PodeLocale.documentationMessage):" -ForegroundColor Yellow foreach ($endpoint in $bookmarks.route.Endpoint) { Write-PodeHost " . $($endpoint.Protocol)://$($endpoint.Address)$($bookmarks.path)" -ForegroundColor Yellow } } else { - Write-PodeHost ' - Specification:' -ForegroundColor Yellow + # Specification + Write-PodeHost " - $($PodeLocale.specificationMessage):" -ForegroundColor Yellow $endpoints | ForEach-Object { $url = [System.Uri]::new( [System.Uri]::new($_.Url), $bookmarks.openApiUrl) Write-PodeHost " . $url" -ForegroundColor Yellow } - Write-PodeHost ' - Documentation:' -ForegroundColor Yellow + Write-PodeHost " - $($PodeLocale.documentationMessage):" -ForegroundColor Yellow $endpoints | ForEach-Object { $url = [System.Uri]::new( [System.Uri]::new($_.Url), $bookmarks.path) Write-PodeHost " . $url" -ForegroundColor Yellow @@ -211,7 +217,8 @@ function Start-PodeInternalServer { function Restart-PodeInternalServer { try { # inform restart - Write-PodeHost 'Restarting server...' -NoNewline -ForegroundColor Cyan + # Restarting server... + Write-PodeHost $PodeLocale.restartingServerMessage -NoNewline -ForegroundColor Cyan # run restart event hooks Invoke-PodeEvent -Type Restart @@ -333,7 +340,7 @@ function Restart-PodeInternalServer { $PodeContext.Server.Configuration = Open-PodeConfiguration -Context $PodeContext # done message - Write-PodeHost ' Done' -ForegroundColor Green + Write-PodeHost $PodeLocale.doneMessage -ForegroundColor Green # restart the server $PodeContext.Metrics.Server.RestartCount++ diff --git a/src/Private/ServiceServer.ps1 b/src/Private/ServiceServer.ps1 index 15dfe32ea..629de4484 100644 --- a/src/Private/ServiceServer.ps1 +++ b/src/Private/ServiceServer.ps1 @@ -6,7 +6,8 @@ function Start-PodeServiceServer { } # state we're running - Write-PodeHost "Server looping every $($PodeContext.Server.Interval)secs" -ForegroundColor Yellow + # Server looping every $PodeContext.Server.Interval secs + Write-PodeHost ($PodeLocale.serverLoopingMessage -f $PodeContext.Server.Interval) -ForegroundColor Yellow # script for the looping server $serverScript = { diff --git a/src/Public/Core.ps1 b/src/Public/Core.ps1 index 3d7f274c6..fec879baa 100644 --- a/src/Public/Core.ps1 +++ b/src/Public/Core.ps1 @@ -207,10 +207,12 @@ function Start-PodeServer { } if ($PodeContext.Server.IsIIS -and $PodeContext.Server.IIS.Shutdown) { - Write-PodeHost '(IIS Shutdown) ' -NoNewline -ForegroundColor Yellow + # (IIS Shutdown) + Write-PodeHost $PodeLocale.iisShutdownMessage -NoNewline -ForegroundColor Yellow + Write-PodeHost ' ' -NoNewline } - - Write-PodeHost 'Terminating...' -NoNewline -ForegroundColor Yellow + # Terminating... + Write-PodeHost $PodeLocale.terminatingMessage -NoNewline -ForegroundColor Yellow Invoke-PodeEvent -Type Terminate $PodeContext.Tokens.Cancellation.Cancel() } diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index d69a926c2..e5a386caa 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -181,7 +181,8 @@ function Enable-PodeOpenApi { if (! $Version) { $Version = '0.0.0' } - Write-PodeHost -ForegroundColor Yellow "WARNING: Title, Version, and Description on 'Enable-PodeOpenApi' are deprecated. Please use 'Add-PodeOAInfo' instead." + # WARNING: Title, Version, and Description on 'Enable-PodeOpenApi' are deprecated. Please use 'Add-PodeOAInfo' instead + Write-PodeHost $PodeLocale.deprecatedTitleVersionDescriptionWarningMessage -ForegroundColor Yellow } if ( $DefinitionTag -ine $PodeContext.Server.OpenAPI.DefaultDefinitionTag ) { $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag] = Get-PodeOABaseObject From 9671aefa19211ca31728f59303994b1cb5a2b798 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Thu, 6 Jun 2024 08:49:05 -0700 Subject: [PATCH 035/177] fix Locales escaping $ --- Convert-HashtableToPsd1.ps1 | 39 ++++++++++++++++++++++++++++ examples/FileBrowser/FileBrowser.ps1 | 2 +- src/Locales/ar/Pode.psd1 | 4 +-- src/Locales/de/Pode.psd1 | 4 +-- src/Locales/en/Pode.psd1 | 4 +-- src/Locales/es/Pode.psd1 | 4 +-- src/Locales/fr/Pode.psd1 | 4 +-- src/Locales/it/Pode.psd1 | 4 +-- src/Locales/ja/Pode.psd1 | 4 +-- src/Locales/ko/Pode.psd1 | 4 +-- src/Locales/pl/Pode.psd1 | 4 +-- src/Locales/pt/Pode.psd1 | 4 +-- src/Locales/zn/Pode.psd1 | 4 +-- 13 files changed, 62 insertions(+), 23 deletions(-) create mode 100644 Convert-HashtableToPsd1.ps1 diff --git a/Convert-HashtableToPsd1.ps1 b/Convert-HashtableToPsd1.ps1 new file mode 100644 index 000000000..1fab320b2 --- /dev/null +++ b/Convert-HashtableToPsd1.ps1 @@ -0,0 +1,39 @@ + +param ( + [Parameter(Mandatory = $false)] + [string]$Path = 'c:\Users\m_dan\Documents\GitHub\Pode\src\Locales\en\Pode.psd1 ' +) +$PodeFileContent = Get-content $Path -raw +$value = Invoke-Expression $podeFileContent + + +function Convert-HashTable { + param ( + [Parameter(Mandatory = $true)] + [hashtable]$hashtable + ) + + + $sb = New-Object System.Text.StringBuilder + $sb.AppendLine('@{') + + foreach ($key in $hashtable.Keys) { + $value = $hashtable[$key] + + if ($value -is [hashtable]) { + $nestedPsd1 = Convert-HashTable -hashtable $value + $sb.AppendLine(" $key = $nestedPsd1") | Out-Null + } + else { + $sb.AppendLine(" $key = `"$($value -replace '$','`$')`"") | Out-Null + } + } + + $sb.AppendLine('}') + return $sb.ToString() +} + + +$sb = Convert-HashTable -hashtable $value +Move-Item -path $Path -destination "$Path.old" +Set-Content -Path $Path -Value $sb \ No newline at end of file diff --git a/examples/FileBrowser/FileBrowser.ps1 b/examples/FileBrowser/FileBrowser.ps1 index b38befb8f..56564f805 100644 --- a/examples/FileBrowser/FileBrowser.ps1 +++ b/examples/FileBrowser/FileBrowser.ps1 @@ -2,7 +2,7 @@ $FileBrowserPath = Split-Path -Parent -Path $MyInvocation.MyCommand.Path $podePath = Split-Path -Parent -Path (Split-Path -Parent -Path $FileBrowserPath) if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { - Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop -ArgumentList 'ja' + Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop #-ArgumentList 'ja' } else { Import-Module -Name 'Pode' -ErrorAction Stop diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 0940a3697..773cdc984 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -56,7 +56,7 @@ invalidMiddlewareTypeExceptionMessage = أحد مكونات Middleware المق hashtableMiddlewareNoLogicExceptionMessage = مكون Middleware من نوع Hashtable المقدم لا يحتوي على منطق معرف. invalidLogicTypeInHashtableMiddlewareExceptionMessage = مكون Middleware من نوع Hashtable المقدم يحتوي على نوع منطق غير صالح. كان المتوقع ScriptBlock، ولكن تم الحصول عليه: {0} scopedVariableAlreadyDefinedExceptionMessage = المتغير المحدد بالفعل معرف: {0} -valueForUsingVariableNotFoundExceptionMessage = لم يتم العثور على قيمة لـ '$using:{0}'. +valueForUsingVariableNotFoundExceptionMessage = لم يتم العثور على قيمة لـ '`$using:{0}'. unlockSecretRequiredExceptionMessage = خاصية 'UnlockSecret' مطلوبة عند استخدام Microsoft.PowerShell.SecretStore unlockSecretButNoScriptBlockExceptionMessage = تم تقديم سر الفتح لنوع خزنة سرية مخصصة، ولكن لم يتم تقديم ScriptBlock الفتح. noUnlockScriptBlockForVaultExceptionMessage = لم يتم تقديم ScriptBlock الفتح لفتح الخزنة '{0}' @@ -146,7 +146,7 @@ routeParameterNeedsValidScriptblockExceptionMessage = المعامل Route يت noCommandsSuppliedToConvertToRoutesExceptionMessage = لم يتم توفير أي أوامر لتحويلها إلى طرق. nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = مطلوب ScriptBlock غير فارغ لإنشاء مسار الصفحة. sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = يمكن تكوين SSE فقط على الطلبات التي تحتوي على قيمة رأس Accept النص/تيار الأحداث. -sseConnectionNameRequiredExceptionMessage = مطلوب اسم اتصال SSE، إما من -Name أو $WebEvent.Sse.Name +sseConnectionNameRequiredExceptionMessage = مطلوب اسم اتصال SSE، إما من -Name أو `$WebEvent.Sse.Name sseFailedToBroadcastExceptionMessage = فشل بث SSE بسبب مستوى البث SSE المحدد لـ {0}: {1} podeNotInitializedExceptionMessage = لم يتم تهيئة Pode. invalidTaskTypeExceptionMessage = نوع المهمة غير صالح، المتوقع إما [System.Threading.Tasks.Task] أو [hashtable]. diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index dcfd18c46..a94c6c673 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -56,7 +56,7 @@ invalidMiddlewareTypeExceptionMessage = Eines der angegebenen Middleware-Objekte hashtableMiddlewareNoLogicExceptionMessage = Eine angegebene Hashtable-Middleware enthält keine definierte Logik. invalidLogicTypeInHashtableMiddlewareExceptionMessage = Eine angegebene Hashtable-Middleware enthält einen ungültigen Logik-Typ. Erwartet wurde ein ScriptBlock, aber erhalten wurde: {0}. scopedVariableAlreadyDefinedExceptionMessage = Die Bereichsvariable ist bereits definiert: {0}. -valueForUsingVariableNotFoundExceptionMessage = Der Wert für '$using:{0}' konnte nicht gefunden werden. +valueForUsingVariableNotFoundExceptionMessage = Der Wert für '`$using:{0}' konnte nicht gefunden werden. unlockSecretRequiredExceptionMessage = Eine 'UnlockSecret'-Eigenschaft ist erforderlich, wenn Microsoft.PowerShell.SecretStore verwendet wird. unlockSecretButNoScriptBlockExceptionMessage = Unlock secret für benutzerdefinierten Secret Vault-Typ angegeben, aber kein Unlock ScriptBlock bereitgestellt. noUnlockScriptBlockForVaultExceptionMessage = Kein Unlock ScriptBlock für das Entsperren des Tresors '{0}' bereitgestellt. @@ -146,7 +146,7 @@ routeParameterNeedsValidScriptblockExceptionMessage = Der Route-Parameter benöt noCommandsSuppliedToConvertToRoutesExceptionMessage = Keine Befehle zur Umwandlung in Routen bereitgestellt. nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Ein nicht leerer ScriptBlock ist erforderlich, um eine Seitenroute zu erstellen. sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE kann nur auf Anfragen mit einem Accept-Header-Wert von text/event-stream konfiguriert werden. -sseConnectionNameRequiredExceptionMessage = Ein SSE-Verbindungsname ist erforderlich, entweder von -Name oder $WebEvent.Sse.Name +sseConnectionNameRequiredExceptionMessage = Ein SSE-Verbindungsname ist erforderlich, entweder von -Name oder ``$WebEvent.Sse.Namee sseFailedToBroadcastExceptionMessage = SSE konnte aufgrund des definierten SSE-Broadcast-Levels für {0}: {1} nicht übertragen werden. podeNotInitializedExceptionMessage = Pode wurde nicht initialisiert. invalidTaskTypeExceptionMessage = Aufgabentyp ist ungültig, erwartet entweder [System.Threading.Tasks.Task] oder [hashtable] diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 80ded57b6..841fdd8f3 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -56,7 +56,7 @@ invalidMiddlewareTypeExceptionMessage = One of the Middlewares supplied is an in hashtableMiddlewareNoLogicExceptionMessage = A Hashtable Middleware supplied has no Logic defined. invalidLogicTypeInHashtableMiddlewareExceptionMessage = A Hashtable Middleware supplied has an invalid Logic type. Expected ScriptBlock, but got: {0} scopedVariableAlreadyDefinedExceptionMessage = Scoped Variable already defined: {0} -valueForUsingVariableNotFoundExceptionMessage = Value for '$using:{0}' could not be found. +valueForUsingVariableNotFoundExceptionMessage = Value for '`$using:{0}' could not be found. unlockSecretRequiredExceptionMessage = An 'UnlockSecret' property is required when using Microsoft.PowerShell.SecretStore unlockSecretButNoScriptBlockExceptionMessage = Unlock secret supplied for custom Secret Vault type, but not Unlock ScriptBlock supplied. noUnlockScriptBlockForVaultExceptionMessage = No Unlock ScriptBlock supplied for unlocking the vault '{0}' @@ -146,7 +146,7 @@ routeParameterNeedsValidScriptblockExceptionMessage = The Route parameter needs noCommandsSuppliedToConvertToRoutesExceptionMessage = No commands supplied to convert to Routes. nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = A non-empty ScriptBlock is required to create a Page Route. sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE can only be configured on requests with an Accept header value of text/event-stream -sseConnectionNameRequiredExceptionMessage = An SSE connection Name is required, either from -Name or $WebEvent.Sse.Name +sseConnectionNameRequiredExceptionMessage = An SSE connection Name is required, either from -Name or `$WebEvent.Sse.Name sseFailedToBroadcastExceptionMessage = SSE failed to broadcast due to defined SSE broadcast level for {0}: {1} podeNotInitializedExceptionMessage = Pode has not been initialized. invalidTaskTypeExceptionMessage = Task type is invalid, expected either [System.Threading.Tasks.Task] or [hashtable] diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 70b79a29a..2f3513626 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -56,7 +56,7 @@ invalidMiddlewareTypeExceptionMessage = Uno de los Middlewares suministrados es hashtableMiddlewareNoLogicExceptionMessage = Un Middleware Hashtable suministrado no tiene lógica definida. invalidLogicTypeInHashtableMiddlewareExceptionMessage = Un Middleware Hashtable suministrado tiene un tipo de lógica no válido. Se esperaba ScriptBlock, pero se obtuvo: {0} scopedVariableAlreadyDefinedExceptionMessage = La variable con alcance ya está definida: {0} -valueForUsingVariableNotFoundExceptionMessage = No se pudo encontrar el valor para '$using:{0}'. +valueForUsingVariableNotFoundExceptionMessage = No se pudo encontrar el valor para '`$using:{0}'. unlockSecretRequiredExceptionMessage = Se requiere una propiedad 'UnlockSecret' al usar Microsoft.PowerShell.SecretStore unlockSecretButNoScriptBlockExceptionMessage = Se suministró un secreto de desbloqueo para el tipo de bóveda secreta personalizada, pero no se suministró ningún ScriptBlock de desbloqueo. noUnlockScriptBlockForVaultExceptionMessage = No se suministró ningún ScriptBlock de desbloqueo para desbloquear la bóveda '{0}' @@ -146,7 +146,7 @@ routeParameterNeedsValidScriptblockExceptionMessage = El parámetro Route necesi noCommandsSuppliedToConvertToRoutesExceptionMessage = No se proporcionaron comandos para convertir a Rutas. nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Se requiere un ScriptBlock no vacío para crear una Ruta de Página. sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE solo se puede configurar en solicitudes con un valor de encabezado Accept de text/event-stream. -sseConnectionNameRequiredExceptionMessage = Se requiere un nombre de conexión SSE, ya sea de -Name o $WebEvent.Sse.Name. +sseConnectionNameRequiredExceptionMessage = Se requiere un nombre de conexión SSE, ya sea de -Name o $`$WebEvent.Sse.Name sseFailedToBroadcastExceptionMessage = SSE no pudo transmitir debido al nivel de transmisión SSE definido para {0}: {1}. podeNotInitializedExceptionMessage = Pode no se ha inicializado. invalidTaskTypeExceptionMessage = El tipo de tarea no es válido, se esperaba [System.Threading.Tasks.Task] o [hashtable]. diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index b9dddc8e3..c6c9ebb43 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -56,7 +56,7 @@ invalidMiddlewareTypeExceptionMessage = Un des Middlewares fournis est d'un type hashtableMiddlewareNoLogicExceptionMessage = Un Middleware Hashtable fourni n'a aucune logique définie. invalidLogicTypeInHashtableMiddlewareExceptionMessage = Un Middleware Hashtable fourni a un type de logique non valide. Attendu ScriptBlock, mais a obtenu : {0} scopedVariableAlreadyDefinedExceptionMessage = La variable à portée est déjà définie : {0} -valueForUsingVariableNotFoundExceptionMessage = Valeur pour '$using:{0}' introuvable. +valueForUsingVariableNotFoundExceptionMessage = Valeur pour '`$using:{0}' introuvable. unlockSecretRequiredExceptionMessage = Une propriété 'UnlockSecret' est requise lors de l'utilisation de Microsoft.PowerShell.SecretStore unlockSecretButNoScriptBlockExceptionMessage = Secret de déverrouillage fourni pour le type de coffre-fort personnalisé, mais aucun ScriptBlock de déverrouillage fourni. noUnlockScriptBlockForVaultExceptionMessage = Aucun ScriptBlock de déverrouillage fourni pour déverrouiller le coffre '{0}' @@ -146,7 +146,7 @@ routeParameterNeedsValidScriptblockExceptionMessage = Le paramètre de la route noCommandsSuppliedToConvertToRoutesExceptionMessage = Aucune commande fournie pour convertir en routes. nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Un ScriptBlock non vide est requis pour créer une route de page. sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE ne peut être configuré que sur les requêtes avec une valeur d'en-tête Accept de text/event-stream. -sseConnectionNameRequiredExceptionMessage = Un nom de connexion SSE est requis, soit de -Name soit de $WebEvent.Sse.Name. +sseConnectionNameRequiredExceptionMessage = Un nom de connexion SSE est requis, soit de -Name soit de $`$WebEvent.Sse.Name sseFailedToBroadcastExceptionMessage = SSE a échoué à diffuser en raison du niveau de diffusion SSE défini pour {0} : {1}. podeNotInitializedExceptionMessage = Pode n'a pas été initialisé. invalidTaskTypeExceptionMessage = Le type de tâche n'est pas valide, attendu [System.Threading.Tasks.Task] ou [hashtable]. diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index 231ededb4..da2d67c0a 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -56,7 +56,7 @@ invalidMiddlewareTypeExceptionMessage = Uno dei Middleware forniti è di un tipo hashtableMiddlewareNoLogicExceptionMessage = Un Middleware di tipo Hashtable fornito non ha una logica definita. invalidLogicTypeInHashtableMiddlewareExceptionMessage = Un Middleware di tipo Hashtable fornito ha un tipo di logica non valido. Previsto ScriptBlock, ma ottenuto: {0} scopedVariableAlreadyDefinedExceptionMessage = Variabile con ambito già definita: {0} -valueForUsingVariableNotFoundExceptionMessage = Impossibile trovare il valore per '$using:{0}'. +valueForUsingVariableNotFoundExceptionMessage = Impossibile trovare il valore per '`$using:{0}'. unlockSecretRequiredExceptionMessage = È necessaria una proprietà 'UnlockSecret' quando si utilizza Microsoft.PowerShell.SecretStore unlockSecretButNoScriptBlockExceptionMessage = Segreto di sblocco fornito per tipo di cassaforte segreta personalizzata, ma nessun ScriptBlock di sblocco fornito. noUnlockScriptBlockForVaultExceptionMessage = Nessun ScriptBlock di sblocco fornito per sbloccare la cassaforte '{0}' @@ -146,7 +146,7 @@ routeParameterNeedsValidScriptblockExceptionMessage = Il parametro della rotta r noCommandsSuppliedToConvertToRoutesExceptionMessage = Nessun comando fornito per convertirlo in rotte. nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = È richiesto uno ScriptBlock non vuoto per creare una rotta di pagina. sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE può essere configurato solo su richieste con un valore di intestazione Accept di text/event-stream. -sseConnectionNameRequiredExceptionMessage = È richiesto un nome di connessione SSE, sia da -Name che da $WebEvent.Sse.Name. +sseConnectionNameRequiredExceptionMessage = È richiesto un nome di connessione SSE, sia da -Name che da $`$WebEvent.Sse.Name sseFailedToBroadcastExceptionMessage = SSE non è riuscito a trasmettere a causa del livello di trasmissione SSE definito per {0}: {1}. podeNotInitializedExceptionMessage = Pode non è stato inizializzato. invalidTaskTypeExceptionMessage = Il tipo di attività non è valido, previsto [System.Threading.Tasks.Task] o [hashtable]. diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index 793ec1b8c..f84068e7a 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -56,7 +56,7 @@ invalidMiddlewareTypeExceptionMessage = 提供されたMiddlewaresの1つが無 hashtableMiddlewareNoLogicExceptionMessage = 提供されたHashtableミドルウェアにロジックが定義されていません。 invalidLogicTypeInHashtableMiddlewareExceptionMessage = 提供されたHashtableミドルウェアに無効なロジック型があります。ScriptBlockを期待しましたが、次を取得しました: {0} scopedVariableAlreadyDefinedExceptionMessage = スコープ付き変数が既に定義されています: {0} -valueForUsingVariableNotFoundExceptionMessage = '$using:{0}'の値が見つかりませんでした。 +valueForUsingVariableNotFoundExceptionMessage = '`$using:{0}'の値が見つかりませんでした。 unlockSecretRequiredExceptionMessage = Microsoft.PowerShell.SecretStoreを使用する場合、'UnlockSecret'プロパティが必要です。 unlockSecretButNoScriptBlockExceptionMessage = カスタムシークレットボールトタイプに対してアンロックシークレットが提供されましたが、アンロックスクリプトブロックが提供されていません。 noUnlockScriptBlockForVaultExceptionMessage = ボールト'{0}'のロック解除に必要なスクリプトブロックが提供されていません。 @@ -146,7 +146,7 @@ routeParameterNeedsValidScriptblockExceptionMessage = ルートパラメータ noCommandsSuppliedToConvertToRoutesExceptionMessage = ルートに変換するためのコマンドが提供されていません。 nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = ページルートを作成するには空でないScriptBlockが必要です。 sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSEはAcceptヘッダー値がtext/event-streamのリクエストでのみ構成できます。 -sseConnectionNameRequiredExceptionMessage = -Nameまたは$WebEvent.Sse.NameからSSE接続名が必要です。 +sseConnectionNameRequiredExceptionMessage = -Nameまたは`$WebEvent.Sse.NameからSSE接続名が必要です。 sseFailedToBroadcastExceptionMessage = {0}のSSEブロードキャストレベルが定義されているため、SSEのブロードキャストに失敗しました: {1} podeNotInitializedExceptionMessage = Podeが初期化されていません。 invalidTaskTypeExceptionMessage = タスクタイプが無効です。予期されるタイプ:[System.Threading.Tasks.Task]または[hashtable] diff --git a/src/Locales/ko/Pode.psd1 b/src/Locales/ko/Pode.psd1 index cc040056e..5e0cd3176 100644 --- a/src/Locales/ko/Pode.psd1 +++ b/src/Locales/ko/Pode.psd1 @@ -56,7 +56,7 @@ invalidMiddlewareTypeExceptionMessage = 제공된 미들웨어 중 하나가 잘 hashtableMiddlewareNoLogicExceptionMessage = 제공된 Hashtable 미들웨어에는 정의된 논리가 없습니다. invalidLogicTypeInHashtableMiddlewareExceptionMessage = 제공된 Hashtable 미들웨어에 잘못된 논리 유형이 있습니다. 예상된 유형은 ScriptBlock이지만, 얻은 것은: {0} scopedVariableAlreadyDefinedExceptionMessage = 범위 지정 변수가 이미 정의되었습니다: {0} -valueForUsingVariableNotFoundExceptionMessage = '$using:{0}'에 대한 값을 찾을 수 없습니다. +valueForUsingVariableNotFoundExceptionMessage = '`$using:{0}'에 대한 값을 찾을 수 없습니다. unlockSecretRequiredExceptionMessage = Microsoft.PowerShell.SecretStore를 사용할 때 'UnlockSecret' 속성이 필요합니다. unlockSecretButNoScriptBlockExceptionMessage = 사용자 정의 비밀 금고 유형에 대해 제공된 Unlock 비밀이지만, Unlock ScriptBlock이 제공되지 않았습니다. noUnlockScriptBlockForVaultExceptionMessage = 금고 '{0}'을(를) 해제하는 Unlock ScriptBlock이 제공되지 않았습니다. @@ -146,7 +146,7 @@ routeParameterNeedsValidScriptblockExceptionMessage = 경로 매개변수에는 noCommandsSuppliedToConvertToRoutesExceptionMessage = 경로로 변환할 명령이 제공되지 않았습니다. nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 페이지 경로를 생성하려면 비어 있지 않은 ScriptBlock이 필요합니다. sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE는 Accept 헤더 값이 text/event-stream인 요청에서만 구성할 수 있습니다. -sseConnectionNameRequiredExceptionMessage = -Name 또는 $WebEvent.Sse.Name에서 SSE 연결 이름이 필요합니다. +sseConnectionNameRequiredExceptionMessage = -Name 또는 `$WebEvent.Sse.Name에서 SSE 연결 이름이 필요합니다. sseFailedToBroadcastExceptionMessage = {0}에 대해 정의된 SSE 브로드캐스트 수준으로 인해 SSE 브로드캐스트에 실패했습니다: {1} podeNotInitializedExceptionMessage = Pode가 초기화되지 않았습니다. invalidTaskTypeExceptionMessage = 작업 유형이 유효하지 않습니다. 예상된 유형: [System.Threading.Tasks.Task] 또는 [hashtable] diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index 63e256b1c..33279d7cd 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -56,7 +56,7 @@ invalidMiddlewareTypeExceptionMessage = Jeden z dostarczonych Middleware jest ni hashtableMiddlewareNoLogicExceptionMessage = Dostarczone Middleware typu Hashtable nie ma zdefiniowanej logiki. invalidLogicTypeInHashtableMiddlewareExceptionMessage = Dostarczone Middleware typu Hashtable ma nieprawidłowy typ logiki. Oczekiwano ScriptBlock, ale otrzymano: {0} scopedVariableAlreadyDefinedExceptionMessage = Zmienna z zakresem już zdefiniowana: {0} -valueForUsingVariableNotFoundExceptionMessage = Nie można znaleźć wartości dla '$using:{0}'. +valueForUsingVariableNotFoundExceptionMessage = Nie można znaleźć wartości dla '`$using:{0}'. unlockSecretRequiredExceptionMessage = Właściwość 'UnlockSecret' jest wymagana przy używaniu Microsoft.PowerShell.SecretStore unlockSecretButNoScriptBlockExceptionMessage = Podano tajemnicę odblokowania dla niestandardowego typu skarbca, ale nie podano ScriptBlock odblokowania. noUnlockScriptBlockForVaultExceptionMessage = Nie podano ScriptBlock odblokowania dla odblokowania skarbca '{0}' @@ -146,7 +146,7 @@ routeParameterNeedsValidScriptblockExceptionMessage = Parametr trasy wymaga praw noCommandsSuppliedToConvertToRoutesExceptionMessage = Nie dostarczono żadnych poleceń do konwersji na trasy. nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Aby utworzyć trasę strony, wymagany jest niepusty ScriptBlock. sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE można skonfigurować tylko na żądaniach z wartością nagłówka Accept równą text/event-stream. -sseConnectionNameRequiredExceptionMessage = Wymagana jest nazwa połączenia SSE, z -Name lub $WebEvent.Sse.Name. +sseConnectionNameRequiredExceptionMessage = Wymagana jest nazwa połączenia SSE, z -Name lub $`$WebEvent.Sse.Name sseFailedToBroadcastExceptionMessage = SSE nie udało się przesłać z powodu zdefiniowanego poziomu przesyłania SSE dla {0}: {1} podeNotInitializedExceptionMessage = Pode nie został zainicjowany. invalidTaskTypeExceptionMessage = Typ zadania jest nieprawidłowy, oczekiwano [System.Threading.Tasks.Task] lub [hashtable] diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index 4f5a79219..1d3967d70 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -56,7 +56,7 @@ invalidMiddlewareTypeExceptionMessage = Um dos Middlewares fornecidos é de um t hashtableMiddlewareNoLogicExceptionMessage = Um Middleware do tipo Hashtable fornecido não tem lógica definida. invalidLogicTypeInHashtableMiddlewareExceptionMessage = Um Middleware do tipo Hashtable fornecido tem um tipo de lógica inválido. Esperado ScriptBlock, mas obtido: {0} scopedVariableAlreadyDefinedExceptionMessage = Variável de escopo já definida: {0} -valueForUsingVariableNotFoundExceptionMessage = Valor para '$using:{0}' não pôde ser encontrado. +valueForUsingVariableNotFoundExceptionMessage = Valor para '`$using:{0}' não pôde ser encontrado. unlockSecretRequiredExceptionMessage = É necessária uma propriedade 'UnlockSecret' ao usar Microsoft.PowerShell.SecretStore unlockSecretButNoScriptBlockExceptionMessage = Segredo de desbloqueio fornecido para tipo de Cofre Secreto personalizado, mas nenhum ScriptBlock de desbloqueio fornecido. noUnlockScriptBlockForVaultExceptionMessage = Nenhum ScriptBlock de desbloqueio fornecido para desbloquear o cofre '{0}' @@ -146,7 +146,7 @@ routeParameterNeedsValidScriptblockExceptionMessage = O parâmetro da Rota preci noCommandsSuppliedToConvertToRoutesExceptionMessage = Nenhum comando fornecido para converter em Rotas. nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Um ScriptBlock não vazio é necessário para criar uma Rota de Página. sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE só pode ser configurado em solicitações com um valor de cabeçalho Accept de text/event-stream. -sseConnectionNameRequiredExceptionMessage = Um nome de conexão SSE é necessário, seja de -Name ou $WebEvent.Sse.Name. +sseConnectionNameRequiredExceptionMessage = Um nome de conexão SSE é necessário, seja de -Name ou `$WebEvent.Sse.Name. sseFailedToBroadcastExceptionMessage = SSE falhou em transmitir devido ao nível de transmissão SSE definido para {0}: {1}. podeNotInitializedExceptionMessage = Pode não foi inicializado. invalidTaskTypeExceptionMessage = O tipo de tarefa é inválido, esperado [System.Threading.Tasks.Task] ou [hashtable]. diff --git a/src/Locales/zn/Pode.psd1 b/src/Locales/zn/Pode.psd1 index b51b5f4fa..77cc0d6aa 100644 --- a/src/Locales/zn/Pode.psd1 +++ b/src/Locales/zn/Pode.psd1 @@ -56,7 +56,7 @@ invalidMiddlewareTypeExceptionMessage = 提供的中间件之一是无效的类 hashtableMiddlewareNoLogicExceptionMessage = 提供的 Hashtable 中间件没有定义逻辑。 invalidLogicTypeInHashtableMiddlewareExceptionMessage = 提供的 Hashtable 中间件具有无效的逻辑类型。期望是 ScriptBlockm, 但得到了: {0} scopedVariableAlreadyDefinedExceptionMessage = 已经定义了作用域变量: {0} -valueForUsingVariableNotFoundExceptionMessage = 未找到 '$using:{0}' 的值。 +valueForUsingVariableNotFoundExceptionMessage = 未找到 '`$using:{0}' 的值。 unlockSecretRequiredExceptionMessage = 使用 Microsoft.PowerShell.SecretStore 时需要 'UnlockSecret' 属性。 unlockSecretButNoScriptBlockExceptionMessage = 为自定义秘密保险库类型提供了解锁密钥,但未提供解锁 ScriptBlock。 noUnlockScriptBlockForVaultExceptionMessage = 未为解锁保险库 '{0}' 提供解锁 ScriptBlock。 @@ -146,7 +146,7 @@ routeParameterNeedsValidScriptblockExceptionMessage = 路由参数需要有效 noCommandsSuppliedToConvertToRoutesExceptionMessage = 未提供要转换为路由的命令。 nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 创建页面路由需要非空的ScriptBlock。 sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE只能在Accept标头值为text/event-stream的请求上配置。 -sseConnectionNameRequiredExceptionMessage = 需要SSE连接名称, 可以从-Name或$WebEvent.Sse.Name获取。 +sseConnectionNameRequiredExceptionMessage = 需要SSE连接名称, 可以从-Name或`$WebEvent.Sse.Name获取。 sseFailedToBroadcastExceptionMessage = 由于为{0}定义的SSE广播级别, SSE广播失败: {1} podeNotInitializedExceptionMessage = Pode未初始化。 invalidTaskTypeExceptionMessage = 任务类型无效,预期类型为[System.Threading.Tasks.Task]或[hashtable]。 From 3bd305ee7daba1fbc5770f82973e33f5e3aaacb8 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Thu, 6 Jun 2024 11:17:25 -0700 Subject: [PATCH 036/177] conversion of Locales to hashtable --- Convert-HashtableToPsd1.ps1 | 32 +- src/Locales/ar/Pode.psd1 | 569 +++++++++++++++--------------- src/Locales/de/Pode.psd1 | 569 +++++++++++++++--------------- src/Locales/en/Pode.psd1 | 569 +++++++++++++++--------------- src/Locales/es/Pode.psd1 | 569 +++++++++++++++--------------- src/Locales/fr/Pode.psd1 | 569 +++++++++++++++--------------- src/Locales/it/Pode.psd1 | 569 +++++++++++++++--------------- src/Locales/ja/Pode.psd1 | 569 +++++++++++++++--------------- src/Locales/ko/Pode.psd1 | 569 +++++++++++++++--------------- src/Locales/pl/Pode.psd1 | 569 +++++++++++++++--------------- src/Locales/pt/Pode.psd1 | 569 +++++++++++++++--------------- src/Locales/zn/Pode.psd1 | 569 +++++++++++++++--------------- tests/unit/Localization.Tests.ps1 | 13 +- 13 files changed, 3156 insertions(+), 3148 deletions(-) diff --git a/Convert-HashtableToPsd1.ps1 b/Convert-HashtableToPsd1.ps1 index 1fab320b2..138dcddda 100644 --- a/Convert-HashtableToPsd1.ps1 +++ b/Convert-HashtableToPsd1.ps1 @@ -1,10 +1,9 @@ param ( [Parameter(Mandatory = $false)] - [string]$Path = 'c:\Users\m_dan\Documents\GitHub\Pode\src\Locales\en\Pode.psd1 ' + [string]$Path = 'c:\Users\m_dan\Documents\GitHub\Pode\src\Locales' ) -$PodeFileContent = Get-content $Path -raw -$value = Invoke-Expression $podeFileContent + function Convert-HashTable { @@ -15,25 +14,26 @@ function Convert-HashTable { $sb = New-Object System.Text.StringBuilder - $sb.AppendLine('@{') + $sb.AppendLine('@{') | Out-Null foreach ($key in $hashtable.Keys) { $value = $hashtable[$key] - - if ($value -is [hashtable]) { - $nestedPsd1 = Convert-HashTable -hashtable $value - $sb.AppendLine(" $key = $nestedPsd1") | Out-Null - } - else { - $sb.AppendLine(" $key = `"$($value -replace '$','`$')`"") | Out-Null - } + $sb.AppendLine(" $key = `"$value`"") | Out-Null } - $sb.AppendLine('}') + $sb.AppendLine('}') | Out-Null return $sb.ToString() } +$languageDirs = Get-ChildItem -Path $Path -Directory +foreach ($item in $languageDirs) { + $fullName = Join-Path -Path $item.FullName -ChildPath 'Pode.psd1' + + $PodeFileContent = Get-content $fullName -raw + $value = Invoke-Expression $podeFileContent + -$sb = Convert-HashTable -hashtable $value -Move-Item -path $Path -destination "$Path.old" -Set-Content -Path $Path -Value $sb \ No newline at end of file + $result = Convert-HashTable -hashtable $value + Move-Item -path $fullName -destination "$fullName.old" + Set-Content -Path $fullName -Value $result +} \ No newline at end of file diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 773cdc984..f5246baee 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -1,284 +1,285 @@ -ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyExceptionMessage = وحدة Active Directory متاحة فقط على نظام Windows. -adModuleNotInstalledExceptionMessage = وحدة Active Directory غير مثبتة. -secretManagementModuleNotInstalledExceptionMessage = وحدة Microsoft.PowerShell.SecretManagement غير مثبتة. -secretVaultAlreadyRegisteredAutoImportExceptionMessage = تم تسجيل خزنة سرية باسم '{0}' بالفعل أثناء استيراد الخزن السرية تلقائيًا. -failedToOpenRunspacePoolExceptionMessage = فشل في فتح RunspacePool: {0} -cronExpressionInvalidExceptionMessage = يجب أن تتكون تعبير Cron من 5 أجزاء فقط: {0} -invalidAliasFoundExceptionMessage = تم العثور على اسم مستعار غير صالح {0}: {1} -invalidAtomCharacterExceptionMessage = حرف الذرة غير صالح: {0} -minValueGreaterThanMaxExceptionMessage = يجب ألا تكون القيمة الدنيا {0} أكبر من القيمة القصوى. -minValueInvalidExceptionMessage = القيمة الدنيا '{0}' لـ {1} غير صالحة، يجب أن تكون أكبر من/أو تساوي {2} -maxValueInvalidExceptionMessage = القيمة القصوى '{0}' لـ {1} غير صالحة، يجب أن تكون أقل من/أو تساوي {2} -valueOutOfRangeExceptionMessage = القيمة '{0}' لـ {1} غير صالحة، يجب أن تكون بين {2} و {3} -daysInMonthExceededExceptionMessage = يحتوي {0} على {1} أيام فقط، ولكن تم توفير {2}. -nextTriggerCalculationErrorExceptionMessage = يبدو أن هناك خطأ ما أثناء محاولة حساب تاريخ المشغل التالي: {0} -incompatiblePodeDllExceptionMessage = يتم تحميل إصدار غير متوافق من Pode.DLL {0}. الإصدار {1} مطلوب. افتح جلسة Powershell/pwsh جديدة وأعد المحاولة. -endpointNotExistExceptionMessage = نقطة النهاية مع البروتوكول '{0}' والعنوان '{1}' أو العنوان المحلي '{2}' غير موجودة. -endpointNameNotExistExceptionMessage = نقطة النهاية بالاسم '{0}' غير موجودة. -failedToConnectToUrlExceptionMessage = فشل الاتصال بعنوان URL: {0} -failedToParseAddressExceptionMessage = فشل في تحليل '{0}' كعنوان IP/مضيف:منفذ صالح -invalidIpAddressExceptionMessage = عنوان IP المقدم غير صالح: {0} -invalidPortExceptionMessage = لا يمكن أن يكون المنفذ سالبًا: {0} -pathNotExistExceptionMessage = المسار غير موجود: {0} -noSecretForHmac256ExceptionMessage = لم يتم تقديم أي سر لتجزئة HMAC256. -noSecretForHmac384ExceptionMessage = لم يتم تقديم أي سر لتجزئة HMAC384. -noSecretForHmac512ExceptionMessage = لم يتم تقديم أي سر لتجزئة HMAC512. -noSecretForJwtSignatureExceptionMessage = لم يتم تقديم أي سر لتوقيع JWT. -noSecretExpectedForNoSignatureExceptionMessage = لم يكن من المتوقع تقديم أي سر لعدم وجود توقيع. -unsupportedJwtAlgorithmExceptionMessage = خوارزمية JWT غير مدعومة حاليًا: {0} -invalidBase64JwtExceptionMessage = تم العثور على قيمة مشفرة بتنسيق Base64 غير صالحة في JWT -invalidJsonJwtExceptionMessage = تم العثور على قيمة JSON غير صالحة في JWT -unsupportedFunctionInServerlessContextExceptionMessage = الدالة {0} غير مدعومة في سياق بدون خادم. -invalidPathWildcardOrDirectoryExceptionMessage = لا يمكن أن يكون المسار المقدم عبارة عن حرف بدل أو دليل: {0} -invalidExceptionTypeExceptionMessage = الاستثناء من نوع غير صالح، يجب أن يكون إما WebException أو HttpRequestException، ولكن تم الحصول عليه: {0} -pathToLoadNotFoundExceptionMessage = لم يتم العثور على المسار لتحميل {0}: {1} -singleValueForIntervalExceptionMessage = يمكنك تقديم قيمة {0} واحدة فقط عند استخدام الفواصل الزمنية. -scriptErrorExceptionMessage = خطأ '{0}' في البرنامج النصي {1} {2} (السطر {3}) الحرف {4} أثناء تنفيذ {5} على الكائن {6} 'الصنف: {7} الصنف الأساسي: {8} -noScriptBlockSuppliedExceptionMessage = لم يتم تقديم أي ScriptBlock. -iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN مفقود. -propertiesParameterWithoutNameExceptionMessage = لا يمكن استخدام معلمات الخصائص إذا لم يكن لدى الخاصية اسم. -multiTypePropertiesRequireOpenApi31ExceptionMessage = تتطلب خصائص الأنواع المتعددة إصدار OpenApi 3.1 أو أعلى. -openApiVersionPropertyMandatoryExceptionMessage = خاصية إصدار OpenApi إلزامية. -webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = ميزة Webhooks غير مدعومة في OpenAPI v3.0.x -authenticationMethodDoesNotExistExceptionMessage = طريقة المصادقة غير موجودة: {0} -unsupportedObjectExceptionMessage = الكائن غير مدعوم -validationOfAnyOfSchemaNotSupportedExceptionMessage = التحقق من مخطط يتضمن 'أي منها' غير مدعوم. -validationOfOneOfSchemaNotSupportedExceptionMessage = التحقق من مخطط يتضمن 'واحد منها' غير مدعوم. -cannotCreatePropertyWithoutTypeExceptionMessage = لا يمكن إنشاء الخاصية لأنه لم يتم تعريف نوع. -headerMustHaveNameInEncodingContextExceptionMessage = يجب أن يحتوي الرأس على اسم عند استخدامه في سياق الترميز. -descriptionRequiredExceptionMessage = الوصف مطلوب. -openApiDocumentNotCompliantExceptionMessage = مستند OpenAPI غير متوافق. -noComponentInDefinitionExceptionMessage = لا توجد مكون من نوع {0} باسم {1} متاح في تعريف {2}. -methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: تم التعريف بالفعل. -methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: تم التعريف بالفعل لـ {2} -invalidMiddlewareTypeExceptionMessage = أحد مكونات Middleware المقدمة من نوع غير صالح. كان المتوقع إما ScriptBlock أو Hashtable، ولكن تم الحصول عليه: {0} -hashtableMiddlewareNoLogicExceptionMessage = مكون Middleware من نوع Hashtable المقدم لا يحتوي على منطق معرف. -invalidLogicTypeInHashtableMiddlewareExceptionMessage = مكون Middleware من نوع Hashtable المقدم يحتوي على نوع منطق غير صالح. كان المتوقع ScriptBlock، ولكن تم الحصول عليه: {0} -scopedVariableAlreadyDefinedExceptionMessage = المتغير المحدد بالفعل معرف: {0} -valueForUsingVariableNotFoundExceptionMessage = لم يتم العثور على قيمة لـ '`$using:{0}'. -unlockSecretRequiredExceptionMessage = خاصية 'UnlockSecret' مطلوبة عند استخدام Microsoft.PowerShell.SecretStore -unlockSecretButNoScriptBlockExceptionMessage = تم تقديم سر الفتح لنوع خزنة سرية مخصصة، ولكن لم يتم تقديم ScriptBlock الفتح. -noUnlockScriptBlockForVaultExceptionMessage = لم يتم تقديم ScriptBlock الفتح لفتح الخزنة '{0}' -noSetScriptBlockForVaultExceptionMessage = لم يتم تقديم ScriptBlock الإعداد لتحديث/إنشاء الأسرار في الخزنة '{0}' -noRemoveScriptBlockForVaultExceptionMessage = لم يتم تقديم ScriptBlock الإزالة لإزالة الأسرار من الخزنة '{0}' -invalidSecretValueTypeExceptionMessage = قيمة السر من نوع غير صالح. الأنواع المتوقعة: String، SecureString، HashTable، Byte[]، أو PSCredential. ولكن تم الحصول عليه: {0} -limitValueCannotBeZeroOrLessExceptionMessage = لا يمكن أن تكون القيمة الحدية 0 أو أقل لـ {0} -secondsValueCannotBeZeroOrLessExceptionMessage = لا يمكن أن تكون قيمة الثواني 0 أو أقل لـ {0} -failedToCreateOpenSslCertExceptionMessage = فشل في إنشاء شهادة openssl: {0} -certificateThumbprintsNameSupportedOnWindowsExceptionMessage = بصمات الإبهام/الاسم للشهادة مدعومة فقط على Windows. -noCertificateFoundExceptionMessage = لم يتم العثور على شهادة في {0}\{1} لـ '{2}' -runspacePoolFailedToLoadExceptionMessage = فشل تحميل RunspacePool لـ {0}. -noServiceHandlersDefinedExceptionMessage = لم يتم تعريف أي معالجات خدمة. -noSessionToSetOnResponseExceptionMessage = لا توجد جلسة متاحة لتعيينها على الاستجابة. -noSessionToCalculateDataHashExceptionMessage = لا توجد جلسة متاحة لحساب تجزئة البيانات. -moduleOrVersionNotFoundExceptionMessage = لم يتم العثور على الوحدة أو الإصدار على {0}: {1}@{2} -noSmtpHandlersDefinedExceptionMessage = لم يتم تعريف أي معالجات SMTP. -taskTimedOutExceptionMessage = انتهت المهلة الزمنية للمهمة بعد {0}ms. -verbAlreadyDefinedExceptionMessage = [الفعل] {0}: تم التعريف بالفعل -verbAlreadyDefinedForUrlExceptionMessage = [الفعل] {0}: تم التعريف بالفعل لـ {1} -pathOrScriptBlockRequiredExceptionMessage = مطلوب مسار أو ScriptBlock للحصول على قيم الوصول المخصصة. -accessMethodAlreadyDefinedExceptionMessage = طريقة الوصول معرفة بالفعل: {0} -accessMethodNotExistForMergingExceptionMessage = طريقة الوصول غير موجودة للدمج: {0} -routeAlreadyContainsCustomAccessExceptionMessage = المسار '[{0}] {1}' يحتوي بالفعل على وصول مخصص باسم '{2}' -accessMethodNotExistExceptionMessage = طريقة الوصول غير موجودة: {0} -pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = ميزة PathItems غير مدعومة في OpenAPI v3.0.x -nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = مطلوب ScriptBlock غير فارغ لخطة المصادقة المخصصة. -oauth2InnerSchemeInvalidExceptionMessage = يمكن أن تكون OAuth2 InnerScheme إما مصادقة Basic أو Form فقط، ولكن تم الحصول على: {0} -sessionsRequiredForOAuth2WithPKCEExceptionMessage = تتطلب OAuth2 مع PKCE جلسات. -oauth2ClientSecretRequiredExceptionMessage = تتطلب OAuth2 سر العميل عند عدم استخدام PKCE. -authMethodAlreadyDefinedExceptionMessage = طريقة المصادقة محددة بالفعل: {0} -invalidSchemeForAuthValidatorExceptionMessage = تتطلب الخطة '{0}' المقدمة لمحقق المصادقة '{1}' ScriptBlock صالح. -sessionsRequiredForSessionPersistentAuthExceptionMessage = تتطلب المصادقة المستمرة للجلسة جلسات. -oauth2RequiresAuthorizeUrlExceptionMessage = تتطلب OAuth2 توفير عنوان URL للتفويض. -authMethodNotExistForMergingExceptionMessage = طريقة المصادقة غير موجودة للدمج: {0} -mergeDefaultAuthNotInListExceptionMessage = المصادقة MergeDefault '{0}' غير موجودة في قائمة المصادقة المقدمة. -defaultAuthNotInListExceptionMessage = المصادقة الافتراضية '{0}' غير موجودة في قائمة المصادقة المقدمة. -scriptBlockRequiredForMergingUsersExceptionMessage = مطلوب ScriptBlock لدمج عدة مستخدمين مصادق عليهم في كائن واحد عندما تكون Valid هي All. -noDomainServerNameForWindowsAdAuthExceptionMessage = لم يتم توفير اسم خادم المجال لمصادقة Windows AD. -sessionsNotConfiguredExceptionMessage = لم يتم تكوين الجلسات. -windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = دعم المصادقة المحلية لـ Windows هو فقط لنظام Windows. -iisAuthSupportIsForWindowsOnlyExceptionMessage = دعم مصادقة IIS هو فقط لنظام Windows. -noAlgorithmInJwtHeaderExceptionMessage = لم يتم توفير أي خوارزمية في رأس JWT. -invalidJwtSuppliedExceptionMessage = JWT المقدم غير صالح. -invalidJwtHeaderAlgorithmSuppliedExceptionMessage = خوارزمية رأس JWT المقدمة غير صالحة. -noJwtSignatureForAlgorithmExceptionMessage = لم يتم توفير توقيع JWT لـ {0}. -expectedNoJwtSignatureSuppliedExceptionMessage = لم يكن من المتوقع توفير توقيع JWT. -invalidJwtSignatureSuppliedExceptionMessage = توقيع JWT المقدم غير صالح. -jwtExpiredExceptionMessage = انتهت صلاحية JWT. -jwtNotYetValidExceptionMessage = JWT غير صالح للاستخدام بعد. -snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Snapins مدعومة فقط في Windows PowerShell. -userFileDoesNotExistExceptionMessage = ملف المستخدم غير موجود: {0} -schemeRequiresValidScriptBlockExceptionMessage = تتطلب الخطة المقدمة لمحقق المصادقة '{0}' ScriptBlock صالح. -oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = مزود OAuth2 لا يدعم نوع الاستجابة 'code'. -oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = مزود OAuth2 لا يدعم نوع المنحة 'password' المطلوبة لاستخدام InnerScheme. -eventAlreadyRegisteredExceptionMessage = الحدث {0} مسجل بالفعل: {1} -noEventRegisteredExceptionMessage = لا يوجد حدث {0} مسجل: {1} -sessionsRequiredForFlashMessagesExceptionMessage = الجلسات مطلوبة لاستخدام رسائل الفلاش. -eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = تسجيل عارض الأحداث مدعوم فقط على Windows. -nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = مطلوب ScriptBlock غير فارغ لطريقة إخراج السجل المخصصة. -requestLoggingAlreadyEnabledExceptionMessage = تم تمكين تسجيل الطلبات بالفعل. -outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = طريقة الإخراج المقدمة لتسجيل الطلبات تتطلب ScriptBlock صالح. -errorLoggingAlreadyEnabledExceptionMessage = تم تمكين تسجيل الأخطاء بالفعل. -nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = مطلوب ScriptBlock غير فارغ لطريقة التسجيل. -csrfMiddlewareNotInitializedExceptionMessage = لم يتم تهيئة CSRF Middleware. -sessionsRequiredForCsrfExceptionMessage = الجلسات مطلوبة لاستخدام CSRF إلا إذا كنت ترغب في استخدام ملفات تعريف الارتباط. -middlewareNoLogicSuppliedExceptionMessage = [Middleware]: لم يتم توفير أي منطق في ScriptBlock. -parameterHasNoNameExceptionMessage = لا يحتوي المعامل على اسم. يرجى إعطاء هذا المكون اسمًا باستخدام معامل 'Name'. -reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = ميزة المكون القابل لإعادة الاستخدام 'pathItems' غير متوفرة في OpenAPI v3.0. -noPropertiesMutuallyExclusiveExceptionMessage = المعامل 'NoProperties' يتعارض مع 'Properties' و 'MinProperties' و 'MaxProperties'. -discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = يمكن استخدام المعامل 'DiscriminatorMapping' فقط عندما تكون خاصية 'DiscriminatorProperty' موجودة. -discriminatorIncompatibleWithAllOfExceptionMessage = المعامل 'Discriminator' غير متوافق مع 'allOf'. -typeCanOnlyBeAssociatedWithObjectExceptionMessage = النوع {0} يمكن ربطه فقط بجسم. -showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui متاح حاليًا فقط لـ Windows PowerShell و PowerShell 7+ على Windows. -nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = مطلوب اسم لنقطة النهاية إذا تم توفير معامل RedirectTo. -clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = الشهادات العميلة مدعومة فقط على نقاط النهاية HTTPS. -explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = وضع TLS الصريح مدعوم فقط على نقاط النهاية SMTPS و TCPS. -acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = رسالة الإقرار مدعومة فقط على نقاط النهاية SMTP و TCP. -crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = فحص نهاية الرسالة CRLF مدعوم فقط على نقاط النهاية TCP. -mustBeRunningWithAdminPrivilegesExceptionMessage = يجب التشغيل بامتيازات المسؤول للاستماع إلى العناوين غير المحلية. -certificateSuppliedForNonHttpsWssEndpointExceptionMessage = تم توفير شهادة لنقطة نهاية غير HTTPS/WSS. -websocketsNotConfiguredForSignalMessagesExceptionMessage = لم يتم تهيئة WebSockets لإرسال رسائل الإشارة. -noPathSuppliedForRouteExceptionMessage = لم يتم توفير مسار للطريق. -accessRequiresAuthenticationOnRoutesExceptionMessage = يتطلب الوصول توفير المصادقة على الطرق. -accessMethodDoesNotExistExceptionMessage = طريقة الوصول غير موجودة: {0}. -routeParameterNeedsValidScriptblockExceptionMessage = المعامل Route يتطلب ScriptBlock صالح وغير فارغ. -noCommandsSuppliedToConvertToRoutesExceptionMessage = لم يتم توفير أي أوامر لتحويلها إلى طرق. -nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = مطلوب ScriptBlock غير فارغ لإنشاء مسار الصفحة. -sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = يمكن تكوين SSE فقط على الطلبات التي تحتوي على قيمة رأس Accept النص/تيار الأحداث. -sseConnectionNameRequiredExceptionMessage = مطلوب اسم اتصال SSE، إما من -Name أو `$WebEvent.Sse.Name -sseFailedToBroadcastExceptionMessage = فشل بث SSE بسبب مستوى البث SSE المحدد لـ {0}: {1} -podeNotInitializedExceptionMessage = لم يتم تهيئة Pode. -invalidTaskTypeExceptionMessage = نوع المهمة غير صالح، المتوقع إما [System.Threading.Tasks.Task] أو [hashtable]. -cannotLockValueTypeExceptionMessage = لا يمكن قفل [ValueTypes]. -cannotLockNullObjectExceptionMessage = لا يمكن قفل كائن فارغ. -failedToAcquireLockExceptionMessage = فشل في الحصول على قفل على الكائن. -cannotUnlockValueTypeExceptionMessage = لا يمكن فتح [ValueTypes]. -cannotUnlockNullObjectExceptionMessage = لا يمكن فتح كائن فارغ. -sessionMiddlewareAlreadyInitializedExceptionMessage = تم تهيئة Session Middleware بالفعل. -customSessionStorageMethodNotImplementedExceptionMessage = تخزين الجلسة المخصص لا ينفذ الطريقة المطلوبة '{0}()'. -secretRequiredForCustomSessionStorageExceptionMessage = مطلوب سر عند استخدام تخزين الجلسة المخصص. -noSessionAvailableToSaveExceptionMessage = لا توجد جلسة متاحة للحفظ. -cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = لا يمكن توفير فترة زمنية عندما يكون المعامل 'Every' مضبوطًا على None. -cannotSupplyIntervalForQuarterExceptionMessage = لا يمكن توفير قيمة الفاصل الزمني لكل ربع. -cannotSupplyIntervalForYearExceptionMessage = لا يمكن توفير قيمة الفاصل الزمني لكل سنة. -secretVaultAlreadyRegisteredExceptionMessage = تم تسجيل مخزن الأسرار بالاسم '{0}' بالفعل{1}. -secretVaultUnlockExpiryDateInPastExceptionMessage = تاريخ انتهاء صلاحية فتح مخزن الأسرار في الماضي (UTC): {0} -secretAlreadyMountedExceptionMessage = تم تثبيت سر بالاسم '{0}' بالفعل. -credentialsPassedWildcardForHeadersLiteralExceptionMessage = عند تمرير بيانات الاعتماد، سيتم اعتبار العلامة * للعنوان كـ سلسلة نصية حرفية وليس كعلامة. -wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = العلامة * للعنوان غير متوافقة مع مفتاح AutoHeaders. -wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = العلامة * للطرق غير متوافقة مع مفتاح AutoMethods. -invalidAccessControlMaxAgeDurationExceptionMessage = مدة Access-Control-Max-Age غير صالحة المقدمة: {0}. يجب أن تكون أكبر من 0. -noNameForWebSocketDisconnectExceptionMessage = لا يوجد اسم لفصل WebSocket من المزود. -noNameForWebSocketRemoveExceptionMessage = لا يوجد اسم لإزالة WebSocket من المزود. -noNameForWebSocketSendMessageExceptionMessage = لا يوجد اسم لإرسال رسالة إلى WebSocket المزود. -noSecretNamedMountedExceptionMessage = لم يتم تثبيت أي سر بالاسم '{0}'. -noNameForWebSocketResetExceptionMessage = لا يوجد اسم لإعادة تعيين WebSocket من المزود. -schemaValidationRequiresPowerShell610ExceptionMessage = يتطلب التحقق من صحة المخطط إصدار PowerShell 6.1.0 أو أحدث. -routeParameterCannotBeNullExceptionMessage = لا يمكن أن يكون المعامل 'Route' فارغًا. -encodingAttributeOnlyAppliesToMultipartExceptionMessage = ينطبق سمة الترميز فقط على نصوص الطلبات multipart و application/x-www-form-urlencoded. -testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = يجب تمكين 'Test-PodeOAComponentSchema' باستخدام 'Enable-PodeOpenApi -EnableSchemaValidation' -openApiComponentSchemaDoesNotExistExceptionMessage = مخطط مكون OpenApi {0} غير موجود. -openApiParameterRequiresNameExceptionMessage = يتطلب معلمة OpenApi اسمًا محددًا. -openApiLicenseObjectRequiresNameExceptionMessage = يتطلب كائن OpenAPI 'license' الخاصية 'name'. استخدم المعامل -LicenseName. -parametersValueOrExternalValueMandatoryExceptionMessage = المعاملات 'Value' أو 'ExternalValue' إلزامية. -parametersMutuallyExclusiveExceptionMessage = المعاملات '{0}' و '{1}' متعارضة. -maximumConcurrentWebSocketThreadsInvalidExceptionMessage = يجب أن يكون الحد الأقصى لمؤشرات ترابط WebSocket المتزامنة >=1، ولكن تم الحصول عليه: {0} -maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = لا يمكن أن يكون الحد الأقصى لمؤشرات ترابط WebSocket المتزامنة أقل من الحد الأدنى {0}، ولكن تم الحصول عليه: {1} -alreadyConnectedToWebSocketExceptionMessage = متصل بالفعل بـ WebSocket بالاسم '{0}' -failedToConnectToWebSocketExceptionMessage = فشل الاتصال بـ WebSocket: {0} -verbNoLogicPassedExceptionMessage = [الفعل] {0}: لم يتم تمرير أي منطق -scriptPathDoesNotExistExceptionMessage = مسار البرنامج النصي غير موجود: {0} -failedToImportModuleExceptionMessage = فشل في استيراد الوحدة: {0} -modulePathDoesNotExistExceptionMessage = مسار الوحدة غير موجود: {0} -defaultValueNotBooleanOrEnumExceptionMessage = القيمة الافتراضية ليست من نوع boolean وليست جزءًا من التعداد. -propertiesTypeObjectAssociationExceptionMessage = يمكن ربط خصائص النوع Object فقط بـ {0}. -invalidContentTypeForSchemaExceptionMessage = 'content-type' غير صالح في المخطط: {0} -openApiRequestStyleInvalidForParameterExceptionMessage = لا يمكن أن يكون نمط الطلب OpenApi {0} لمعلمة {1}. -pathParameterRequiresRequiredSwitchExceptionMessage = إذا كانت موقع المعلمة هو 'Path'، فإن المعلمة التبديل 'Required' إلزامية. -operationIdMustBeUniqueForArrayExceptionMessage = يجب أن يكون OperationID: {0} فريدًا ولا يمكن تطبيقه على مصفوفة. -operationIdMustBeUniqueExceptionMessage = يجب أن يكون OperationID: {0} فريدًا. -noOpenApiUrlSuppliedExceptionMessage = لم يتم توفير عنوان URL OpenAPI لـ {0}. -noTitleSuppliedForPageExceptionMessage = لم يتم توفير عنوان للصفحة {0}. -noRoutePathSuppliedForPageExceptionMessage = لم يتم توفير مسار للصفحة {0}. -swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = هذا الإصدار من Swagger-Editor لا يدعم OpenAPI 3.1 -rapidPdfDoesNotSupportOpenApi31ExceptionMessage = أداة الوثائق RapidPdf لا تدعم OpenAPI 3.1 -definitionTagNotDefinedExceptionMessage = لم يتم تعريف علامة التعريف {0}. -scopedVariableNotFoundExceptionMessage = لم يتم العثور على المتغير المحدد: {0} -noSecretVaultRegisteredExceptionMessage = لم يتم تسجيل خزينة سرية بالاسم '{0}'. -invalidStrictTransportSecurityDurationExceptionMessage = تم توفير مدة Strict-Transport-Security غير صالحة: {0}. يجب أن تكون أكبر من 0. -durationMustBeZeroOrGreaterExceptionMessage = يجب أن تكون المدة 0 أو أكبر، ولكن تم الحصول عليها: {0}s -taskAlreadyDefinedExceptionMessage = [المهمة] {0}: المهمة معرفة بالفعل. -maximumConcurrentTasksInvalidExceptionMessage = يجب أن يكون الحد الأقصى للمهام المتزامنة >=1، ولكن تم الحصول عليه: {0} -maximumConcurrentTasksLessThanMinimumExceptionMessage = لا يمكن أن يكون الحد الأقصى للمهام المتزامنة أقل من الحد الأدنى {0}، ولكن تم الحصول عليه: {1} -taskDoesNotExistExceptionMessage = المهمة '{0}' غير موجودة. -cacheStorageNotFoundForRetrieveExceptionMessage = لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة استرجاع العنصر المخزن مؤقتًا '{1}' -cacheStorageNotFoundForSetExceptionMessage = لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة تعيين العنصر المخزن مؤقتًا '{1}' -cacheStorageNotFoundForExistsExceptionMessage = لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة التحقق مما إذا كان العنصر المخزن مؤقتًا '{1}' موجودًا. -cacheStorageNotFoundForRemoveExceptionMessage = لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة إزالة العنصر المخزن مؤقتًا '{1}' -cacheStorageNotFoundForClearExceptionMessage = لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة مسح الذاكرة المؤقتة. -cacheStorageAlreadyExistsExceptionMessage = مخزن ذاكرة التخزين المؤقت بالاسم '{0}' موجود بالفعل. -pathToIconForGuiDoesNotExistExceptionMessage = المسار إلى الأيقونة للواجهة الرسومية غير موجود: {0} -invalidHostnameSuppliedExceptionMessage = اسم المضيف المقدم غير صالح: {0} -endpointAlreadyDefinedExceptionMessage = تم تعريف نقطة نهاية باسم '{0}' بالفعل. -certificateExpiredExceptionMessage = الشهادة '{0}' منتهية الصلاحية: {1} -endpointNotDefinedForRedirectingExceptionMessage = لم يتم تعريف نقطة نهاية باسم '{0}' لإعادة التوجيه. -fileWatcherAlreadyDefinedExceptionMessage = تم تعريف مراقب الملفات باسم '{0}' بالفعل. -handlerAlreadyDefinedExceptionMessage = [{0}] {1}: تم تعريف المعالج بالفعل. -maxDaysInvalidExceptionMessage = يجب أن يكون MaxDays 0 أو أكبر، ولكن تم الحصول على: {0} -maxSizeInvalidExceptionMessage = يجب أن يكون MaxSize 0 أو أكبر، ولكن تم الحصول على: {0} -loggingMethodAlreadyDefinedExceptionMessage = تم تعريف طريقة التسجيل بالفعل: {0} -loggingMethodRequiresValidScriptBlockExceptionMessage = تتطلب طريقة الإخراج المقدمة لطريقة التسجيل '{0}' ScriptBlock صالح. -csrfCookieRequiresSecretExceptionMessage = عند استخدام ملفات تعريف الارتباط لـ CSRF، يكون السر مطلوبًا. يمكنك تقديم سر أو تعيين السر العالمي لملف تعريف الارتباط - (Set-PodeCookieSecret '' -Global) -bodyParserAlreadyDefinedForContentTypeExceptionMessage = تم تعريف محلل الجسم لنوع المحتوى {0} بالفعل. -middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: تم تعريف الوسيط بالفعل. -parameterNotSuppliedInRequestExceptionMessage = لم يتم توفير معلمة باسم '{0}' في الطلب أو لا توجد بيانات متاحة. -noDataForFileUploadedExceptionMessage = لا توجد بيانات للملف '{0}' الذي تم تحميله في الطلب. -viewsFolderNameAlreadyExistsExceptionMessage = اسم مجلد العرض موجود بالفعل: {0} -viewsPathDoesNotExistExceptionMessage = مسار العرض غير موجود: {0} -timerAlreadyDefinedExceptionMessage = [المؤقت] {0}: المؤقت معرف بالفعل. -timerParameterMustBeGreaterThanZeroExceptionMessage = [المؤقت] {0}: {1} يجب أن يكون أكبر من 0. -timerDoesNotExistExceptionMessage = المؤقت '{0}' غير موجود. -mutexAlreadyExistsExceptionMessage = يوجد بالفعل Mutex بالاسم التالي: {0} -noMutexFoundExceptionMessage = لم يتم العثور على Mutex باسم '{0}' -failedToAcquireMutexOwnershipExceptionMessage = فشل في الحصول على ملكية Mutex. اسم Mutex: {0} -semaphoreAlreadyExistsExceptionMessage = يوجد بالفعل Semaphore بالاسم التالي: {0} -failedToAcquireSemaphoreOwnershipExceptionMessage = فشل في الحصول على ملكية Semaphore. اسم Semaphore: {0} -scheduleAlreadyDefinedExceptionMessage = [الجدول الزمني] {0}: الجدول الزمني معرف بالفعل. -scheduleCannotHaveNegativeLimitExceptionMessage = [الجدول الزمني] {0}: لا يمكن أن يكون له حد سلبي. -scheduleEndTimeMustBeInFutureExceptionMessage = [الجدول الزمني] {0}: يجب أن تكون قيمة EndTime في المستقبل. -scheduleStartTimeAfterEndTimeExceptionMessage = [الجدول الزمني] {0}: لا يمكن أن يكون 'StartTime' بعد 'EndTime' -maximumConcurrentSchedulesInvalidExceptionMessage = يجب أن تكون الجداول الزمنية المتزامنة القصوى >=1 ولكن تم الحصول على: {0} -maximumConcurrentSchedulesLessThanMinimumExceptionMessage = لا يمكن أن تكون الجداول الزمنية المتزامنة القصوى أقل من الحد الأدنى {0} ولكن تم الحصول على: {1} -scheduleDoesNotExistExceptionMessage = الجدول الزمني '{0}' غير موجود. -suppliedDateBeforeScheduleStartTimeExceptionMessage = التاريخ المقدم قبل وقت بدء الجدول الزمني في {0} -suppliedDateAfterScheduleEndTimeExceptionMessage = التاريخ المقدم بعد وقت انتهاء الجدول الزمني في {0} -noSemaphoreFoundExceptionMessage = لم يتم العثور على Semaphore باسم '{0}' -noLogicPassedForRouteExceptionMessage = لم يتم تمرير منطق للمسار: {0} -noPathSuppliedForStaticRouteExceptionMessage = [{0}]: لم يتم توفير مسار للمسار الثابت. -sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: مسار المصدر المقدم للمسار الثابت غير موجود: {2} -noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: لم يتم تمرير منطق. -moduleDoesNotContainFunctionExceptionMessage = الوحدة {0} لا تحتوي على الوظيفة {1} لتحويلها إلى مسار. -pageNameShouldBeAlphaNumericExceptionMessage = يجب أن يكون اسم الصفحة قيمة أبجدية رقمية صالحة: {0} -filesHaveChangedMessage = تم تغيير الملفات التالية: -multipleEndpointsForGuiMessage = تم تعريف نقاط نهاية متعددة، سيتم استخدام الأولى فقط للواجهة الرسومية. -openingGuiMessage = جارٍ فتح الواجهة الرسومية. -listeningOnEndpointsMessage = الاستماع على {0} نقطة(نقاط) النهاية التالية [{1} خيط(خيوط)]: -specificationMessage = مواصفات -documentationMessage = توثيق -restartingServerMessage = إعادة تشغيل الخادم... -doneMessage = تم -deprecatedTitleVersionDescriptionWarningMessage = تحذير: العنوان، الإصدار والوصف في 'Enable-PodeOpenApi' مهمل. يرجى استخدام 'Add-PodeOAInfo' بدلاً من ذلك. -undefinedOpenApiReferencesMessage = مراجع OpenAPI غير معرّفة: -definitionTagMessage = تعريف {0}: -openApiGenerationDocumentErrorMessage = خطأ في مستند إنشاء OpenAPI: -infoTitleMandatoryMessage = info.title إلزامي. -infoVersionMandatoryMessage = info.version إلزامي. -missingComponentsMessage = المكون (المكونات) المفقود -openApiInfoMessage = معلومات OpenAPI: -serverLoopingMessage = تكرار الخادم كل {0} ثانية -iisShutdownMessage = (إيقاف تشغيل IIS) -terminatingMessage = إنهاء... -eolPowerShellWarningMessage = [تحذير] لم يتم اختبار Pode {0} على PowerShell {1}، حيث أنه نهاية العمر. -untestedPowerShellVersionWarningMessage = [تحذير] لم يتم اختبار Pode {0} على PowerShell {1}، حيث لم يكن متاحًا عند إصدار Pode. -'@ \ No newline at end of file +@{ + schemaValidationRequiresPowerShell610ExceptionMessage = 'يتطلب التحقق من صحة المخطط إصدار PowerShell 6.1.0 أو أحدث.' + pathOrScriptBlockRequiredExceptionMessage = 'مطلوب مسار أو ScriptBlock للحصول على قيم الوصول المخصصة.' + operationIdMustBeUniqueForArrayExceptionMessage = 'يجب أن يكون OperationID: {0} فريدًا ولا يمكن تطبيقه على مصفوفة.' + endpointNotDefinedForRedirectingExceptionMessage = "لم يتم تعريف نقطة نهاية باسم '{0}' لإعادة التوجيه." + filesHaveChangedMessage = 'تم تغيير الملفات التالية:' + iisAspnetcoreTokenMissingExceptionMessage = 'IIS ASPNETCORE_TOKEN مفقود.' + minValueGreaterThanMaxExceptionMessage = 'يجب ألا تكون القيمة الدنيا {0} أكبر من القيمة القصوى.' + noLogicPassedForRouteExceptionMessage = 'لم يتم تمرير منطق للمسار: {0}' + scriptPathDoesNotExistExceptionMessage = 'مسار البرنامج النصي غير موجود: {0}' + mutexAlreadyExistsExceptionMessage = 'يوجد بالفعل Mutex بالاسم التالي: {0}' + listeningOnEndpointsMessage = 'الاستماع على {0} نقطة(نقاط) النهاية التالية [{1} خيط(خيوط)]:' + unsupportedFunctionInServerlessContextExceptionMessage = 'الدالة {0} غير مدعومة في سياق بدون خادم.' + expectedNoJwtSignatureSuppliedExceptionMessage = 'لم يكن من المتوقع توفير توقيع JWT.' + secretAlreadyMountedExceptionMessage = "تم تثبيت سر بالاسم '{0}' بالفعل." + failedToAcquireLockExceptionMessage = 'فشل في الحصول على قفل على الكائن.' + noPathSuppliedForStaticRouteExceptionMessage = '[{0}]: لم يتم توفير مسار للمسار الثابت.' + invalidHostnameSuppliedExceptionMessage = 'اسم المضيف المقدم غير صالح: {0}' + authMethodAlreadyDefinedExceptionMessage = 'طريقة المصادقة محددة بالفعل: {0}' + csrfCookieRequiresSecretExceptionMessage = "عند استخدام ملفات تعريف الارتباط لـ CSRF، يكون السر مطلوبًا. يمكنك تقديم سر أو تعيين السر العالمي لملف تعريف الارتباط - (Set-PodeCookieSecret '' -Global)" + nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 'مطلوب ScriptBlock غير فارغ لإنشاء مسار الصفحة.' + noPropertiesMutuallyExclusiveExceptionMessage = "المعامل 'NoProperties' يتعارض مع 'Properties' و 'MinProperties' و 'MaxProperties'." + incompatiblePodeDllExceptionMessage = 'يتم تحميل إصدار غير متوافق من Pode.DLL {0}. الإصدار {1} مطلوب. افتح جلسة Powershell/pwsh جديدة وأعد المحاولة.' + accessMethodDoesNotExistExceptionMessage = 'طريقة الوصول غير موجودة: {0}.' + scheduleAlreadyDefinedExceptionMessage = '[الجدول الزمني] {0}: الجدول الزمني معرف بالفعل.' + secondsValueCannotBeZeroOrLessExceptionMessage = 'لا يمكن أن تكون قيمة الثواني 0 أو أقل لـ {0}' + pathToLoadNotFoundExceptionMessage = 'لم يتم العثور على المسار لتحميل {0}: {1}' + failedToImportModuleExceptionMessage = 'فشل في استيراد الوحدة: {0}' + endpointNotExistExceptionMessage = "نقطة النهاية مع البروتوكول '{0}' والعنوان '{1}' أو العنوان المحلي '{2}' غير موجودة." + terminatingMessage = 'إنهاء...' + noCommandsSuppliedToConvertToRoutesExceptionMessage = 'لم يتم توفير أي أوامر لتحويلها إلى طرق.' + invalidTaskTypeExceptionMessage = 'نوع المهمة غير صالح، المتوقع إما [System.Threading.Tasks.Task] أو [hashtable].' + alreadyConnectedToWebSocketExceptionMessage = "متصل بالفعل بـ WebSocket بالاسم '{0}'" + crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = 'فحص نهاية الرسالة CRLF مدعوم فقط على نقاط النهاية TCP.' + testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = "يجب تمكين 'Test-PodeOAComponentSchema' باستخدام 'Enable-PodeOpenApi -EnableSchemaValidation'" + adModuleNotInstalledExceptionMessage = 'وحدة Active Directory غير مثبتة.' + cronExpressionInvalidExceptionMessage = 'يجب أن تتكون تعبير Cron من 5 أجزاء فقط: {0}' + noSessionToSetOnResponseExceptionMessage = 'لا توجد جلسة متاحة لتعيينها على الاستجابة.' + valueOutOfRangeExceptionMessage = "القيمة '{0}' لـ {1} غير صالحة، يجب أن تكون بين {2} و {3}" + loggingMethodAlreadyDefinedExceptionMessage = 'تم تعريف طريقة التسجيل بالفعل: {0}' + noSecretForHmac256ExceptionMessage = 'لم يتم تقديم أي سر لتجزئة HMAC256.' + eolPowerShellWarningMessage = '[تحذير] لم يتم اختبار Pode {0} على PowerShell {1}، حيث أنه نهاية العمر.' + runspacePoolFailedToLoadExceptionMessage = 'فشل تحميل RunspacePool لـ {0}.' + noEventRegisteredExceptionMessage = 'لا يوجد حدث {0} مسجل: {1}' + scheduleCannotHaveNegativeLimitExceptionMessage = '[الجدول الزمني] {0}: لا يمكن أن يكون له حد سلبي.' + openApiRequestStyleInvalidForParameterExceptionMessage = 'لا يمكن أن يكون نمط الطلب OpenApi {0} لمعلمة {1}.' + openApiDocumentNotCompliantExceptionMessage = 'مستند OpenAPI غير متوافق.' + taskDoesNotExistExceptionMessage = "المهمة '{0}' غير موجودة." + scopedVariableNotFoundExceptionMessage = 'لم يتم العثور على المتغير المحدد: {0}' + sessionsRequiredForCsrfExceptionMessage = 'الجلسات مطلوبة لاستخدام CSRF إلا إذا كنت ترغب في استخدام ملفات تعريف الارتباط.' + nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 'مطلوب ScriptBlock غير فارغ لطريقة التسجيل.' + credentialsPassedWildcardForHeadersLiteralExceptionMessage = 'عند تمرير بيانات الاعتماد، سيتم اعتبار العلامة * للعنوان كـ سلسلة نصية حرفية وليس كعلامة.' + podeNotInitializedExceptionMessage = 'لم يتم تهيئة Pode.' + multipleEndpointsForGuiMessage = 'تم تعريف نقاط نهاية متعددة، سيتم استخدام الأولى فقط للواجهة الرسومية.' + operationIdMustBeUniqueExceptionMessage = 'يجب أن يكون OperationID: {0} فريدًا.' + invalidJsonJwtExceptionMessage = 'تم العثور على قيمة JSON غير صالحة في JWT' + noAlgorithmInJwtHeaderExceptionMessage = 'لم يتم توفير أي خوارزمية في رأس JWT.' + openApiVersionPropertyMandatoryExceptionMessage = 'خاصية إصدار OpenApi إلزامية.' + limitValueCannotBeZeroOrLessExceptionMessage = 'لا يمكن أن تكون القيمة الحدية 0 أو أقل لـ {0}' + timerDoesNotExistExceptionMessage = "المؤقت '{0}' غير موجود." + openApiGenerationDocumentErrorMessage = 'خطأ في مستند إنشاء OpenAPI:' + routeAlreadyContainsCustomAccessExceptionMessage = "المسار '[{0}] {1}' يحتوي بالفعل على وصول مخصص باسم '{2}'" + maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 'لا يمكن أن يكون الحد الأقصى لمؤشرات ترابط WebSocket المتزامنة أقل من الحد الأدنى {0}، ولكن تم الحصول عليه: {1}' + middlewareAlreadyDefinedExceptionMessage = '[Middleware] {0}: تم تعريف الوسيط بالفعل.' + invalidAtomCharacterExceptionMessage = 'حرف الذرة غير صالح: {0}' + cacheStorageNotFoundForRetrieveExceptionMessage = "لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة استرجاع العنصر المخزن مؤقتًا '{1}'" + headerMustHaveNameInEncodingContextExceptionMessage = 'يجب أن يحتوي الرأس على اسم عند استخدامه في سياق الترميز.' + moduleDoesNotContainFunctionExceptionMessage = 'الوحدة {0} لا تحتوي على الوظيفة {1} لتحويلها إلى مسار.' + pathToIconForGuiDoesNotExistExceptionMessage = 'المسار إلى الأيقونة للواجهة الرسومية غير موجود: {0}' + noTitleSuppliedForPageExceptionMessage = 'لم يتم توفير عنوان للصفحة {0}.' + certificateSuppliedForNonHttpsWssEndpointExceptionMessage = 'تم توفير شهادة لنقطة نهاية غير HTTPS/WSS.' + cannotLockNullObjectExceptionMessage = 'لا يمكن قفل كائن فارغ.' + showPodeGuiOnlyAvailableOnWindowsExceptionMessage = 'Show-PodeGui متاح حاليًا فقط لـ Windows PowerShell و PowerShell 7+ على Windows.' + unlockSecretButNoScriptBlockExceptionMessage = 'تم تقديم سر الفتح لنوع خزنة سرية مخصصة، ولكن لم يتم تقديم ScriptBlock الفتح.' + invalidIpAddressExceptionMessage = 'عنوان IP المقدم غير صالح: {0}' + maxDaysInvalidExceptionMessage = 'يجب أن يكون MaxDays 0 أو أكبر، ولكن تم الحصول على: {0}' + noRemoveScriptBlockForVaultExceptionMessage = "لم يتم تقديم ScriptBlock الإزالة لإزالة الأسرار من الخزنة '{0}'" + noSecretExpectedForNoSignatureExceptionMessage = 'لم يكن من المتوقع تقديم أي سر لعدم وجود توقيع.' + noCertificateFoundExceptionMessage = "لم يتم العثور على شهادة في {0}{1} لـ '{2}'" + minValueInvalidExceptionMessage = "القيمة الدنيا '{0}' لـ {1} غير صالحة، يجب أن تكون أكبر من/أو تساوي {2}" + accessRequiresAuthenticationOnRoutesExceptionMessage = 'يتطلب الوصول توفير المصادقة على الطرق.' + noSecretForHmac384ExceptionMessage = 'لم يتم تقديم أي سر لتجزئة HMAC384.' + windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = 'دعم المصادقة المحلية لـ Windows هو فقط لنظام Windows.' + definitionTagNotDefinedExceptionMessage = 'لم يتم تعريف علامة التعريف {0}.' + noComponentInDefinitionExceptionMessage = 'لا توجد مكون من نوع {0} باسم {1} متاح في تعريف {2}.' + noSmtpHandlersDefinedExceptionMessage = 'لم يتم تعريف أي معالجات SMTP.' + sessionMiddlewareAlreadyInitializedExceptionMessage = 'تم تهيئة Session Middleware بالفعل.' + reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = "ميزة المكون القابل لإعادة الاستخدام 'pathItems' غير متوفرة في OpenAPI v3.0." + wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 'العلامة * للعنوان غير متوافقة مع مفتاح AutoHeaders.' + noDataForFileUploadedExceptionMessage = "لا توجد بيانات للملف '{0}' الذي تم تحميله في الطلب." + sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = 'يمكن تكوين SSE فقط على الطلبات التي تحتوي على قيمة رأس Accept النص/تيار الأحداث.' + noSessionAvailableToSaveExceptionMessage = 'لا توجد جلسة متاحة للحفظ.' + pathParameterRequiresRequiredSwitchExceptionMessage = "إذا كانت موقع المعلمة هو 'Path'، فإن المعلمة التبديل 'Required' إلزامية." + noOpenApiUrlSuppliedExceptionMessage = 'لم يتم توفير عنوان URL OpenAPI لـ {0}.' + maximumConcurrentSchedulesInvalidExceptionMessage = 'يجب أن تكون الجداول الزمنية المتزامنة القصوى >=1 ولكن تم الحصول على: {0}' + snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = 'Snapins مدعومة فقط في Windows PowerShell.' + eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = 'تسجيل عارض الأحداث مدعوم فقط على Windows.' + parametersMutuallyExclusiveExceptionMessage = "المعاملات '{0}' و '{1}' متعارضة." + pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 'ميزة PathItems غير مدعومة في OpenAPI v3.0.x' + openApiParameterRequiresNameExceptionMessage = 'يتطلب معلمة OpenApi اسمًا محددًا.' + maximumConcurrentTasksLessThanMinimumExceptionMessage = 'لا يمكن أن يكون الحد الأقصى للمهام المتزامنة أقل من الحد الأدنى {0}، ولكن تم الحصول عليه: {1}' + noSemaphoreFoundExceptionMessage = "لم يتم العثور على Semaphore باسم '{0}'" + singleValueForIntervalExceptionMessage = 'يمكنك تقديم قيمة {0} واحدة فقط عند استخدام الفواصل الزمنية.' + jwtNotYetValidExceptionMessage = 'JWT غير صالح للاستخدام بعد.' + verbAlreadyDefinedForUrlExceptionMessage = '[الفعل] {0}: تم التعريف بالفعل لـ {1}' + noSecretNamedMountedExceptionMessage = "لم يتم تثبيت أي سر بالاسم '{0}'." + moduleOrVersionNotFoundExceptionMessage = 'لم يتم العثور على الوحدة أو الإصدار على {0}: {1}@{2}' + noScriptBlockSuppliedExceptionMessage = 'لم يتم تقديم أي ScriptBlock.' + noSecretVaultRegisteredExceptionMessage = "لم يتم تسجيل خزينة سرية بالاسم '{0}'." + nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = 'مطلوب اسم لنقطة النهاية إذا تم توفير معامل RedirectTo.' + openApiLicenseObjectRequiresNameExceptionMessage = "يتطلب كائن OpenAPI 'license' الخاصية 'name'. استخدم المعامل -LicenseName." + sourcePathDoesNotExistForStaticRouteExceptionMessage = '[{0})] {1}: مسار المصدر المقدم للمسار الثابت غير موجود: {2}' + noNameForWebSocketDisconnectExceptionMessage = 'لا يوجد اسم لفصل WebSocket من المزود.' + certificateExpiredExceptionMessage = "الشهادة '{0}' منتهية الصلاحية: {1}" + secretVaultUnlockExpiryDateInPastExceptionMessage = 'تاريخ انتهاء صلاحية فتح مخزن الأسرار في الماضي (UTC): {0}' + invalidExceptionTypeExceptionMessage = 'الاستثناء من نوع غير صالح، يجب أن يكون إما WebException أو HttpRequestException، ولكن تم الحصول عليه: {0}' + invalidSecretValueTypeExceptionMessage = 'قيمة السر من نوع غير صالح. الأنواع المتوقعة: String، SecureString، HashTable، Byte[]، أو PSCredential. ولكن تم الحصول عليه: {0}' + explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 'وضع TLS الصريح مدعوم فقط على نقاط النهاية SMTPS و TCPS.' + discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = "يمكن استخدام المعامل 'DiscriminatorMapping' فقط عندما تكون خاصية 'DiscriminatorProperty' موجودة." + scriptErrorExceptionMessage = "خطأ '{0}' في البرنامج النصي {1} {2} (السطر {3}) الحرف {4} أثناء تنفيذ {5} على الكائن {6} 'الصنف: {7} الصنف الأساسي: {8}" + cannotSupplyIntervalForQuarterExceptionMessage = 'لا يمكن توفير قيمة الفاصل الزمني لكل ربع.' + scheduleEndTimeMustBeInFutureExceptionMessage = '[الجدول الزمني] {0}: يجب أن تكون قيمة EndTime في المستقبل.' + invalidJwtSignatureSuppliedExceptionMessage = 'توقيع JWT المقدم غير صالح.' + noSetScriptBlockForVaultExceptionMessage = "لم يتم تقديم ScriptBlock الإعداد لتحديث/إنشاء الأسرار في الخزنة '{0}'" + accessMethodNotExistForMergingExceptionMessage = 'طريقة الوصول غير موجودة للدمج: {0}' + defaultAuthNotInListExceptionMessage = "المصادقة الافتراضية '{0}' غير موجودة في قائمة المصادقة المقدمة." + parameterHasNoNameExceptionMessage = "لا يحتوي المعامل على اسم. يرجى إعطاء هذا المكون اسمًا باستخدام معامل 'Name'." + methodPathAlreadyDefinedForUrlExceptionMessage = '[{0}] {1}: تم التعريف بالفعل لـ {2}' + fileWatcherAlreadyDefinedExceptionMessage = "تم تعريف مراقب الملفات باسم '{0}' بالفعل." + noServiceHandlersDefinedExceptionMessage = 'لم يتم تعريف أي معالجات خدمة.' + secretRequiredForCustomSessionStorageExceptionMessage = 'مطلوب سر عند استخدام تخزين الجلسة المخصص.' + secretManagementModuleNotInstalledExceptionMessage = 'وحدة Microsoft.PowerShell.SecretManagement غير مثبتة.' + noPathSuppliedForRouteExceptionMessage = 'لم يتم توفير مسار للطريق.' + validationOfAnyOfSchemaNotSupportedExceptionMessage = "التحقق من مخطط يتضمن 'أي منها' غير مدعوم." + iisAuthSupportIsForWindowsOnlyExceptionMessage = 'دعم مصادقة IIS هو فقط لنظام Windows.' + oauth2InnerSchemeInvalidExceptionMessage = 'يمكن أن تكون OAuth2 InnerScheme إما مصادقة Basic أو Form فقط، ولكن تم الحصول على: {0}' + noRoutePathSuppliedForPageExceptionMessage = 'لم يتم توفير مسار للصفحة {0}.' + cacheStorageNotFoundForExistsExceptionMessage = "لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة التحقق مما إذا كان العنصر المخزن مؤقتًا '{1}' موجودًا." + handlerAlreadyDefinedExceptionMessage = '[{0}] {1}: تم تعريف المعالج بالفعل.' + sessionsNotConfiguredExceptionMessage = 'لم يتم تكوين الجلسات.' + propertiesTypeObjectAssociationExceptionMessage = 'يمكن ربط خصائص النوع Object فقط بـ {0}.' + sessionsRequiredForSessionPersistentAuthExceptionMessage = 'تتطلب المصادقة المستمرة للجلسة جلسات.' + invalidPathWildcardOrDirectoryExceptionMessage = 'لا يمكن أن يكون المسار المقدم عبارة عن حرف بدل أو دليل: {0}' + accessMethodAlreadyDefinedExceptionMessage = 'طريقة الوصول معرفة بالفعل: {0}' + parametersValueOrExternalValueMandatoryExceptionMessage = "المعاملات 'Value' أو 'ExternalValue' إلزامية." + maximumConcurrentTasksInvalidExceptionMessage = 'يجب أن يكون الحد الأقصى للمهام المتزامنة >=1، ولكن تم الحصول عليه: {0}' + cannotCreatePropertyWithoutTypeExceptionMessage = 'لا يمكن إنشاء الخاصية لأنه لم يتم تعريف نوع.' + authMethodNotExistForMergingExceptionMessage = 'طريقة المصادقة غير موجودة للدمج: {0}' + maxValueInvalidExceptionMessage = "القيمة القصوى '{0}' لـ {1} غير صالحة، يجب أن تكون أقل من/أو تساوي {2}" + endpointAlreadyDefinedExceptionMessage = "تم تعريف نقطة نهاية باسم '{0}' بالفعل." + eventAlreadyRegisteredExceptionMessage = 'الحدث {0} مسجل بالفعل: {1}' + parameterNotSuppliedInRequestExceptionMessage = "لم يتم توفير معلمة باسم '{0}' في الطلب أو لا توجد بيانات متاحة." + cacheStorageNotFoundForSetExceptionMessage = "لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة تعيين العنصر المخزن مؤقتًا '{1}'" + methodPathAlreadyDefinedExceptionMessage = '[{0}] {1}: تم التعريف بالفعل.' + errorLoggingAlreadyEnabledExceptionMessage = 'تم تمكين تسجيل الأخطاء بالفعل.' + valueForUsingVariableNotFoundExceptionMessage = "لم يتم العثور على قيمة لـ '`$using:{0}'." + rapidPdfDoesNotSupportOpenApi31ExceptionMessage = 'أداة الوثائق RapidPdf لا تدعم OpenAPI 3.1' + oauth2ClientSecretRequiredExceptionMessage = 'تتطلب OAuth2 سر العميل عند عدم استخدام PKCE.' + invalidBase64JwtExceptionMessage = 'تم العثور على قيمة مشفرة بتنسيق Base64 غير صالحة في JWT' + noSessionToCalculateDataHashExceptionMessage = 'لا توجد جلسة متاحة لحساب تجزئة البيانات.' + cacheStorageNotFoundForRemoveExceptionMessage = "لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة إزالة العنصر المخزن مؤقتًا '{1}'" + csrfMiddlewareNotInitializedExceptionMessage = 'لم يتم تهيئة CSRF Middleware.' + infoTitleMandatoryMessage = 'info.title إلزامي.' + typeCanOnlyBeAssociatedWithObjectExceptionMessage = 'النوع {0} يمكن ربطه فقط بجسم.' + userFileDoesNotExistExceptionMessage = 'ملف المستخدم غير موجود: {0}' + routeParameterNeedsValidScriptblockExceptionMessage = 'المعامل Route يتطلب ScriptBlock صالح وغير فارغ.' + nextTriggerCalculationErrorExceptionMessage = 'يبدو أن هناك خطأ ما أثناء محاولة حساب تاريخ المشغل التالي: {0}' + cannotLockValueTypeExceptionMessage = 'لا يمكن قفل [ValueTypes].' + failedToCreateOpenSslCertExceptionMessage = 'فشل في إنشاء شهادة openssl: {0}' + jwtExpiredExceptionMessage = 'انتهت صلاحية JWT.' + openingGuiMessage = 'جارٍ فتح الواجهة الرسومية.' + multiTypePropertiesRequireOpenApi31ExceptionMessage = 'تتطلب خصائص الأنواع المتعددة إصدار OpenApi 3.1 أو أعلى.' + noNameForWebSocketRemoveExceptionMessage = 'لا يوجد اسم لإزالة WebSocket من المزود.' + maxSizeInvalidExceptionMessage = 'يجب أن يكون MaxSize 0 أو أكبر، ولكن تم الحصول على: {0}' + iisShutdownMessage = '(إيقاف تشغيل IIS)' + cannotUnlockValueTypeExceptionMessage = 'لا يمكن فتح [ValueTypes].' + noJwtSignatureForAlgorithmExceptionMessage = 'لم يتم توفير توقيع JWT لـ {0}.' + maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 'يجب أن يكون الحد الأقصى لمؤشرات ترابط WebSocket المتزامنة >=1، ولكن تم الحصول عليه: {0}' + acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 'رسالة الإقرار مدعومة فقط على نقاط النهاية SMTP و TCP.' + failedToConnectToUrlExceptionMessage = 'فشل الاتصال بعنوان URL: {0}' + failedToAcquireMutexOwnershipExceptionMessage = 'فشل في الحصول على ملكية Mutex. اسم Mutex: {0}' + sessionsRequiredForOAuth2WithPKCEExceptionMessage = 'تتطلب OAuth2 مع PKCE جلسات.' + failedToConnectToWebSocketExceptionMessage = 'فشل الاتصال بـ WebSocket: {0}' + unsupportedObjectExceptionMessage = 'الكائن غير مدعوم' + failedToParseAddressExceptionMessage = "فشل في تحليل '{0}' كعنوان IP/مضيف:منفذ صالح" + mustBeRunningWithAdminPrivilegesExceptionMessage = 'يجب التشغيل بامتيازات المسؤول للاستماع إلى العناوين غير المحلية.' + specificationMessage = 'مواصفات' + cacheStorageNotFoundForClearExceptionMessage = "لم يتم العثور على مخزن ذاكرة التخزين المؤقت بالاسم '{0}' عند محاولة مسح الذاكرة المؤقتة." + restartingServerMessage = 'إعادة تشغيل الخادم...' + cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = "لا يمكن توفير فترة زمنية عندما يكون المعامل 'Every' مضبوطًا على None." + unsupportedJwtAlgorithmExceptionMessage = 'خوارزمية JWT غير مدعومة حاليًا: {0}' + websocketsNotConfiguredForSignalMessagesExceptionMessage = 'لم يتم تهيئة WebSockets لإرسال رسائل الإشارة.' + invalidLogicTypeInHashtableMiddlewareExceptionMessage = 'مكون Middleware من نوع Hashtable المقدم يحتوي على نوع منطق غير صالح. كان المتوقع ScriptBlock، ولكن تم الحصول عليه: {0}' + maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 'لا يمكن أن تكون الجداول الزمنية المتزامنة القصوى أقل من الحد الأدنى {0} ولكن تم الحصول على: {1}' + failedToAcquireSemaphoreOwnershipExceptionMessage = 'فشل في الحصول على ملكية Semaphore. اسم Semaphore: {0}' + propertiesParameterWithoutNameExceptionMessage = 'لا يمكن استخدام معلمات الخصائص إذا لم يكن لدى الخاصية اسم.' + customSessionStorageMethodNotImplementedExceptionMessage = "تخزين الجلسة المخصص لا ينفذ الطريقة المطلوبة '{0}()'." + authenticationMethodDoesNotExistExceptionMessage = 'طريقة المصادقة غير موجودة: {0}' + webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = 'ميزة Webhooks غير مدعومة في OpenAPI v3.0.x' + invalidContentTypeForSchemaExceptionMessage = "'content-type' غير صالح في المخطط: {0}" + noUnlockScriptBlockForVaultExceptionMessage = "لم يتم تقديم ScriptBlock الفتح لفتح الخزنة '{0}'" + definitionTagMessage = 'تعريف {0}:' + failedToOpenRunspacePoolExceptionMessage = 'فشل في فتح RunspacePool: {0}' + verbNoLogicPassedExceptionMessage = '[الفعل] {0}: لم يتم تمرير أي منطق' + noMutexFoundExceptionMessage = "لم يتم العثور على Mutex باسم '{0}'" + documentationMessage = 'توثيق' + timerAlreadyDefinedExceptionMessage = '[المؤقت] {0}: المؤقت معرف بالفعل.' + invalidPortExceptionMessage = 'لا يمكن أن يكون المنفذ سالبًا: {0}' + viewsFolderNameAlreadyExistsExceptionMessage = 'اسم مجلد العرض موجود بالفعل: {0}' + noNameForWebSocketResetExceptionMessage = 'لا يوجد اسم لإعادة تعيين WebSocket من المزود.' + mergeDefaultAuthNotInListExceptionMessage = "المصادقة MergeDefault '{0}' غير موجودة في قائمة المصادقة المقدمة." + descriptionRequiredExceptionMessage = 'الوصف مطلوب.' + pageNameShouldBeAlphaNumericExceptionMessage = 'يجب أن يكون اسم الصفحة قيمة أبجدية رقمية صالحة: {0}' + defaultValueNotBooleanOrEnumExceptionMessage = 'القيمة الافتراضية ليست من نوع boolean وليست جزءًا من التعداد.' + openApiComponentSchemaDoesNotExistExceptionMessage = 'مخطط مكون OpenApi {0} غير موجود.' + timerParameterMustBeGreaterThanZeroExceptionMessage = '[المؤقت] {0}: {1} يجب أن يكون أكبر من 0.' + taskTimedOutExceptionMessage = 'انتهت المهلة الزمنية للمهمة بعد {0}ms.' + scheduleStartTimeAfterEndTimeExceptionMessage = "[الجدول الزمني] {0}: لا يمكن أن يكون 'StartTime' بعد 'EndTime'" + infoVersionMandatoryMessage = 'info.version إلزامي.' + cannotUnlockNullObjectExceptionMessage = 'لا يمكن فتح كائن فارغ.' + nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 'مطلوب ScriptBlock غير فارغ لخطة المصادقة المخصصة.' + validationOfOneOfSchemaNotSupportedExceptionMessage = "التحقق من مخطط يتضمن 'واحد منها' غير مدعوم." + routeParameterCannotBeNullExceptionMessage = "لا يمكن أن يكون المعامل 'Route' فارغًا." + cacheStorageAlreadyExistsExceptionMessage = "مخزن ذاكرة التخزين المؤقت بالاسم '{0}' موجود بالفعل." + loggingMethodRequiresValidScriptBlockExceptionMessage = "تتطلب طريقة الإخراج المقدمة لطريقة التسجيل '{0}' ScriptBlock صالح." + scopedVariableAlreadyDefinedExceptionMessage = 'المتغير المحدد بالفعل معرف: {0}' + oauth2RequiresAuthorizeUrlExceptionMessage = 'تتطلب OAuth2 توفير عنوان URL للتفويض.' + pathNotExistExceptionMessage = 'المسار غير موجود: {0}' + noDomainServerNameForWindowsAdAuthExceptionMessage = 'لم يتم توفير اسم خادم المجال لمصادقة Windows AD.' + suppliedDateAfterScheduleEndTimeExceptionMessage = 'التاريخ المقدم بعد وقت انتهاء الجدول الزمني في {0}' + wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 'العلامة * للطرق غير متوافقة مع مفتاح AutoMethods.' + cannotSupplyIntervalForYearExceptionMessage = 'لا يمكن توفير قيمة الفاصل الزمني لكل سنة.' + missingComponentsMessage = 'المكون (المكونات) المفقود' + invalidStrictTransportSecurityDurationExceptionMessage = 'تم توفير مدة Strict-Transport-Security غير صالحة: {0}. يجب أن تكون أكبر من 0.' + noSecretForHmac512ExceptionMessage = 'لم يتم تقديم أي سر لتجزئة HMAC512.' + daysInMonthExceededExceptionMessage = 'يحتوي {0} على {1} أيام فقط، ولكن تم توفير {2}.' + nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 'مطلوب ScriptBlock غير فارغ لطريقة إخراج السجل المخصصة.' + encodingAttributeOnlyAppliesToMultipartExceptionMessage = 'ينطبق سمة الترميز فقط على نصوص الطلبات multipart و application/x-www-form-urlencoded.' + suppliedDateBeforeScheduleStartTimeExceptionMessage = 'التاريخ المقدم قبل وقت بدء الجدول الزمني في {0}' + unlockSecretRequiredExceptionMessage = "خاصية 'UnlockSecret' مطلوبة عند استخدام Microsoft.PowerShell.SecretStore" + noLogicPassedForMethodRouteExceptionMessage = '[{0}] {1}: لم يتم تمرير منطق.' + bodyParserAlreadyDefinedForContentTypeExceptionMessage = 'تم تعريف محلل الجسم لنوع المحتوى {0} بالفعل.' + invalidJwtSuppliedExceptionMessage = 'JWT المقدم غير صالح.' + sessionsRequiredForFlashMessagesExceptionMessage = 'الجلسات مطلوبة لاستخدام رسائل الفلاش.' + outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = 'طريقة الإخراج المقدمة لتسجيل الطلبات تتطلب ScriptBlock صالح.' + semaphoreAlreadyExistsExceptionMessage = 'يوجد بالفعل Semaphore بالاسم التالي: {0}' + invalidJwtHeaderAlgorithmSuppliedExceptionMessage = 'خوارزمية رأس JWT المقدمة غير صالحة.' + oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = "مزود OAuth2 لا يدعم نوع المنحة 'password' المطلوبة لاستخدام InnerScheme." + invalidAliasFoundExceptionMessage = 'تم العثور على اسم مستعار غير صالح {0}: {1}' + scheduleDoesNotExistExceptionMessage = "الجدول الزمني '{0}' غير موجود." + accessMethodNotExistExceptionMessage = 'طريقة الوصول غير موجودة: {0}' + oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = "مزود OAuth2 لا يدعم نوع الاستجابة 'code'." + untestedPowerShellVersionWarningMessage = '[تحذير] لم يتم اختبار Pode {0} على PowerShell {1}، حيث لم يكن متاحًا عند إصدار Pode.' + secretVaultAlreadyRegisteredAutoImportExceptionMessage = "تم تسجيل خزنة سرية باسم '{0}' بالفعل أثناء استيراد الخزن السرية تلقائيًا." + schemeRequiresValidScriptBlockExceptionMessage = "تتطلب الخطة المقدمة لمحقق المصادقة '{0}' ScriptBlock صالح." + serverLoopingMessage = 'تكرار الخادم كل {0} ثانية' + certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 'بصمات الإبهام/الاسم للشهادة مدعومة فقط على Windows.' + sseConnectionNameRequiredExceptionMessage = "مطلوب اسم اتصال SSE، إما من -Name أو `$WebEvent.Sse.Name" + invalidMiddlewareTypeExceptionMessage = 'أحد مكونات Middleware المقدمة من نوع غير صالح. كان المتوقع إما ScriptBlock أو Hashtable، ولكن تم الحصول عليه: {0}' + noSecretForJwtSignatureExceptionMessage = 'لم يتم تقديم أي سر لتوقيع JWT.' + modulePathDoesNotExistExceptionMessage = 'مسار الوحدة غير موجود: {0}' + taskAlreadyDefinedExceptionMessage = '[المهمة] {0}: المهمة معرفة بالفعل.' + verbAlreadyDefinedExceptionMessage = '[الفعل] {0}: تم التعريف بالفعل' + clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 'الشهادات العميلة مدعومة فقط على نقاط النهاية HTTPS.' + endpointNameNotExistExceptionMessage = "نقطة النهاية بالاسم '{0}' غير موجودة." + middlewareNoLogicSuppliedExceptionMessage = '[Middleware]: لم يتم توفير أي منطق في ScriptBlock.' + scriptBlockRequiredForMergingUsersExceptionMessage = 'مطلوب ScriptBlock لدمج عدة مستخدمين مصادق عليهم في كائن واحد عندما تكون Valid هي All.' + secretVaultAlreadyRegisteredExceptionMessage = "تم تسجيل مخزن الأسرار بالاسم '{0}' بالفعل{1}." + deprecatedTitleVersionDescriptionWarningMessage = "تحذير: العنوان، الإصدار والوصف في 'Enable-PodeOpenApi' مهمل. يرجى استخدام 'Add-PodeOAInfo' بدلاً من ذلك." + undefinedOpenApiReferencesMessage = 'مراجع OpenAPI غير معرّفة:' + doneMessage = 'تم' + swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = 'هذا الإصدار من Swagger-Editor لا يدعم OpenAPI 3.1' + durationMustBeZeroOrGreaterExceptionMessage = 'يجب أن تكون المدة 0 أو أكبر، ولكن تم الحصول عليها: {0}s' + viewsPathDoesNotExistExceptionMessage = 'مسار العرض غير موجود: {0}' + discriminatorIncompatibleWithAllOfExceptionMessage = "المعامل 'Discriminator' غير متوافق مع 'allOf'." + noNameForWebSocketSendMessageExceptionMessage = 'لا يوجد اسم لإرسال رسالة إلى WebSocket المزود.' + hashtableMiddlewareNoLogicExceptionMessage = 'مكون Middleware من نوع Hashtable المقدم لا يحتوي على منطق معرف.' + openApiInfoMessage = 'معلومات OpenAPI:' + invalidSchemeForAuthValidatorExceptionMessage = "تتطلب الخطة '{0}' المقدمة لمحقق المصادقة '{1}' ScriptBlock صالح." + sseFailedToBroadcastExceptionMessage = 'فشل بث SSE بسبب مستوى البث SSE المحدد لـ {0}: {1}' + adModuleWindowsOnlyExceptionMessage = 'وحدة Active Directory متاحة فقط على نظام Windows.' + requestLoggingAlreadyEnabledExceptionMessage = 'تم تمكين تسجيل الطلبات بالفعل.' + invalidAccessControlMaxAgeDurationExceptionMessage = 'مدة Access-Control-Max-Age غير صالحة المقدمة: {0}. يجب أن تكون أكبر من 0.' +} + diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index a94c6c673..7e23337ee 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -1,284 +1,285 @@ -ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyExceptionMessage = Active Directory-Modul nur unter Windows verfügbar. -adModuleNotInstalledExceptionMessage = Das Active Directory-Modul ist nicht installiert. -secretManagementModuleNotInstalledExceptionMessage = Das Modul Microsoft.PowerShell.SecretManagement ist nicht installiert. -secretVaultAlreadyRegisteredAutoImportExceptionMessage = Ein Geheimtresor mit dem Namen '{0}' wurde bereits beim automatischen Importieren von Geheimtresoren registriert. -failedToOpenRunspacePoolExceptionMessage = Fehler beim Öffnen des Runspace-Pools: {0} -cronExpressionInvalidExceptionMessage = Die Cron-Ausdruck sollte nur aus 5 Teilen bestehen: {0} -invalidAliasFoundExceptionMessage = Ungültiges {0}-Alias gefunden: {1} -invalidAtomCharacterExceptionMessage = Ungültiges Atomzeichen: {0} -minValueGreaterThanMaxExceptionMessage = Der Mindestwert für {0} darf nicht größer als der Maximalwert sein. -minValueInvalidExceptionMessage = Der Mindestwert '{0}' für {1} ist ungültig, sollte größer oder gleich {2} sein -maxValueInvalidExceptionMessage = Der Maximalwert '{0}' für {1} ist ungültig, sollte kleiner oder gleich {2} sein -valueOutOfRangeExceptionMessage = Wert '{0}' für {1} ist ungültig, sollte zwischen {2} und {3} liegen -daysInMonthExceededExceptionMessage = {0} hat nur {1} Tage, aber {2} wurden angegeben -nextTriggerCalculationErrorExceptionMessage = Es scheint, als ob beim Berechnen des nächsten Trigger-Datums und der nächsten Triggerzeit etwas schief gelaufen wäre: {0} -incompatiblePodeDllExceptionMessage = Eine vorhandene inkompatible Pode.DLL-Version {0} ist geladen. Version {1} wird benötigt. Öffnen Sie eine neue PowerShell/pwsh-Sitzung und versuchen Sie es erneut. -endpointNotExistExceptionMessage = Der Endpunkt mit dem Protokoll '{0}' und der Adresse '{1}' oder der lokalen Adresse '{2}' existiert nicht -endpointNameNotExistExceptionMessage = Der Endpunkt mit dem Namen '{0}' existiert nicht -failedToConnectToUrlExceptionMessage = Verbindung mit der URL fehlgeschlagen: {0} -failedToParseAddressExceptionMessage = Konnte '{0}' nicht als gültige IP/Host:Port-Adresse analysieren -invalidIpAddressExceptionMessage = Die angegebene IP-Adresse ist ungültig: {0} -invalidPortExceptionMessage = Der Port kann nicht negativ sein: {0} -pathNotExistExceptionMessage = Pfad existiert nicht: {0} -noSecretForHmac256ExceptionMessage = Es wurde kein Geheimnis für den HMAC256-Hash angegeben. -noSecretForHmac384ExceptionMessage = Es wurde kein Geheimnis für den HMAC384-Hash angegeben. -noSecretForHmac512ExceptionMessage = Es wurde kein Geheimnis für den HMAC512-Hash angegeben. -noSecretForJwtSignatureExceptionMessage = Es wurde kein Geheimnis für die JWT-Signatur angegeben. -noSecretExpectedForNoSignatureExceptionMessage = Es wurde erwartet, dass kein Geheimnis für keine Signatur angegeben wird. -unsupportedJwtAlgorithmExceptionMessage = Der JWT-Algorithmus wird derzeit nicht unterstützt: {0} -invalidBase64JwtExceptionMessage = Ungültiger Base64-codierter Wert in JWT gefunden -invalidJsonJwtExceptionMessage = Ungültiger JSON-Wert in JWT gefunden -unsupportedFunctionInServerlessContextExceptionMessage = Die Funktion {0} wird in einem serverlosen Kontext nicht unterstützt. -invalidPathWildcardOrDirectoryExceptionMessage = Der angegebene Pfad darf kein Platzhalter oder Verzeichnis sein: {0} -invalidExceptionTypeExceptionMessage = Die Ausnahme hat einen ungültigen Typ. Er sollte entweder WebException oder HttpRequestException sein, aber es wurde {0} erhalten -pathToLoadNotFoundExceptionMessage = Pfad zum Laden von {0} nicht gefunden: {1} -singleValueForIntervalExceptionMessage = Sie können nur einen einzelnen {0}-Wert angeben, wenn Sie Intervalle verwenden. -scriptErrorExceptionMessage = Fehler '{0}' im Skript {1} {2} (Zeile {3}) Zeichen {4} beim Ausführen von {5} auf {6} Objekt '{7}' Klasse: {8} Basisklasse: {9} -noScriptBlockSuppliedExceptionMessage = Kein Skriptblock angegeben. -iisAspnetcoreTokenMissingExceptionMessage = Das IIS-ASPNETCORE_TOKEN fehlt. -propertiesParameterWithoutNameExceptionMessage = Die Eigenschaftsparameter können nicht verwendet werden, wenn die Eigenschaft keinen Namen hat. -multiTypePropertiesRequireOpenApi31ExceptionMessage = Mehrfachtyp-Eigenschaften erfordern OpenApi-Version 3.1 oder höher. -openApiVersionPropertyMandatoryExceptionMessage = Die Eigenschaft OpenApi-Version ist obligatorisch. -webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = Das Webhooks-Feature wird in OpenAPI v3.0.x nicht unterstützt. -authenticationMethodDoesNotExistExceptionMessage = Authentifizierungsmethode existiert nicht: {0} -unsupportedObjectExceptionMessage = Nicht unterstütztes Objekt -validationOfAnyOfSchemaNotSupportedExceptionMessage = Die Validierung eines Schemas, das 'anyof' enthält, wird nicht unterstützt. -validationOfOneOfSchemaNotSupportedExceptionMessage = Die Validierung eines Schemas, das 'oneof' enthält, wird nicht unterstützt. -cannotCreatePropertyWithoutTypeExceptionMessage = Die Eigenschaft kann nicht erstellt werden, weil kein Typ definiert ist. -headerMustHaveNameInEncodingContextExceptionMessage = Ein Header muss einen Namen haben, wenn er im Codierungskontext verwendet wird. -descriptionRequiredExceptionMessage = Eine Beschreibung ist erforderlich. -openApiDocumentNotCompliantExceptionMessage = Das OpenAPI-Dokument ist nicht konform. -noComponentInDefinitionExceptionMessage = Es ist keine Komponente des Typs {0} mit dem Namen {1} in der Definition {2} verfügbar. -methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: Bereits definiert. -methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: Bereits für {2} definiert. -invalidMiddlewareTypeExceptionMessage = Eines der angegebenen Middleware-Objekte ist ein ungültiger Typ. Erwartet wurde entweder ein ScriptBlock oder ein Hashtable, aber erhalten wurde: {0}. -hashtableMiddlewareNoLogicExceptionMessage = Eine angegebene Hashtable-Middleware enthält keine definierte Logik. -invalidLogicTypeInHashtableMiddlewareExceptionMessage = Eine angegebene Hashtable-Middleware enthält einen ungültigen Logik-Typ. Erwartet wurde ein ScriptBlock, aber erhalten wurde: {0}. -scopedVariableAlreadyDefinedExceptionMessage = Die Bereichsvariable ist bereits definiert: {0}. -valueForUsingVariableNotFoundExceptionMessage = Der Wert für '`$using:{0}' konnte nicht gefunden werden. -unlockSecretRequiredExceptionMessage = Eine 'UnlockSecret'-Eigenschaft ist erforderlich, wenn Microsoft.PowerShell.SecretStore verwendet wird. -unlockSecretButNoScriptBlockExceptionMessage = Unlock secret für benutzerdefinierten Secret Vault-Typ angegeben, aber kein Unlock ScriptBlock bereitgestellt. -noUnlockScriptBlockForVaultExceptionMessage = Kein Unlock ScriptBlock für das Entsperren des Tresors '{0}' bereitgestellt. -noSetScriptBlockForVaultExceptionMessage = Kein Set ScriptBlock für das Aktualisieren/Erstellen von Geheimnissen im Tresor '{0}' bereitgestellt. -noRemoveScriptBlockForVaultExceptionMessage = Kein Remove ScriptBlock für das Entfernen von Geheimnissen im Tresor '{0}' bereitgestellt. -invalidSecretValueTypeExceptionMessage = Der Geheimniswert hat einen ungültigen Typ. Erwartete Typen: String, SecureString, HashTable, Byte[] oder PSCredential. Aber erhalten wurde: {0}. -limitValueCannotBeZeroOrLessExceptionMessage = Der Grenzwert darf für {0} nicht 0 oder weniger sein. -secondsValueCannotBeZeroOrLessExceptionMessage = Der Sekundenwert darf für {0} nicht 0 oder weniger sein. -failedToCreateOpenSslCertExceptionMessage = Erstellung des OpenSSL-Zertifikats fehlgeschlagen: {0}. -certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Zertifikat-Thumbprints/Name werden nur unter Windows unterstützt. -noCertificateFoundExceptionMessage = Es wurde kein Zertifikat in {0}\{1} für '{2}' gefunden. -runspacePoolFailedToLoadExceptionMessage = {0} RunspacePool konnte nicht geladen werden. -noServiceHandlersDefinedExceptionMessage = Es wurden keine Service-Handler definiert. -noSessionToSetOnResponseExceptionMessage = Keine Sitzung verfügbar, die auf die Antwort gesetzt werden kann. -noSessionToCalculateDataHashExceptionMessage = Keine Sitzung verfügbar, um den Datenhash zu berechnen. -moduleOrVersionNotFoundExceptionMessage = Modul oder Version nicht gefunden auf {0}: {1}@{2} -noSmtpHandlersDefinedExceptionMessage = Es wurden keine SMTP-Handler definiert. -taskTimedOutExceptionMessage = Aufgabe ist nach {0}ms abgelaufen. -verbAlreadyDefinedExceptionMessage = [Verb] {0}: Bereits definiert. -verbAlreadyDefinedForUrlExceptionMessage = [Verb] {0}: Bereits für {1} definiert. -pathOrScriptBlockRequiredExceptionMessage = Ein Pfad oder ScriptBlock ist erforderlich, um die benutzerdefinierten Zugriffswerte zu beziehen. -accessMethodAlreadyDefinedExceptionMessage = Zugriffsmethode bereits definiert: {0}. -accessMethodNotExistForMergingExceptionMessage = Zugriffsmethode zum Zusammenführen nicht vorhanden: {0}. -routeAlreadyContainsCustomAccessExceptionMessage = Die Route '[{0}] {1}' enthält bereits einen benutzerdefinierten Zugriff mit dem Namen '{2}'. -accessMethodNotExistExceptionMessage = Zugriffsmethode nicht vorhanden: {0}. -pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = Das PathItems-Feature wird in OpenAPI v3.0.x nicht unterstützt. -nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = Ein nicht leerer ScriptBlock ist für das benutzerdefinierte Authentifizierungsschema erforderlich. -oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme kann nur entweder Basic oder Form-Authentifizierung sein, aber erhalten: {0} -sessionsRequiredForOAuth2WithPKCEExceptionMessage = Sitzungen sind erforderlich, um OAuth2 mit PKCE zu verwenden. -oauth2ClientSecretRequiredExceptionMessage = OAuth2 erfordert ein Client Secret, wenn PKCE nicht verwendet wird. -authMethodAlreadyDefinedExceptionMessage = Authentifizierungsmethode bereits definiert: {0} -invalidSchemeForAuthValidatorExceptionMessage = Das bereitgestellte '{0}'-Schema für den Authentifizierungsvalidator '{1}' erfordert einen gültigen ScriptBlock. -sessionsRequiredForSessionPersistentAuthExceptionMessage = Sitzungen sind erforderlich, um die sitzungsbeständige Authentifizierung zu verwenden. -oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 erfordert die Angabe einer Autorisierungs-URL. -authMethodNotExistForMergingExceptionMessage = Die Authentifizierungsmethode existiert nicht zum Zusammenführen: {0} -mergeDefaultAuthNotInListExceptionMessage = Die MergeDefault-Authentifizierung '{0}' befindet sich nicht in der angegebenen Authentifizierungsliste. -defaultAuthNotInListExceptionMessage = Die Standardauthentifizierung '{0}' befindet sich nicht in der angegebenen Authentifizierungsliste. -scriptBlockRequiredForMergingUsersExceptionMessage = Ein ScriptBlock ist erforderlich, um mehrere authentifizierte Benutzer zu einem Objekt zusammenzuführen, wenn Valid All ist. -noDomainServerNameForWindowsAdAuthExceptionMessage = Es wurde kein Domänenservername für die Windows-AD-Authentifizierung angegeben. -sessionsNotConfiguredExceptionMessage = Sitzungen wurden nicht konfiguriert. -windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Die Unterstützung der lokalen Windows-Authentifizierung gilt nur für Windows. -iisAuthSupportIsForWindowsOnlyExceptionMessage = Die IIS-Authentifizierungsunterstützung gilt nur für Windows. -noAlgorithmInJwtHeaderExceptionMessage = Kein Algorithmus im JWT-Header angegeben. -invalidJwtSuppliedExceptionMessage = Ungültiger JWT angegeben. -invalidJwtHeaderAlgorithmSuppliedExceptionMessage = Ungültiger JWT-Header-Algorithmus angegeben. -noJwtSignatureForAlgorithmExceptionMessage = Keine JWT-Signatur für {0} angegeben. -expectedNoJwtSignatureSuppliedExceptionMessage = Es wurde keine JWT-Signatur erwartet. -invalidJwtSignatureSuppliedExceptionMessage = Ungültige JWT-Signatur angegeben. -jwtExpiredExceptionMessage = Der JWT ist abgelaufen. -jwtNotYetValidExceptionMessage = Der JWT ist noch nicht gültig. -snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Snapins werden nur in Windows PowerShell unterstützt. -userFileDoesNotExistExceptionMessage = Die Benutzerdaten-Datei existiert nicht: {0} -schemeRequiresValidScriptBlockExceptionMessage = Das bereitgestellte Schema für den Authentifizierungsvalidator '{0}' erfordert einen gültigen ScriptBlock. -oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = Der OAuth2-Anbieter unterstützt den 'code'-Antworttyp nicht. -oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = Der OAuth2-Anbieter unterstützt den für die Verwendung eines InnerScheme erforderlichen 'password'-Grant-Typ nicht. -eventAlreadyRegisteredExceptionMessage = Ereignis {0} bereits registriert: {1} -noEventRegisteredExceptionMessage = Kein Ereignis {0} registriert: {1} -sessionsRequiredForFlashMessagesExceptionMessage = Sitzungen sind erforderlich, um Flash-Nachrichten zu verwenden. -eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = Das Protokollieren im Ereignisanzeige wird nur auf Windows unterstützt. -nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = Ein nicht leerer ScriptBlock ist für die benutzerdefinierte Protokollierungsmethode erforderlich. -requestLoggingAlreadyEnabledExceptionMessage = Die Anforderungsprotokollierung wurde bereits aktiviert. -outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = Die angegebene Ausgabemethode für die Anforderungsprotokollierung erfordert einen gültigen ScriptBlock. -errorLoggingAlreadyEnabledExceptionMessage = Die Fehlerprotokollierung wurde bereits aktiviert. -nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = Ein nicht leerer ScriptBlock ist für die Protokollierungsmethode erforderlich. -csrfMiddlewareNotInitializedExceptionMessage = CSRF Middleware wurde nicht initialisiert. -sessionsRequiredForCsrfExceptionMessage = Sitzungen sind erforderlich, um CSRF zu verwenden, es sei denn, Sie möchten Cookies verwenden. -middlewareNoLogicSuppliedExceptionMessage = [Middleware]: Kein Logik-ScriptBlock bereitgestellt. -parameterHasNoNameExceptionMessage = Der Parameter hat keinen Namen. Bitte geben Sie dieser Komponente einen Namen mit dem 'Name'-Parameter. -reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = Die wiederverwendbare Komponente 'pathItems' ist in OpenAPI v3.0 nicht verfügbar. -noPropertiesMutuallyExclusiveExceptionMessage = Der Parameter 'NoProperties' schließt 'Properties', 'MinProperties' und 'MaxProperties' gegenseitig aus. -discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = Der Parameter 'DiscriminatorMapping' kann nur verwendet werden, wenn 'DiscriminatorProperty' vorhanden ist. -discriminatorIncompatibleWithAllOfExceptionMessage = Der Parameter 'Discriminator' ist nicht mit 'allOf' kompatibel. -typeCanOnlyBeAssociatedWithObjectExceptionMessage = Der Typ {0} kann nur einem Objekt zugeordnet werden. -showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui ist derzeit nur für Windows PowerShell und PowerShell 7+ unter Windows verfügbar. -nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = Ein Name ist für den Endpunkt erforderlich, wenn der RedirectTo-Parameter angegeben ist. -clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = Clientzertifikate werden nur auf HTTPS-Endpunkten unterstützt. -explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = Der explizite TLS-Modus wird nur auf SMTPS- und TCPS-Endpunkten unterstützt. -acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = Die Bestätigungsnachricht wird nur auf SMTP- und TCP-Endpunkten unterstützt. -crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = Die CRLF-Nachrichtenendprüfung wird nur auf TCP-Endpunkten unterstützt. -mustBeRunningWithAdminPrivilegesExceptionMessage = Muss mit Administratorrechten ausgeführt werden, um auf Nicht-Localhost-Adressen zu lauschen. -certificateSuppliedForNonHttpsWssEndpointExceptionMessage = Zertifikat für Nicht-HTTPS/WSS-Endpunkt bereitgestellt. -websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSockets wurden nicht konfiguriert, um Signalnachrichten zu senden. -noPathSuppliedForRouteExceptionMessage = Kein Pfad für die Route bereitgestellt. -accessRequiresAuthenticationOnRoutesExceptionMessage = Der Zugriff erfordert eine Authentifizierung auf den Routen. -accessMethodDoesNotExistExceptionMessage = Zugriffsmethode existiert nicht: {0}. -routeParameterNeedsValidScriptblockExceptionMessage = Der Route-Parameter benötigt einen gültigen, nicht leeren ScriptBlock. -noCommandsSuppliedToConvertToRoutesExceptionMessage = Keine Befehle zur Umwandlung in Routen bereitgestellt. -nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Ein nicht leerer ScriptBlock ist erforderlich, um eine Seitenroute zu erstellen. -sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE kann nur auf Anfragen mit einem Accept-Header-Wert von text/event-stream konfiguriert werden. -sseConnectionNameRequiredExceptionMessage = Ein SSE-Verbindungsname ist erforderlich, entweder von -Name oder ``$WebEvent.Sse.Namee -sseFailedToBroadcastExceptionMessage = SSE konnte aufgrund des definierten SSE-Broadcast-Levels für {0}: {1} nicht übertragen werden. -podeNotInitializedExceptionMessage = Pode wurde nicht initialisiert. -invalidTaskTypeExceptionMessage = Aufgabentyp ist ungültig, erwartet entweder [System.Threading.Tasks.Task] oder [hashtable] -cannotLockValueTypeExceptionMessage = Kann [ValueTypes] nicht sperren. -cannotLockNullObjectExceptionMessage = Kann ein null-Objekt nicht sperren. -failedToAcquireLockExceptionMessage = Sperre des Objekts konnte nicht erworben werden. -cannotUnlockValueTypeExceptionMessage = Kann [ValueTypes] nicht entsperren. -cannotUnlockNullObjectExceptionMessage = Kann ein null-Objekt nicht entsperren. -sessionMiddlewareAlreadyInitializedExceptionMessage = Session Middleware wurde bereits initialisiert. -customSessionStorageMethodNotImplementedExceptionMessage = Der benutzerdefinierte Sitzungspeicher implementiert die erforderliche Methode '{0}()' nicht. -secretRequiredForCustomSessionStorageExceptionMessage = Ein Geheimnis ist erforderlich, wenn benutzerdefinierter Sitzungspeicher verwendet wird. -noSessionAvailableToSaveExceptionMessage = Keine Sitzung verfügbar zum Speichern. -cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Ein Intervall kann nicht angegeben werden, wenn der Parameter 'Every' auf None gesetzt ist. -cannotSupplyIntervalForQuarterExceptionMessage = Ein Intervallwert kann nicht für jedes Quartal angegeben werden. -cannotSupplyIntervalForYearExceptionMessage = Ein Intervallwert kann nicht für jedes Jahr angegeben werden. -secretVaultAlreadyRegisteredExceptionMessage = Ein Geheimnis-Tresor mit dem Namen '{0}' wurde bereits registriert{1}. -secretVaultUnlockExpiryDateInPastExceptionMessage = Das Ablaufdatum zum Entsperren des Geheimnis-Tresors liegt in der Vergangenheit (UTC): {0} -secretAlreadyMountedExceptionMessage = Ein Geheimnis mit dem Namen '{0}' wurde bereits eingebunden. -credentialsPassedWildcardForHeadersLiteralExceptionMessage = Wenn Anmeldeinformationen übergeben werden, wird das *-Wildcard für Header als Literalzeichenfolge und nicht als Platzhalter verwendet. -wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = Das *-Wildcard für Header ist nicht mit dem AutoHeaders-Schalter kompatibel. -wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = Das *-Wildcard für Methoden ist nicht mit dem AutoMethods-Schalter kompatibel. -invalidAccessControlMaxAgeDurationExceptionMessage = Ungültige Access-Control-Max-Age-Dauer angegeben: {0}. Sollte größer als 0 sein. -noNameForWebSocketDisconnectExceptionMessage = Kein Name für die Trennung vom WebSocket angegeben. -noNameForWebSocketRemoveExceptionMessage = Kein Name für das Entfernen des WebSocket angegeben. -noNameForWebSocketSendMessageExceptionMessage = Kein Name für das Senden einer Nachricht an den WebSocket angegeben. -noSecretNamedMountedExceptionMessage = Kein Geheimnis mit dem Namen '{0}' wurde eingebunden. -noNameForWebSocketResetExceptionMessage = Kein Name für das Zurücksetzen des WebSocket angegeben. -schemaValidationRequiresPowerShell610ExceptionMessage = Die Schema-Validierung erfordert PowerShell Version 6.1.0 oder höher. -routeParameterCannotBeNullExceptionMessage = Der Parameter 'Route' darf nicht null sein. -encodingAttributeOnlyAppliesToMultipartExceptionMessage = Das Encoding-Attribut gilt nur für multipart und application/x-www-form-urlencoded Anfragekörper. -testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema' muss mit 'Enable-PodeOpenApi -EnableSchemaValidation' aktiviert werden. -openApiComponentSchemaDoesNotExistExceptionMessage = Das OpenApi-Komponentenschema {0} existiert nicht. -openApiParameterRequiresNameExceptionMessage = Der OpenApi-Parameter erfordert einen angegebenen Namen. -openApiLicenseObjectRequiresNameExceptionMessage = Das OpenAPI-Objekt 'license' erfordert die Eigenschaft 'name'. Verwenden Sie den Parameter -LicenseName. -parametersValueOrExternalValueMandatoryExceptionMessage = Die Parameter 'Value' oder 'ExternalValue' sind obligatorisch. -parametersMutuallyExclusiveExceptionMessage = Die Parameter '{0}' und '{1}' schließen sich gegenseitig aus. -maximumConcurrentWebSocketThreadsInvalidExceptionMessage = Die maximale Anzahl gleichzeitiger WebSocket-Threads muss >=1 sein, aber erhalten: {0} -maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = Die maximale Anzahl gleichzeitiger WebSocket-Threads darf nicht kleiner als das Minimum von {0} sein, aber erhalten: {1} -alreadyConnectedToWebSocketExceptionMessage = Bereits mit dem WebSocket mit dem Namen '{0}' verbunden -failedToConnectToWebSocketExceptionMessage = Verbindung zum WebSocket fehlgeschlagen: {0} -verbNoLogicPassedExceptionMessage = [Verb] {0}: Keine Logik übergeben -scriptPathDoesNotExistExceptionMessage = Der Skriptpfad existiert nicht: {0} -failedToImportModuleExceptionMessage = Modulimport fehlgeschlagen: {0} -modulePathDoesNotExistExceptionMessage = Der Modulpfad existiert nicht: {0} -defaultValueNotBooleanOrEnumExceptionMessage = Der Standardwert ist kein Boolean und gehört nicht zum Enum. -propertiesTypeObjectAssociationExceptionMessage = Nur Eigenschaften vom Typ Object können mit {0} verknüpft werden. -invalidContentTypeForSchemaExceptionMessage = Ungültiger 'content-type' im Schema gefunden: {0} -openApiRequestStyleInvalidForParameterExceptionMessage = Der OpenApi-Anfragestil kann für einen {1}-Parameter nicht {0} sein. -pathParameterRequiresRequiredSwitchExceptionMessage = Wenn der Parameterstandort 'Path' ist, ist der Schalterparameter 'Required' erforderlich. -operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0} muss eindeutig sein und kann nicht auf ein Array angewendet werden. -operationIdMustBeUniqueExceptionMessage = OperationID: {0} muss eindeutig sein. -noOpenApiUrlSuppliedExceptionMessage = Keine OpenAPI-URL für {0} angegeben. -noTitleSuppliedForPageExceptionMessage = Kein Titel für die Seite {0} angegeben. -noRoutePathSuppliedForPageExceptionMessage = Kein Routenpfad für die Seite {0} angegeben. -swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = Diese Version des Swagger-Editors unterstützt OpenAPI 3.1 nicht. -rapidPdfDoesNotSupportOpenApi31ExceptionMessage = Das Dokumentationstool RapidPdf unterstützt OpenAPI 3.1 nicht. -definitionTagNotDefinedExceptionMessage = Definitionstag {0} ist nicht definiert. -scopedVariableNotFoundExceptionMessage = Bereichsvariable nicht gefunden: {0} -noSecretVaultRegisteredExceptionMessage = Kein Geheimnistresor mit dem Namen '{0}' registriert. -invalidStrictTransportSecurityDurationExceptionMessage = Ungültige Strict-Transport-Security-Dauer angegeben: {0}. Sie sollte größer als 0 sein. -durationMustBeZeroOrGreaterExceptionMessage = Die Dauer muss 0 oder größer sein, aber erhalten: {0}s -taskAlreadyDefinedExceptionMessage = [Aufgabe] {0}: Aufgabe bereits definiert. -maximumConcurrentTasksInvalidExceptionMessage = Die maximale Anzahl gleichzeitiger Aufgaben muss >=1 sein, aber erhalten: {0} -maximumConcurrentTasksLessThanMinimumExceptionMessage = Die maximale Anzahl gleichzeitiger Aufgaben darf nicht kleiner als das Minimum von {0} sein, aber erhalten: {1} -taskDoesNotExistExceptionMessage = Aufgabe '{0}' existiert nicht. -cacheStorageNotFoundForRetrieveExceptionMessage = Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde, das zwischengespeicherte Element '{1}' abzurufen. -cacheStorageNotFoundForSetExceptionMessage = Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde, das zwischengespeicherte Element '{1}' zu setzen. -cacheStorageNotFoundForExistsExceptionMessage = Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde zu überprüfen, ob das zwischengespeicherte Element '{1}' existiert. -cacheStorageNotFoundForRemoveExceptionMessage = Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde, das zwischengespeicherte Element '{1}' zu entfernen. -cacheStorageNotFoundForClearExceptionMessage = Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde, den Cache zu leeren. -cacheStorageAlreadyExistsExceptionMessage = Ein Cache-Speicher mit dem Namen '{0}' existiert bereits. -pathToIconForGuiDoesNotExistExceptionMessage = Der Pfad zum Symbol für die GUI existiert nicht: {0} -invalidHostnameSuppliedExceptionMessage = Der angegebene Hostname ist ungültig: {0} -endpointAlreadyDefinedExceptionMessage = Ein Endpunkt mit dem Namen '{0}' wurde bereits definiert. -certificateExpiredExceptionMessage = Das Zertifikat '{0}' ist abgelaufen: {1} -endpointNotDefinedForRedirectingExceptionMessage = Ein Endpunkt mit dem Namen '{0}' wurde nicht für die Weiterleitung definiert. -fileWatcherAlreadyDefinedExceptionMessage = Ein Dateiwächter mit dem Namen '{0}' wurde bereits definiert. -handlerAlreadyDefinedExceptionMessage = [{0}] {1}: Handler bereits definiert. -maxDaysInvalidExceptionMessage = MaxDays muss 0 oder größer sein, aber erhalten: {0} -maxSizeInvalidExceptionMessage = MaxSize muss 0 oder größer sein, aber erhalten: {0} -loggingMethodAlreadyDefinedExceptionMessage = Logging-Methode bereits definiert: {0} -loggingMethodRequiresValidScriptBlockExceptionMessage = Die angegebene Ausgabemethode für die Logging-Methode '{0}' erfordert einen gültigen ScriptBlock. -csrfCookieRequiresSecretExceptionMessage = Beim Verwenden von Cookies für CSRF ist ein Geheimnis erforderlich. Sie können ein Geheimnis angeben oder das globale Cookie-Geheimnis festlegen - (Set-PodeCookieSecret '' -Global) -bodyParserAlreadyDefinedForContentTypeExceptionMessage = Für den Inhaltstyp {0} ist bereits ein Body-Parser definiert. -middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: Middleware bereits definiert. -parameterNotSuppliedInRequestExceptionMessage = Ein Parameter namens '{0}' wurde in der Anfrage nicht angegeben oder es sind keine Daten verfügbar. -noDataForFileUploadedExceptionMessage = Keine Daten für die Datei '{0}' wurden in der Anfrage hochgeladen. -viewsFolderNameAlreadyExistsExceptionMessage = Der Name des Ansichtsordners existiert bereits: {0} -viewsPathDoesNotExistExceptionMessage = Der Ansichtsordnerpfad existiert nicht: {0} -timerAlreadyDefinedExceptionMessage = [Timer] {0}: Timer bereits definiert. -timerParameterMustBeGreaterThanZeroExceptionMessage = [Timer] {0}: {1} muss größer als 0 sein. -timerDoesNotExistExceptionMessage = Timer '{0}' existiert nicht. -mutexAlreadyExistsExceptionMessage = Ein Mutex mit folgendem Namen existiert bereits: {0} -noMutexFoundExceptionMessage = Kein Mutex mit dem Namen '{0}' gefunden. -failedToAcquireMutexOwnershipExceptionMessage = Fehler beim Erwerb des Mutex-Besitzes. Mutex-Name: {0} -semaphoreAlreadyExistsExceptionMessage = Ein Semaphor mit folgendem Namen existiert bereits: {0} -failedToAcquireSemaphoreOwnershipExceptionMessage = Fehler beim Erwerb des Semaphor-Besitzes. Semaphor-Name: {0} -scheduleAlreadyDefinedExceptionMessage = [Zeitplan] {0}: Zeitplan bereits definiert. -scheduleCannotHaveNegativeLimitExceptionMessage = [Zeitplan] {0}: Kann kein negatives Limit haben. -scheduleEndTimeMustBeInFutureExceptionMessage = [Zeitplan] {0}: Der Wert für EndTime muss in der Zukunft liegen. -scheduleStartTimeAfterEndTimeExceptionMessage = [Zeitplan] {0}: StartTime kann nicht nach EndTime liegen. -maximumConcurrentSchedulesInvalidExceptionMessage = Maximale gleichzeitige Zeitpläne müssen >=1 sein, aber erhalten: {0} -maximumConcurrentSchedulesLessThanMinimumExceptionMessage = Maximale gleichzeitige Zeitpläne dürfen nicht kleiner als das Minimum von {0} sein, aber erhalten: {1} -scheduleDoesNotExistExceptionMessage = Zeitplan '{0}' existiert nicht. -suppliedDateBeforeScheduleStartTimeExceptionMessage = Das angegebene Datum liegt vor der Startzeit des Zeitplans bei {0} -suppliedDateAfterScheduleEndTimeExceptionMessage = Das angegebene Datum liegt nach der Endzeit des Zeitplans bei {0} -noSemaphoreFoundExceptionMessage = Kein Semaphor mit dem Namen '{0}' gefunden. -noLogicPassedForRouteExceptionMessage = Keine Logik für Route übergeben: {0} -noPathSuppliedForStaticRouteExceptionMessage = [{0}]: Kein Pfad für statische Route angegeben. -sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: Der angegebene Quellpfad für die statische Route existiert nicht: {2} -noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Keine Logik übergeben. -moduleDoesNotContainFunctionExceptionMessage = Modul {0} enthält keine Funktion {1} zur Umwandlung in eine Route. -pageNameShouldBeAlphaNumericExceptionMessage = Der Seitenname sollte einen gültigen alphanumerischen Wert haben: {0} -filesHaveChangedMessage = Die folgenden Dateien wurden geändert: -multipleEndpointsForGuiMessage = Mehrere Endpunkte definiert, es wird nur der erste für die GUI verwendet. -openingGuiMessage = Die GUI wird geöffnet. -listeningOnEndpointsMessage = Lauschen auf den folgenden {0} Endpunkt(en) [{1} Thread(s)]: -specificationMessage = Spezifikation -documentationMessage = Dokumentation -restartingServerMessage = Server wird neu gestartet... -doneMessage = Fertig -deprecatedTitleVersionDescriptionWarningMessage = WARNUNG: Titel, Version und Beschreibung in 'Enable-PodeOpenApi' sind veraltet. Bitte verwenden Sie stattdessen 'Add-PodeOAInfo'. -undefinedOpenApiReferencesMessage = Nicht definierte OpenAPI-Referenzen: -definitionTagMessage = Definition {0}: -openApiGenerationDocumentErrorMessage = Fehler beim Generieren des OpenAPI-Dokuments: -infoTitleMandatoryMessage = info.title ist obligatorisch. -infoVersionMandatoryMessage = info.version ist obligatorisch. -missingComponentsMessage = Fehlende Komponente(n) -openApiInfoMessage = OpenAPI-Informationen: -serverLoopingMessage = Server-Schleife alle {0} Sekunden -iisShutdownMessage = (IIS Herunterfahren) -terminatingMessage = Beenden... -eolPowerShellWarningMessage = [WARNUNG] Pode {0} wurde nicht auf PowerShell {1} getestet, da es das Ende des Lebenszyklus erreicht hat. -untestedPowerShellVersionWarningMessage = [WARNUNG] Pode {0} wurde nicht auf PowerShell {1} getestet, da diese Version bei der Veröffentlichung von Pode nicht verfügbar war. -'@ \ No newline at end of file +@{ + schemaValidationRequiresPowerShell610ExceptionMessage = 'Die Schema-Validierung erfordert PowerShell Version 6.1.0 oder höher.' + pathOrScriptBlockRequiredExceptionMessage = 'Ein Pfad oder ScriptBlock ist erforderlich, um die benutzerdefinierten Zugriffswerte zu beziehen.' + operationIdMustBeUniqueForArrayExceptionMessage = 'OperationID: {0} muss eindeutig sein und kann nicht auf ein Array angewendet werden.' + endpointNotDefinedForRedirectingExceptionMessage = "Ein Endpunkt mit dem Namen '{0}' wurde nicht für die Weiterleitung definiert." + filesHaveChangedMessage = 'Die folgenden Dateien wurden geändert:' + iisAspnetcoreTokenMissingExceptionMessage = 'Das IIS-ASPNETCORE_TOKEN fehlt.' + minValueGreaterThanMaxExceptionMessage = 'Der Mindestwert für {0} darf nicht größer als der Maximalwert sein.' + noLogicPassedForRouteExceptionMessage = 'Keine Logik für Route übergeben: {0}' + scriptPathDoesNotExistExceptionMessage = 'Der Skriptpfad existiert nicht: {0}' + mutexAlreadyExistsExceptionMessage = 'Ein Mutex mit folgendem Namen existiert bereits: {0}' + listeningOnEndpointsMessage = 'Lauschen auf den folgenden {0} Endpunkt(en) [{1} Thread(s)]:' + unsupportedFunctionInServerlessContextExceptionMessage = 'Die Funktion {0} wird in einem serverlosen Kontext nicht unterstützt.' + expectedNoJwtSignatureSuppliedExceptionMessage = 'Es wurde keine JWT-Signatur erwartet.' + secretAlreadyMountedExceptionMessage = "Ein Geheimnis mit dem Namen '{0}' wurde bereits eingebunden." + failedToAcquireLockExceptionMessage = 'Sperre des Objekts konnte nicht erworben werden.' + noPathSuppliedForStaticRouteExceptionMessage = '[{0}]: Kein Pfad für statische Route angegeben.' + invalidHostnameSuppliedExceptionMessage = 'Der angegebene Hostname ist ungültig: {0}' + authMethodAlreadyDefinedExceptionMessage = 'Authentifizierungsmethode bereits definiert: {0}' + csrfCookieRequiresSecretExceptionMessage = "Beim Verwenden von Cookies für CSRF ist ein Geheimnis erforderlich. Sie können ein Geheimnis angeben oder das globale Cookie-Geheimnis festlegen - (Set-PodeCookieSecret '' -Global)" + nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 'Ein nicht leerer ScriptBlock ist erforderlich, um eine Seitenroute zu erstellen.' + noPropertiesMutuallyExclusiveExceptionMessage = "Der Parameter 'NoProperties' schließt 'Properties', 'MinProperties' und 'MaxProperties' gegenseitig aus." + incompatiblePodeDllExceptionMessage = 'Eine vorhandene inkompatible Pode.DLL-Version {0} ist geladen. Version {1} wird benötigt. Öffnen Sie eine neue PowerShell/pwsh-Sitzung und versuchen Sie es erneut.' + accessMethodDoesNotExistExceptionMessage = 'Zugriffsmethode existiert nicht: {0}.' + scheduleAlreadyDefinedExceptionMessage = '[Zeitplan] {0}: Zeitplan bereits definiert.' + secondsValueCannotBeZeroOrLessExceptionMessage = 'Der Sekundenwert darf für {0} nicht 0 oder weniger sein.' + pathToLoadNotFoundExceptionMessage = 'Pfad zum Laden von {0} nicht gefunden: {1}' + failedToImportModuleExceptionMessage = 'Modulimport fehlgeschlagen: {0}' + endpointNotExistExceptionMessage = "Der Endpunkt mit dem Protokoll '{0}' und der Adresse '{1}' oder der lokalen Adresse '{2}' existiert nicht" + terminatingMessage = 'Beenden...' + noCommandsSuppliedToConvertToRoutesExceptionMessage = 'Keine Befehle zur Umwandlung in Routen bereitgestellt.' + invalidTaskTypeExceptionMessage = 'Aufgabentyp ist ungültig, erwartet entweder [System.Threading.Tasks.Task] oder [hashtable]' + alreadyConnectedToWebSocketExceptionMessage = "Bereits mit dem WebSocket mit dem Namen '{0}' verbunden" + crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = 'Die CRLF-Nachrichtenendprüfung wird nur auf TCP-Endpunkten unterstützt.' + testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = "'Test-PodeOAComponentSchema' muss mit 'Enable-PodeOpenApi -EnableSchemaValidation' aktiviert werden." + adModuleNotInstalledExceptionMessage = 'Das Active Directory-Modul ist nicht installiert.' + cronExpressionInvalidExceptionMessage = 'Die Cron-Ausdruck sollte nur aus 5 Teilen bestehen: {0}' + noSessionToSetOnResponseExceptionMessage = 'Keine Sitzung verfügbar, die auf die Antwort gesetzt werden kann.' + valueOutOfRangeExceptionMessage = "Wert '{0}' für {1} ist ungültig, sollte zwischen {2} und {3} liegen" + loggingMethodAlreadyDefinedExceptionMessage = 'Logging-Methode bereits definiert: {0}' + noSecretForHmac256ExceptionMessage = 'Es wurde kein Geheimnis für den HMAC256-Hash angegeben.' + eolPowerShellWarningMessage = '[WARNUNG] Pode {0} wurde nicht auf PowerShell {1} getestet, da es das Ende des Lebenszyklus erreicht hat.' + runspacePoolFailedToLoadExceptionMessage = '{0} RunspacePool konnte nicht geladen werden.' + noEventRegisteredExceptionMessage = 'Kein Ereignis {0} registriert: {1}' + scheduleCannotHaveNegativeLimitExceptionMessage = '[Zeitplan] {0}: Kann kein negatives Limit haben.' + openApiRequestStyleInvalidForParameterExceptionMessage = 'Der OpenApi-Anfragestil kann für einen {1}-Parameter nicht {0} sein.' + openApiDocumentNotCompliantExceptionMessage = 'Das OpenAPI-Dokument ist nicht konform.' + taskDoesNotExistExceptionMessage = "Aufgabe '{0}' existiert nicht." + scopedVariableNotFoundExceptionMessage = 'Bereichsvariable nicht gefunden: {0}' + sessionsRequiredForCsrfExceptionMessage = 'Sitzungen sind erforderlich, um CSRF zu verwenden, es sei denn, Sie möchten Cookies verwenden.' + nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 'Ein nicht leerer ScriptBlock ist für die Protokollierungsmethode erforderlich.' + credentialsPassedWildcardForHeadersLiteralExceptionMessage = 'Wenn Anmeldeinformationen übergeben werden, wird das *-Wildcard für Header als Literalzeichenfolge und nicht als Platzhalter verwendet.' + podeNotInitializedExceptionMessage = 'Pode wurde nicht initialisiert.' + multipleEndpointsForGuiMessage = 'Mehrere Endpunkte definiert, es wird nur der erste für die GUI verwendet.' + operationIdMustBeUniqueExceptionMessage = 'OperationID: {0} muss eindeutig sein.' + invalidJsonJwtExceptionMessage = 'Ungültiger JSON-Wert in JWT gefunden' + noAlgorithmInJwtHeaderExceptionMessage = 'Kein Algorithmus im JWT-Header angegeben.' + openApiVersionPropertyMandatoryExceptionMessage = 'Die Eigenschaft OpenApi-Version ist obligatorisch.' + limitValueCannotBeZeroOrLessExceptionMessage = 'Der Grenzwert darf für {0} nicht 0 oder weniger sein.' + timerDoesNotExistExceptionMessage = "Timer '{0}' existiert nicht." + openApiGenerationDocumentErrorMessage = 'Fehler beim Generieren des OpenAPI-Dokuments:' + routeAlreadyContainsCustomAccessExceptionMessage = "Die Route '[{0}] {1}' enthält bereits einen benutzerdefinierten Zugriff mit dem Namen '{2}'." + maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 'Die maximale Anzahl gleichzeitiger WebSocket-Threads darf nicht kleiner als das Minimum von {0} sein, aber erhalten: {1}' + middlewareAlreadyDefinedExceptionMessage = '[Middleware] {0}: Middleware bereits definiert.' + invalidAtomCharacterExceptionMessage = 'Ungültiges Atomzeichen: {0}' + cacheStorageNotFoundForRetrieveExceptionMessage = "Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde, das zwischengespeicherte Element '{1}' abzurufen." + headerMustHaveNameInEncodingContextExceptionMessage = 'Ein Header muss einen Namen haben, wenn er im Codierungskontext verwendet wird.' + moduleDoesNotContainFunctionExceptionMessage = 'Modul {0} enthält keine Funktion {1} zur Umwandlung in eine Route.' + pathToIconForGuiDoesNotExistExceptionMessage = 'Der Pfad zum Symbol für die GUI existiert nicht: {0}' + noTitleSuppliedForPageExceptionMessage = 'Kein Titel für die Seite {0} angegeben.' + certificateSuppliedForNonHttpsWssEndpointExceptionMessage = 'Zertifikat für Nicht-HTTPS/WSS-Endpunkt bereitgestellt.' + cannotLockNullObjectExceptionMessage = 'Kann ein null-Objekt nicht sperren.' + showPodeGuiOnlyAvailableOnWindowsExceptionMessage = 'Show-PodeGui ist derzeit nur für Windows PowerShell und PowerShell 7+ unter Windows verfügbar.' + unlockSecretButNoScriptBlockExceptionMessage = 'Unlock secret für benutzerdefinierten Secret Vault-Typ angegeben, aber kein Unlock ScriptBlock bereitgestellt.' + invalidIpAddressExceptionMessage = 'Die angegebene IP-Adresse ist ungültig: {0}' + maxDaysInvalidExceptionMessage = 'MaxDays muss 0 oder größer sein, aber erhalten: {0}' + noRemoveScriptBlockForVaultExceptionMessage = "Kein Remove ScriptBlock für das Entfernen von Geheimnissen im Tresor '{0}' bereitgestellt." + noSecretExpectedForNoSignatureExceptionMessage = 'Es wurde erwartet, dass kein Geheimnis für keine Signatur angegeben wird.' + noCertificateFoundExceptionMessage = "Es wurde kein Zertifikat in {0}{1} für '{2}' gefunden." + minValueInvalidExceptionMessage = "Der Mindestwert '{0}' für {1} ist ungültig, sollte größer oder gleich {2} sein" + accessRequiresAuthenticationOnRoutesExceptionMessage = 'Der Zugriff erfordert eine Authentifizierung auf den Routen.' + noSecretForHmac384ExceptionMessage = 'Es wurde kein Geheimnis für den HMAC384-Hash angegeben.' + windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = 'Die Unterstützung der lokalen Windows-Authentifizierung gilt nur für Windows.' + definitionTagNotDefinedExceptionMessage = 'Definitionstag {0} ist nicht definiert.' + noComponentInDefinitionExceptionMessage = 'Es ist keine Komponente des Typs {0} mit dem Namen {1} in der Definition {2} verfügbar.' + noSmtpHandlersDefinedExceptionMessage = 'Es wurden keine SMTP-Handler definiert.' + sessionMiddlewareAlreadyInitializedExceptionMessage = 'Session Middleware wurde bereits initialisiert.' + reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = "Die wiederverwendbare Komponente 'pathItems' ist in OpenAPI v3.0 nicht verfügbar." + wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 'Das *-Wildcard für Header ist nicht mit dem AutoHeaders-Schalter kompatibel.' + noDataForFileUploadedExceptionMessage = "Keine Daten für die Datei '{0}' wurden in der Anfrage hochgeladen." + sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = 'SSE kann nur auf Anfragen mit einem Accept-Header-Wert von text/event-stream konfiguriert werden.' + noSessionAvailableToSaveExceptionMessage = 'Keine Sitzung verfügbar zum Speichern.' + pathParameterRequiresRequiredSwitchExceptionMessage = "Wenn der Parameterstandort 'Path' ist, ist der Schalterparameter 'Required' erforderlich." + noOpenApiUrlSuppliedExceptionMessage = 'Keine OpenAPI-URL für {0} angegeben.' + maximumConcurrentSchedulesInvalidExceptionMessage = 'Maximale gleichzeitige Zeitpläne müssen >=1 sein, aber erhalten: {0}' + snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = 'Snapins werden nur in Windows PowerShell unterstützt.' + eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = 'Das Protokollieren im Ereignisanzeige wird nur auf Windows unterstützt.' + parametersMutuallyExclusiveExceptionMessage = "Die Parameter '{0}' und '{1}' schließen sich gegenseitig aus." + pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 'Das PathItems-Feature wird in OpenAPI v3.0.x nicht unterstützt.' + openApiParameterRequiresNameExceptionMessage = 'Der OpenApi-Parameter erfordert einen angegebenen Namen.' + maximumConcurrentTasksLessThanMinimumExceptionMessage = 'Die maximale Anzahl gleichzeitiger Aufgaben darf nicht kleiner als das Minimum von {0} sein, aber erhalten: {1}' + noSemaphoreFoundExceptionMessage = "Kein Semaphor mit dem Namen '{0}' gefunden." + singleValueForIntervalExceptionMessage = 'Sie können nur einen einzelnen {0}-Wert angeben, wenn Sie Intervalle verwenden.' + jwtNotYetValidExceptionMessage = 'Der JWT ist noch nicht gültig.' + verbAlreadyDefinedForUrlExceptionMessage = '[Verb] {0}: Bereits für {1} definiert.' + noSecretNamedMountedExceptionMessage = "Kein Geheimnis mit dem Namen '{0}' wurde eingebunden." + moduleOrVersionNotFoundExceptionMessage = 'Modul oder Version nicht gefunden auf {0}: {1}@{2}' + noScriptBlockSuppliedExceptionMessage = 'Kein Skriptblock angegeben.' + noSecretVaultRegisteredExceptionMessage = "Kein Geheimnistresor mit dem Namen '{0}' registriert." + nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = 'Ein Name ist für den Endpunkt erforderlich, wenn der RedirectTo-Parameter angegeben ist.' + openApiLicenseObjectRequiresNameExceptionMessage = "Das OpenAPI-Objekt 'license' erfordert die Eigenschaft 'name'. Verwenden Sie den Parameter -LicenseName." + sourcePathDoesNotExistForStaticRouteExceptionMessage = '[{0})] {1}: Der angegebene Quellpfad für die statische Route existiert nicht: {2}' + noNameForWebSocketDisconnectExceptionMessage = 'Kein Name für die Trennung vom WebSocket angegeben.' + certificateExpiredExceptionMessage = "Das Zertifikat '{0}' ist abgelaufen: {1}" + secretVaultUnlockExpiryDateInPastExceptionMessage = 'Das Ablaufdatum zum Entsperren des Geheimnis-Tresors liegt in der Vergangenheit (UTC): {0}' + invalidExceptionTypeExceptionMessage = 'Die Ausnahme hat einen ungültigen Typ. Er sollte entweder WebException oder HttpRequestException sein, aber es wurde {0} erhalten' + invalidSecretValueTypeExceptionMessage = 'Der Geheimniswert hat einen ungültigen Typ. Erwartete Typen: String, SecureString, HashTable, Byte[] oder PSCredential. Aber erhalten wurde: {0}.' + explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 'Der explizite TLS-Modus wird nur auf SMTPS- und TCPS-Endpunkten unterstützt.' + discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = "Der Parameter 'DiscriminatorMapping' kann nur verwendet werden, wenn 'DiscriminatorProperty' vorhanden ist." + scriptErrorExceptionMessage = "Fehler '{0}' im Skript {1} {2} (Zeile {3}) Zeichen {4} beim Ausführen von {5} auf {6} Objekt '{7}' Klasse: {8} Basisklasse: {9}" + cannotSupplyIntervalForQuarterExceptionMessage = 'Ein Intervallwert kann nicht für jedes Quartal angegeben werden.' + scheduleEndTimeMustBeInFutureExceptionMessage = '[Zeitplan] {0}: Der Wert für EndTime muss in der Zukunft liegen.' + invalidJwtSignatureSuppliedExceptionMessage = 'Ungültige JWT-Signatur angegeben.' + noSetScriptBlockForVaultExceptionMessage = "Kein Set ScriptBlock für das Aktualisieren/Erstellen von Geheimnissen im Tresor '{0}' bereitgestellt." + accessMethodNotExistForMergingExceptionMessage = 'Zugriffsmethode zum Zusammenführen nicht vorhanden: {0}.' + defaultAuthNotInListExceptionMessage = "Die Standardauthentifizierung '{0}' befindet sich nicht in der angegebenen Authentifizierungsliste." + parameterHasNoNameExceptionMessage = "Der Parameter hat keinen Namen. Bitte geben Sie dieser Komponente einen Namen mit dem 'Name'-Parameter." + methodPathAlreadyDefinedForUrlExceptionMessage = '[{0}] {1}: Bereits für {2} definiert.' + fileWatcherAlreadyDefinedExceptionMessage = "Ein Dateiwächter mit dem Namen '{0}' wurde bereits definiert." + noServiceHandlersDefinedExceptionMessage = 'Es wurden keine Service-Handler definiert.' + secretRequiredForCustomSessionStorageExceptionMessage = 'Ein Geheimnis ist erforderlich, wenn benutzerdefinierter Sitzungspeicher verwendet wird.' + secretManagementModuleNotInstalledExceptionMessage = 'Das Modul Microsoft.PowerShell.SecretManagement ist nicht installiert.' + noPathSuppliedForRouteExceptionMessage = 'Kein Pfad für die Route bereitgestellt.' + validationOfAnyOfSchemaNotSupportedExceptionMessage = "Die Validierung eines Schemas, das 'anyof' enthält, wird nicht unterstützt." + iisAuthSupportIsForWindowsOnlyExceptionMessage = 'Die IIS-Authentifizierungsunterstützung gilt nur für Windows.' + oauth2InnerSchemeInvalidExceptionMessage = 'OAuth2 InnerScheme kann nur entweder Basic oder Form-Authentifizierung sein, aber erhalten: {0}' + noRoutePathSuppliedForPageExceptionMessage = 'Kein Routenpfad für die Seite {0} angegeben.' + cacheStorageNotFoundForExistsExceptionMessage = "Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde zu überprüfen, ob das zwischengespeicherte Element '{1}' existiert." + handlerAlreadyDefinedExceptionMessage = '[{0}] {1}: Handler bereits definiert.' + sessionsNotConfiguredExceptionMessage = 'Sitzungen wurden nicht konfiguriert.' + propertiesTypeObjectAssociationExceptionMessage = 'Nur Eigenschaften vom Typ Object können mit {0} verknüpft werden.' + sessionsRequiredForSessionPersistentAuthExceptionMessage = 'Sitzungen sind erforderlich, um die sitzungsbeständige Authentifizierung zu verwenden.' + invalidPathWildcardOrDirectoryExceptionMessage = 'Der angegebene Pfad darf kein Platzhalter oder Verzeichnis sein: {0}' + accessMethodAlreadyDefinedExceptionMessage = 'Zugriffsmethode bereits definiert: {0}.' + parametersValueOrExternalValueMandatoryExceptionMessage = "Die Parameter 'Value' oder 'ExternalValue' sind obligatorisch." + maximumConcurrentTasksInvalidExceptionMessage = 'Die maximale Anzahl gleichzeitiger Aufgaben muss >=1 sein, aber erhalten: {0}' + cannotCreatePropertyWithoutTypeExceptionMessage = 'Die Eigenschaft kann nicht erstellt werden, weil kein Typ definiert ist.' + authMethodNotExistForMergingExceptionMessage = 'Die Authentifizierungsmethode existiert nicht zum Zusammenführen: {0}' + maxValueInvalidExceptionMessage = "Der Maximalwert '{0}' für {1} ist ungültig, sollte kleiner oder gleich {2} sein" + endpointAlreadyDefinedExceptionMessage = "Ein Endpunkt mit dem Namen '{0}' wurde bereits definiert." + eventAlreadyRegisteredExceptionMessage = 'Ereignis {0} bereits registriert: {1}' + parameterNotSuppliedInRequestExceptionMessage = "Ein Parameter namens '{0}' wurde in der Anfrage nicht angegeben oder es sind keine Daten verfügbar." + cacheStorageNotFoundForSetExceptionMessage = "Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde, das zwischengespeicherte Element '{1}' zu setzen." + methodPathAlreadyDefinedExceptionMessage = '[{0}] {1}: Bereits definiert.' + errorLoggingAlreadyEnabledExceptionMessage = 'Die Fehlerprotokollierung wurde bereits aktiviert.' + valueForUsingVariableNotFoundExceptionMessage = "Der Wert für '`$using:{0}' konnte nicht gefunden werden." + rapidPdfDoesNotSupportOpenApi31ExceptionMessage = 'Das Dokumentationstool RapidPdf unterstützt OpenAPI 3.1 nicht.' + oauth2ClientSecretRequiredExceptionMessage = 'OAuth2 erfordert ein Client Secret, wenn PKCE nicht verwendet wird.' + invalidBase64JwtExceptionMessage = 'Ungültiger Base64-codierter Wert in JWT gefunden' + noSessionToCalculateDataHashExceptionMessage = 'Keine Sitzung verfügbar, um den Datenhash zu berechnen.' + cacheStorageNotFoundForRemoveExceptionMessage = "Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde, das zwischengespeicherte Element '{1}' zu entfernen." + csrfMiddlewareNotInitializedExceptionMessage = 'CSRF Middleware wurde nicht initialisiert.' + infoTitleMandatoryMessage = 'info.title ist obligatorisch.' + typeCanOnlyBeAssociatedWithObjectExceptionMessage = 'Der Typ {0} kann nur einem Objekt zugeordnet werden.' + userFileDoesNotExistExceptionMessage = 'Die Benutzerdaten-Datei existiert nicht: {0}' + routeParameterNeedsValidScriptblockExceptionMessage = 'Der Route-Parameter benötigt einen gültigen, nicht leeren ScriptBlock.' + nextTriggerCalculationErrorExceptionMessage = 'Es scheint, als ob beim Berechnen des nächsten Trigger-Datums und der nächsten Triggerzeit etwas schief gelaufen wäre: {0}' + cannotLockValueTypeExceptionMessage = 'Kann [ValueTypes] nicht sperren.' + failedToCreateOpenSslCertExceptionMessage = 'Erstellung des OpenSSL-Zertifikats fehlgeschlagen: {0}.' + jwtExpiredExceptionMessage = 'Der JWT ist abgelaufen.' + openingGuiMessage = 'Die GUI wird geöffnet.' + multiTypePropertiesRequireOpenApi31ExceptionMessage = 'Mehrfachtyp-Eigenschaften erfordern OpenApi-Version 3.1 oder höher.' + noNameForWebSocketRemoveExceptionMessage = 'Kein Name für das Entfernen des WebSocket angegeben.' + maxSizeInvalidExceptionMessage = 'MaxSize muss 0 oder größer sein, aber erhalten: {0}' + iisShutdownMessage = '(IIS Herunterfahren)' + cannotUnlockValueTypeExceptionMessage = 'Kann [ValueTypes] nicht entsperren.' + noJwtSignatureForAlgorithmExceptionMessage = 'Keine JWT-Signatur für {0} angegeben.' + maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 'Die maximale Anzahl gleichzeitiger WebSocket-Threads muss >=1 sein, aber erhalten: {0}' + acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 'Die Bestätigungsnachricht wird nur auf SMTP- und TCP-Endpunkten unterstützt.' + failedToConnectToUrlExceptionMessage = 'Verbindung mit der URL fehlgeschlagen: {0}' + failedToAcquireMutexOwnershipExceptionMessage = 'Fehler beim Erwerb des Mutex-Besitzes. Mutex-Name: {0}' + sessionsRequiredForOAuth2WithPKCEExceptionMessage = 'Sitzungen sind erforderlich, um OAuth2 mit PKCE zu verwenden.' + failedToConnectToWebSocketExceptionMessage = 'Verbindung zum WebSocket fehlgeschlagen: {0}' + unsupportedObjectExceptionMessage = 'Nicht unterstütztes Objekt' + failedToParseAddressExceptionMessage = "Konnte '{0}' nicht als gültige IP/Host:Port-Adresse analysieren" + mustBeRunningWithAdminPrivilegesExceptionMessage = 'Muss mit Administratorrechten ausgeführt werden, um auf Nicht-Localhost-Adressen zu lauschen.' + specificationMessage = 'Spezifikation' + cacheStorageNotFoundForClearExceptionMessage = "Der Cache-Speicher mit dem Namen '{0}' wurde nicht gefunden, als versucht wurde, den Cache zu leeren." + restartingServerMessage = 'Server wird neu gestartet...' + cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = "Ein Intervall kann nicht angegeben werden, wenn der Parameter 'Every' auf None gesetzt ist." + unsupportedJwtAlgorithmExceptionMessage = 'Der JWT-Algorithmus wird derzeit nicht unterstützt: {0}' + websocketsNotConfiguredForSignalMessagesExceptionMessage = 'WebSockets wurden nicht konfiguriert, um Signalnachrichten zu senden.' + invalidLogicTypeInHashtableMiddlewareExceptionMessage = 'Eine angegebene Hashtable-Middleware enthält einen ungültigen Logik-Typ. Erwartet wurde ein ScriptBlock, aber erhalten wurde: {0}.' + maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 'Maximale gleichzeitige Zeitpläne dürfen nicht kleiner als das Minimum von {0} sein, aber erhalten: {1}' + failedToAcquireSemaphoreOwnershipExceptionMessage = 'Fehler beim Erwerb des Semaphor-Besitzes. Semaphor-Name: {0}' + propertiesParameterWithoutNameExceptionMessage = 'Die Eigenschaftsparameter können nicht verwendet werden, wenn die Eigenschaft keinen Namen hat.' + customSessionStorageMethodNotImplementedExceptionMessage = "Der benutzerdefinierte Sitzungspeicher implementiert die erforderliche Methode '{0}()' nicht." + authenticationMethodDoesNotExistExceptionMessage = 'Authentifizierungsmethode existiert nicht: {0}' + webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = 'Das Webhooks-Feature wird in OpenAPI v3.0.x nicht unterstützt.' + invalidContentTypeForSchemaExceptionMessage = "Ungültiger 'content-type' im Schema gefunden: {0}" + noUnlockScriptBlockForVaultExceptionMessage = "Kein Unlock ScriptBlock für das Entsperren des Tresors '{0}' bereitgestellt." + definitionTagMessage = 'Definition {0}:' + failedToOpenRunspacePoolExceptionMessage = 'Fehler beim Öffnen des Runspace-Pools: {0}' + verbNoLogicPassedExceptionMessage = '[Verb] {0}: Keine Logik übergeben' + noMutexFoundExceptionMessage = "Kein Mutex mit dem Namen '{0}' gefunden." + documentationMessage = 'Dokumentation' + timerAlreadyDefinedExceptionMessage = '[Timer] {0}: Timer bereits definiert.' + invalidPortExceptionMessage = 'Der Port kann nicht negativ sein: {0}' + viewsFolderNameAlreadyExistsExceptionMessage = 'Der Name des Ansichtsordners existiert bereits: {0}' + noNameForWebSocketResetExceptionMessage = 'Kein Name für das Zurücksetzen des WebSocket angegeben.' + mergeDefaultAuthNotInListExceptionMessage = "Die MergeDefault-Authentifizierung '{0}' befindet sich nicht in der angegebenen Authentifizierungsliste." + descriptionRequiredExceptionMessage = 'Eine Beschreibung ist erforderlich.' + pageNameShouldBeAlphaNumericExceptionMessage = 'Der Seitenname sollte einen gültigen alphanumerischen Wert haben: {0}' + defaultValueNotBooleanOrEnumExceptionMessage = 'Der Standardwert ist kein Boolean und gehört nicht zum Enum.' + openApiComponentSchemaDoesNotExistExceptionMessage = 'Das OpenApi-Komponentenschema {0} existiert nicht.' + timerParameterMustBeGreaterThanZeroExceptionMessage = '[Timer] {0}: {1} muss größer als 0 sein.' + taskTimedOutExceptionMessage = 'Aufgabe ist nach {0}ms abgelaufen.' + scheduleStartTimeAfterEndTimeExceptionMessage = '[Zeitplan] {0}: StartTime kann nicht nach EndTime liegen.' + infoVersionMandatoryMessage = 'info.version ist obligatorisch.' + cannotUnlockNullObjectExceptionMessage = 'Kann ein null-Objekt nicht entsperren.' + nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 'Ein nicht leerer ScriptBlock ist für das benutzerdefinierte Authentifizierungsschema erforderlich.' + validationOfOneOfSchemaNotSupportedExceptionMessage = "Die Validierung eines Schemas, das 'oneof' enthält, wird nicht unterstützt." + routeParameterCannotBeNullExceptionMessage = "Der Parameter 'Route' darf nicht null sein." + cacheStorageAlreadyExistsExceptionMessage = "Ein Cache-Speicher mit dem Namen '{0}' existiert bereits." + loggingMethodRequiresValidScriptBlockExceptionMessage = "Die angegebene Ausgabemethode für die Logging-Methode '{0}' erfordert einen gültigen ScriptBlock." + scopedVariableAlreadyDefinedExceptionMessage = 'Die Bereichsvariable ist bereits definiert: {0}.' + oauth2RequiresAuthorizeUrlExceptionMessage = 'OAuth2 erfordert die Angabe einer Autorisierungs-URL.' + pathNotExistExceptionMessage = 'Pfad existiert nicht: {0}' + noDomainServerNameForWindowsAdAuthExceptionMessage = 'Es wurde kein Domänenservername für die Windows-AD-Authentifizierung angegeben.' + suppliedDateAfterScheduleEndTimeExceptionMessage = 'Das angegebene Datum liegt nach der Endzeit des Zeitplans bei {0}' + wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 'Das *-Wildcard für Methoden ist nicht mit dem AutoMethods-Schalter kompatibel.' + cannotSupplyIntervalForYearExceptionMessage = 'Ein Intervallwert kann nicht für jedes Jahr angegeben werden.' + missingComponentsMessage = 'Fehlende Komponente(n)' + invalidStrictTransportSecurityDurationExceptionMessage = 'Ungültige Strict-Transport-Security-Dauer angegeben: {0}. Sie sollte größer als 0 sein.' + noSecretForHmac512ExceptionMessage = 'Es wurde kein Geheimnis für den HMAC512-Hash angegeben.' + daysInMonthExceededExceptionMessage = '{0} hat nur {1} Tage, aber {2} wurden angegeben' + nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 'Ein nicht leerer ScriptBlock ist für die benutzerdefinierte Protokollierungsmethode erforderlich.' + encodingAttributeOnlyAppliesToMultipartExceptionMessage = 'Das Encoding-Attribut gilt nur für multipart und application/x-www-form-urlencoded Anfragekörper.' + suppliedDateBeforeScheduleStartTimeExceptionMessage = 'Das angegebene Datum liegt vor der Startzeit des Zeitplans bei {0}' + unlockSecretRequiredExceptionMessage = "Eine 'UnlockSecret'-Eigenschaft ist erforderlich, wenn Microsoft.PowerShell.SecretStore verwendet wird." + noLogicPassedForMethodRouteExceptionMessage = '[{0}] {1}: Keine Logik übergeben.' + bodyParserAlreadyDefinedForContentTypeExceptionMessage = 'Für den Inhaltstyp {0} ist bereits ein Body-Parser definiert.' + invalidJwtSuppliedExceptionMessage = 'Ungültiger JWT angegeben.' + sessionsRequiredForFlashMessagesExceptionMessage = 'Sitzungen sind erforderlich, um Flash-Nachrichten zu verwenden.' + outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = 'Die angegebene Ausgabemethode für die Anforderungsprotokollierung erfordert einen gültigen ScriptBlock.' + semaphoreAlreadyExistsExceptionMessage = 'Ein Semaphor mit folgendem Namen existiert bereits: {0}' + invalidJwtHeaderAlgorithmSuppliedExceptionMessage = 'Ungültiger JWT-Header-Algorithmus angegeben.' + oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = "Der OAuth2-Anbieter unterstützt den für die Verwendung eines InnerScheme erforderlichen 'password'-Grant-Typ nicht." + invalidAliasFoundExceptionMessage = 'Ungültiges {0}-Alias gefunden: {1}' + scheduleDoesNotExistExceptionMessage = "Zeitplan '{0}' existiert nicht." + accessMethodNotExistExceptionMessage = 'Zugriffsmethode nicht vorhanden: {0}.' + oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = "Der OAuth2-Anbieter unterstützt den 'code'-Antworttyp nicht." + untestedPowerShellVersionWarningMessage = '[WARNUNG] Pode {0} wurde nicht auf PowerShell {1} getestet, da diese Version bei der Veröffentlichung von Pode nicht verfügbar war.' + secretVaultAlreadyRegisteredAutoImportExceptionMessage = "Ein Geheimtresor mit dem Namen '{0}' wurde bereits beim automatischen Importieren von Geheimtresoren registriert." + schemeRequiresValidScriptBlockExceptionMessage = "Das bereitgestellte Schema für den Authentifizierungsvalidator '{0}' erfordert einen gültigen ScriptBlock." + serverLoopingMessage = 'Server-Schleife alle {0} Sekunden' + certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 'Zertifikat-Thumbprints/Name werden nur unter Windows unterstützt.' + sseConnectionNameRequiredExceptionMessage = "Ein SSE-Verbindungsname ist erforderlich, entweder von -Name oder `$WebEvent.Sse.Namee" + invalidMiddlewareTypeExceptionMessage = 'Eines der angegebenen Middleware-Objekte ist ein ungültiger Typ. Erwartet wurde entweder ein ScriptBlock oder ein Hashtable, aber erhalten wurde: {0}.' + noSecretForJwtSignatureExceptionMessage = 'Es wurde kein Geheimnis für die JWT-Signatur angegeben.' + modulePathDoesNotExistExceptionMessage = 'Der Modulpfad existiert nicht: {0}' + taskAlreadyDefinedExceptionMessage = '[Aufgabe] {0}: Aufgabe bereits definiert.' + verbAlreadyDefinedExceptionMessage = '[Verb] {0}: Bereits definiert.' + clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 'Clientzertifikate werden nur auf HTTPS-Endpunkten unterstützt.' + endpointNameNotExistExceptionMessage = "Der Endpunkt mit dem Namen '{0}' existiert nicht" + middlewareNoLogicSuppliedExceptionMessage = '[Middleware]: Kein Logik-ScriptBlock bereitgestellt.' + scriptBlockRequiredForMergingUsersExceptionMessage = 'Ein ScriptBlock ist erforderlich, um mehrere authentifizierte Benutzer zu einem Objekt zusammenzuführen, wenn Valid All ist.' + secretVaultAlreadyRegisteredExceptionMessage = "Ein Geheimnis-Tresor mit dem Namen '{0}' wurde bereits registriert{1}." + deprecatedTitleVersionDescriptionWarningMessage = "WARNUNG: Titel, Version und Beschreibung in 'Enable-PodeOpenApi' sind veraltet. Bitte verwenden Sie stattdessen 'Add-PodeOAInfo'." + undefinedOpenApiReferencesMessage = 'Nicht definierte OpenAPI-Referenzen:' + doneMessage = 'Fertig' + swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = 'Diese Version des Swagger-Editors unterstützt OpenAPI 3.1 nicht.' + durationMustBeZeroOrGreaterExceptionMessage = 'Die Dauer muss 0 oder größer sein, aber erhalten: {0}s' + viewsPathDoesNotExistExceptionMessage = 'Der Ansichtsordnerpfad existiert nicht: {0}' + discriminatorIncompatibleWithAllOfExceptionMessage = "Der Parameter 'Discriminator' ist nicht mit 'allOf' kompatibel." + noNameForWebSocketSendMessageExceptionMessage = 'Kein Name für das Senden einer Nachricht an den WebSocket angegeben.' + hashtableMiddlewareNoLogicExceptionMessage = 'Eine angegebene Hashtable-Middleware enthält keine definierte Logik.' + openApiInfoMessage = 'OpenAPI-Informationen:' + invalidSchemeForAuthValidatorExceptionMessage = "Das bereitgestellte '{0}'-Schema für den Authentifizierungsvalidator '{1}' erfordert einen gültigen ScriptBlock." + sseFailedToBroadcastExceptionMessage = 'SSE konnte aufgrund des definierten SSE-Broadcast-Levels für {0}: {1} nicht übertragen werden.' + adModuleWindowsOnlyExceptionMessage = 'Active Directory-Modul nur unter Windows verfügbar.' + requestLoggingAlreadyEnabledExceptionMessage = 'Die Anforderungsprotokollierung wurde bereits aktiviert.' + invalidAccessControlMaxAgeDurationExceptionMessage = 'Ungültige Access-Control-Max-Age-Dauer angegeben: {0}. Sollte größer als 0 sein.' +} + diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 841fdd8f3..cccd55e58 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -1,284 +1,285 @@ -ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyExceptionMessage = Active Directory module only available on Windows. -adModuleNotInstalledExceptionMessage = Active Directory module is not installed. -secretManagementModuleNotInstalledExceptionMessage = Microsoft.PowerShell.SecretManagement module not installed. -secretVaultAlreadyRegisteredAutoImportExceptionMessage = A Secret Vault with the name '{0}' has already been registered while auto-importing Secret Vaults. -failedToOpenRunspacePoolExceptionMessage = Failed to open RunspacePool: {0} -cronExpressionInvalidExceptionMessage = Cron expression should only consist of 5 parts: {0} -invalidAliasFoundExceptionMessage = Invalid {0} alias found: {1} -invalidAtomCharacterExceptionMessage = Invalid atom character: {0} -minValueGreaterThanMaxExceptionMessage = Min value for {0} should not be greater than the max value. -minValueInvalidExceptionMessage = Min value '{0}' for {1} is invalid, should be greater than/equal to {2} -maxValueInvalidExceptionMessage = Max value '{0}' for {1} is invalid, should be less than/equal to {2} -valueOutOfRangeExceptionMessage = Value '{0}' for {1} is invalid, should be between {2} and {3} -daysInMonthExceededExceptionMessage = {0} only has {1} days, but {2} was supplied. -nextTriggerCalculationErrorExceptionMessage = Looks like something went wrong trying to calculate the next trigger datetime: {0} -incompatiblePodeDllExceptionMessage = An existing incompatible Pode.DLL version {0} is loaded. Version {1} is required. Open a new Powershell/pwsh session and retry. -endpointNotExistExceptionMessage = Endpoint with protocol '{0}' and address '{1}' or local address '{2}' does not exist. -endpointNameNotExistExceptionMessage = Endpoint with name '{0}' does not exist. -failedToConnectToUrlExceptionMessage = Failed to connect to URL: {0} -failedToParseAddressExceptionMessage = Failed to parse '{0}' as a valid IP/Host:Port address -invalidIpAddressExceptionMessage = The IP address supplied is invalid: {0} -invalidPortExceptionMessage = The port cannot be negative: {0} -pathNotExistExceptionMessage = Path does not exist: {0} -noSecretForHmac256ExceptionMessage = No secret supplied for HMAC256 hash. -noSecretForHmac384ExceptionMessage = No secret supplied for HMAC384 hash. -noSecretForHmac512ExceptionMessage = No secret supplied for HMAC512 hash. -noSecretForJwtSignatureExceptionMessage = No secret supplied for JWT signature. -noSecretExpectedForNoSignatureExceptionMessage = Expected no secret to be supplied for no signature. -unsupportedJwtAlgorithmExceptionMessage = The JWT algorithm is not currently supported: {0} -invalidBase64JwtExceptionMessage = Invalid Base64 encoded value found in JWT -invalidJsonJwtExceptionMessage = Invalid JSON value found in JWT -unsupportedFunctionInServerlessContextExceptionMessage = The {0} function is not supported in a serverless context. -invalidPathWildcardOrDirectoryExceptionMessage = The Path supplied cannot be a wildcard or a directory: {0} -invalidExceptionTypeExceptionMessage = Exception is of an invalid type, should be either WebException or HttpRequestException, but got: {0} -pathToLoadNotFoundExceptionMessage = Path to load {0} not found: {1} -singleValueForIntervalExceptionMessage = You can only supply a single {0} value when using intervals. -scriptErrorExceptionMessage = Error '{0}' in script {1} {2} (line {3}) char {4} executing {5} on {6} object '{7}' Class: {8} BaseClass: {9} -noScriptBlockSuppliedExceptionMessage = No ScriptBlock supplied. -iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN is missing. -propertiesParameterWithoutNameExceptionMessage = The Properties parameters cannot be used if the Property has no name. -multiTypePropertiesRequireOpenApi31ExceptionMessage = Multi-type properties require OpenApi Version 3.1 or above. -openApiVersionPropertyMandatoryExceptionMessage = OpenApi Version property is mandatory. -webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = The Webhooks feature is not supported in OpenAPI v3.0.x -authenticationMethodDoesNotExistExceptionMessage = Authentication method does not exist: {0} -unsupportedObjectExceptionMessage = Unsupported object -validationOfAnyOfSchemaNotSupportedExceptionMessage = Validation of a schema that includes 'anyof' is not supported. -validationOfOneOfSchemaNotSupportedExceptionMessage = Validation of a schema that includes 'oneof' is not supported. -cannotCreatePropertyWithoutTypeExceptionMessage = Cannot create the property because no type is defined. -headerMustHaveNameInEncodingContextExceptionMessage = Header must have a name when used in an encoding context. -descriptionRequiredExceptionMessage = A Description is required. -openApiDocumentNotCompliantExceptionMessage = OpenAPI document is not compliant. -noComponentInDefinitionExceptionMessage = No component of type {0} named {1} is available in the {2} definition. -methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: Already defined. -methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: Already defined for {2} -invalidMiddlewareTypeExceptionMessage = One of the Middlewares supplied is an invalid type. Expected either a ScriptBlock or Hashtable, but got: {0} -hashtableMiddlewareNoLogicExceptionMessage = A Hashtable Middleware supplied has no Logic defined. -invalidLogicTypeInHashtableMiddlewareExceptionMessage = A Hashtable Middleware supplied has an invalid Logic type. Expected ScriptBlock, but got: {0} -scopedVariableAlreadyDefinedExceptionMessage = Scoped Variable already defined: {0} -valueForUsingVariableNotFoundExceptionMessage = Value for '`$using:{0}' could not be found. -unlockSecretRequiredExceptionMessage = An 'UnlockSecret' property is required when using Microsoft.PowerShell.SecretStore -unlockSecretButNoScriptBlockExceptionMessage = Unlock secret supplied for custom Secret Vault type, but not Unlock ScriptBlock supplied. -noUnlockScriptBlockForVaultExceptionMessage = No Unlock ScriptBlock supplied for unlocking the vault '{0}' -noSetScriptBlockForVaultExceptionMessage = No Set ScriptBlock supplied for updating/creating secrets in the vault '{0}' -noRemoveScriptBlockForVaultExceptionMessage = No Remove ScriptBlock supplied for removing secrets from the vault '{0}' -invalidSecretValueTypeExceptionMessage = Secret value is of an invalid type. Expected types: String, SecureString, HashTable, Byte[], or PSCredential. But got: {0} -limitValueCannotBeZeroOrLessExceptionMessage = Limit value cannot be 0 or less for {0} -secondsValueCannotBeZeroOrLessExceptionMessage = Seconds value cannot be 0 or less for {0} -failedToCreateOpenSslCertExceptionMessage = Failed to create openssl cert: {0} -certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Certificate Thumbprints/Name are only supported on Windows. -noCertificateFoundExceptionMessage = No certificate could be found in {0}\{1} for '{2}' -runspacePoolFailedToLoadExceptionMessage = {0} RunspacePool failed to load. -noServiceHandlersDefinedExceptionMessage = No Service handlers have been defined. -noSessionToSetOnResponseExceptionMessage = There is no session available to set on the response. -noSessionToCalculateDataHashExceptionMessage = No session available to calculate data hash. -moduleOrVersionNotFoundExceptionMessage = Module or version not found on {0}: {1}@{2} -noSmtpHandlersDefinedExceptionMessage = No SMTP handlers have been defined. -taskTimedOutExceptionMessage = Task has timed out after {0}ms. -verbAlreadyDefinedExceptionMessage = [Verb] {0}: Already defined -verbAlreadyDefinedForUrlExceptionMessage = [Verb] {0}: Already defined for {1} -pathOrScriptBlockRequiredExceptionMessage = A Path or ScriptBlock is required for sourcing the Custom access values. -accessMethodAlreadyDefinedExceptionMessage = Access method already defined: {0} -accessMethodNotExistForMergingExceptionMessage = Access method does not exist for merging: {0} -routeAlreadyContainsCustomAccessExceptionMessage = Route '[{0}] {1}' already contains Custom Access with name '{2}' -accessMethodNotExistExceptionMessage = Access method does not exist: {0} -pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = The PathItems feature is not supported in OpenAPI v3.0.x -nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = A non-empty ScriptBlock is required for the Custom authentication scheme. -oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme can only be one of either Basic or Form authentication, but got: {0} -sessionsRequiredForOAuth2WithPKCEExceptionMessage = Sessions are required to use OAuth2 with PKCE -oauth2ClientSecretRequiredExceptionMessage = OAuth2 requires a Client Secret when not using PKCE. -authMethodAlreadyDefinedExceptionMessage = Authentication method already defined: {0} -invalidSchemeForAuthValidatorExceptionMessage = The supplied '{0}' Scheme for the '{1}' authentication validator requires a valid ScriptBlock. -sessionsRequiredForSessionPersistentAuthExceptionMessage = Sessions are required to use session persistent authentication. -oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 requires an Authorize URL to be supplied -authMethodNotExistForMergingExceptionMessage = Authentication method does not exist for merging: {0} -mergeDefaultAuthNotInListExceptionMessage = The MergeDefault Authentication '{0}' is not in the Authentication list supplied. -defaultAuthNotInListExceptionMessage = The Default Authentication '{0}' is not in the Authentication list supplied. -scriptBlockRequiredForMergingUsersExceptionMessage = A Scriptblock for merging multiple authenticated users into 1 object is required When Valid is All. -noDomainServerNameForWindowsAdAuthExceptionMessage = No domain server name has been supplied for Windows AD authentication -sessionsNotConfiguredExceptionMessage = Sessions have not been configured. -windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Windows Local Authentication support is for Windows only. -iisAuthSupportIsForWindowsOnlyExceptionMessage = IIS Authentication support is for Windows only. -noAlgorithmInJwtHeaderExceptionMessage = No algorithm supplied in JWT Header. -invalidJwtSuppliedExceptionMessage = Invalid JWT supplied. -invalidJwtHeaderAlgorithmSuppliedExceptionMessage = Invalid JWT header algorithm supplied. -noJwtSignatureForAlgorithmExceptionMessage = No JWT signature supplied for {0}. -expectedNoJwtSignatureSuppliedExceptionMessage = Expected no JWT signature to be supplied. -invalidJwtSignatureSuppliedExceptionMessage = Invalid JWT signature supplied. -jwtExpiredExceptionMessage = The JWT has expired. -jwtNotYetValidExceptionMessage = The JWT is not yet valid for use. -snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Snapins are only supported on Windows PowerShell. -userFileDoesNotExistExceptionMessage = The user file does not exist: {0} -schemeRequiresValidScriptBlockExceptionMessage = The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock. -oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = The OAuth2 provider does not support the 'code' response_type. -oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = The OAuth2 provider does not support the 'password' grant_type required by using an InnerScheme. -eventAlreadyRegisteredExceptionMessage = {0} event already registered: {1} -noEventRegisteredExceptionMessage = No {0} event registered: {1} -sessionsRequiredForFlashMessagesExceptionMessage = Sessions are required to use Flash messages. -eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = Event Viewer logging only supported on Windows. -nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = A non-empty ScriptBlock is required for the Custom logging output method. -requestLoggingAlreadyEnabledExceptionMessage = Request Logging has already been enabled. -outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = The supplied output Method for Request Logging requires a valid ScriptBlock. -errorLoggingAlreadyEnabledExceptionMessage = Error Logging has already been enabled. -nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = A non-empty ScriptBlock is required for the logging method. -csrfMiddlewareNotInitializedExceptionMessage = CSRF Middleware has not been initialized. -sessionsRequiredForCsrfExceptionMessage = Sessions are required to use CSRF unless you want to use cookies. -middlewareNoLogicSuppliedExceptionMessage = [Middleware]: No logic supplied in ScriptBlock. -parameterHasNoNameExceptionMessage = The Parameter has no name. Please give this component a name using the 'Name' parameter. -reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = The 'pathItems' reusable component feature is not available in OpenAPI v3.0. -noPropertiesMutuallyExclusiveExceptionMessage = The parameter 'NoProperties' is mutually exclusive with 'Properties', 'MinProperties' and 'MaxProperties' -discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = The parameter 'DiscriminatorMapping' can only be used when 'DiscriminatorProperty' is present. -discriminatorIncompatibleWithAllOfExceptionMessage = The parameter 'Discriminator' is incompatible with 'allOf'. -typeCanOnlyBeAssociatedWithObjectExceptionMessage = Type {0} can only be associated with an Object. -showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui is currently only available for Windows PowerShell and PowerShell 7+ on Windows. -nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = A Name is required for the endpoint if the RedirectTo parameter is supplied. -clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = Client certificates are only supported on HTTPS endpoints. -explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = The Explicit TLS mode is only supported on SMTPS and TCPS endpoints. -acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = The Acknowledge message is only supported on SMTP and TCP endpoints. -crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = The CRLF message end check is only supported on TCP endpoints. -mustBeRunningWithAdminPrivilegesExceptionMessage = Must be running with administrator privileges to listen on non-localhost addresses. -certificateSuppliedForNonHttpsWssEndpointExceptionMessage = Certificate supplied for non-HTTPS/WSS endpoint. -websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSockets have not been configured to send signal messages. -noPathSuppliedForRouteExceptionMessage = No Path supplied for the Route. -accessRequiresAuthenticationOnRoutesExceptionMessage = Access requires Authentication to be supplied on Routes. -accessMethodDoesNotExistExceptionMessage = Access method does not exist: {0}. -routeParameterNeedsValidScriptblockExceptionMessage = The Route parameter needs a valid, not empty, scriptblock. -noCommandsSuppliedToConvertToRoutesExceptionMessage = No commands supplied to convert to Routes. -nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = A non-empty ScriptBlock is required to create a Page Route. -sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE can only be configured on requests with an Accept header value of text/event-stream -sseConnectionNameRequiredExceptionMessage = An SSE connection Name is required, either from -Name or `$WebEvent.Sse.Name -sseFailedToBroadcastExceptionMessage = SSE failed to broadcast due to defined SSE broadcast level for {0}: {1} -podeNotInitializedExceptionMessage = Pode has not been initialized. -invalidTaskTypeExceptionMessage = Task type is invalid, expected either [System.Threading.Tasks.Task] or [hashtable] -cannotLockValueTypeExceptionMessage = Cannot lock a [ValueTypes] -cannotLockNullObjectExceptionMessage = Cannot lock an object that is null. -failedToAcquireLockExceptionMessage = Failed to acquire a lock on the object. -cannotUnlockValueTypeExceptionMessage = Cannot unlock a [ValueTypes] -cannotUnlockNullObjectExceptionMessage = Cannot unlock an object that is null. -sessionMiddlewareAlreadyInitializedExceptionMessage = Session Middleware has already been initialized. -customSessionStorageMethodNotImplementedExceptionMessage = The custom session storage does not implement the required '{0}()' method. -secretRequiredForCustomSessionStorageExceptionMessage = A Secret is required when using custom session storage. -noSessionAvailableToSaveExceptionMessage = There is no session available to save. -cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Cannot supply an interval when the parameter 'Every' is set to None. -cannotSupplyIntervalForQuarterExceptionMessage = Cannot supply interval value for every quarter. -cannotSupplyIntervalForYearExceptionMessage = Cannot supply interval value for every year. -secretVaultAlreadyRegisteredExceptionMessage = A Secret Vault with the name '{0}' has already been registered{1}. -secretVaultUnlockExpiryDateInPastExceptionMessage = Secret Vault unlock expiry date is in the past (UTC): {0} -secretAlreadyMountedExceptionMessage = A Secret with the name '{0}' has already been mounted. -credentialsPassedWildcardForHeadersLiteralExceptionMessage = When Credentials is passed, The * wildcard for Headers will be taken as a literal string and not a wildcard. -wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = The * wildcard for Headers is incompatible with the AutoHeaders switch. -wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = The * wildcard for Methods is incompatible with the AutoMethods switch. -invalidAccessControlMaxAgeDurationExceptionMessage = Invalid Access-Control-Max-Age duration supplied: {0}. Should be greater than 0. -noNameForWebSocketDisconnectExceptionMessage = No Name for a WebSocket to disconnect from supplied. -noNameForWebSocketRemoveExceptionMessage = No Name for a WebSocket to remove supplied. -noNameForWebSocketSendMessageExceptionMessage = No Name for a WebSocket to send message to supplied. -noSecretNamedMountedExceptionMessage = No Secret named '{0}' has been mounted. -noNameForWebSocketResetExceptionMessage = No Name for a WebSocket to reset supplied. -schemaValidationRequiresPowerShell610ExceptionMessage = Schema validation required PowerShell version 6.1.0 or greater. -routeParameterCannotBeNullExceptionMessage = The parameter 'Route' cannot be null. -encodingAttributeOnlyAppliesToMultipartExceptionMessage = The encoding attribute only applies to multipart and application/x-www-form-urlencoded request bodies. -testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentchema' need to be enabled using 'Enable-PodeOpenApi -EnableSchemaValidation' -openApiComponentSchemaDoesNotExistExceptionMessage = The OpenApi component schema {0} doesn't exist. -openApiParameterRequiresNameExceptionMessage = The OpenApi parameter requires a name to be specified. -openApiLicenseObjectRequiresNameExceptionMessage = The OpenAPI object 'license' required the property 'name'. Use -LicenseName parameter. -parametersValueOrExternalValueMandatoryExceptionMessage = Parameters 'Value' or 'ExternalValue' are mandatory -parametersMutuallyExclusiveExceptionMessage = Parameters '{0}' and '{1}' are mutually exclusive. -maximumConcurrentWebSocketThreadsInvalidExceptionMessage = Maximum concurrent WebSocket threads must be >=1 but got: {0} -maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = Maximum concurrent WebSocket threads cannot be less than the minimum of {0} but got: {1} -alreadyConnectedToWebSocketExceptionMessage = Already connected to websocket with name '{0}' -failedToConnectToWebSocketExceptionMessage = Failed to connect to websocket: {0} -verbNoLogicPassedExceptionMessage = [Verb] {0}: No logic passed -scriptPathDoesNotExistExceptionMessage = The script path does not exist: {0} -failedToImportModuleExceptionMessage = Failed to import module: {0} -modulePathDoesNotExistExceptionMessage = The module path does not exist: {0} -defaultValueNotBooleanOrEnumExceptionMessage = The default value is not a boolean and is not part of the enum. -propertiesTypeObjectAssociationExceptionMessage = Only properties of type Object can be associated with {0}. -invalidContentTypeForSchemaExceptionMessage = Invalid 'content-type' found for schema: {0} -openApiRequestStyleInvalidForParameterExceptionMessage = OpenApi request Style cannot be {0} for a {1} parameter. -pathParameterRequiresRequiredSwitchExceptionMessage = If the parameter location is 'Path', the switch parameter 'Required' is mandatory. -operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0} has to be unique and cannot be applied to an array. -operationIdMustBeUniqueExceptionMessage = OperationID: {0} has to be unique. -noOpenApiUrlSuppliedExceptionMessage = No OpenAPI URL supplied for {0}. -noTitleSuppliedForPageExceptionMessage = No title supplied for {0} page. -noRoutePathSuppliedForPageExceptionMessage = No route path supplied for {0} page. -swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = This version on Swagger-Editor doesn't support OpenAPI 3.1 -rapidPdfDoesNotSupportOpenApi31ExceptionMessage = The Document tool RapidPdf doesn't support OpenAPI 3.1 -definitionTagNotDefinedExceptionMessage = DefinitionTag {0} does not exist. -scopedVariableNotFoundExceptionMessage = Scoped Variable not found: {0} -noSecretVaultRegisteredExceptionMessage = No Secret Vault with the name '{0}' has been registered. -invalidStrictTransportSecurityDurationExceptionMessage = Invalid Strict-Transport-Security duration supplied: {0}. It should be greater than 0. -durationMustBeZeroOrGreaterExceptionMessage = Duration must be 0 or greater, but got: {0}s -taskAlreadyDefinedExceptionMessage = [Task] {0}: Task already defined. -maximumConcurrentTasksInvalidExceptionMessage = Maximum concurrent tasks must be >=1 but got: {0} -maximumConcurrentTasksLessThanMinimumExceptionMessage = Maximum concurrent tasks cannot be less than the minimum of {0} but got: {1} -taskDoesNotExistExceptionMessage = Task '{0}' does not exist. -cacheStorageNotFoundForRetrieveExceptionMessage = Cache storage with name '{0}' not found when attempting to retrieve cached item '{1}' -cacheStorageNotFoundForSetExceptionMessage = Cache storage with name '{0}' not found when attempting to set cached item '{1}' -cacheStorageNotFoundForExistsExceptionMessage = Cache storage with name '{0}' not found when attempting to check if cached item '{1}' exists. -cacheStorageNotFoundForRemoveExceptionMessage = Cache storage with name '{0}' not found when attempting to remove cached item '{1}' -cacheStorageNotFoundForClearExceptionMessage = Cache storage with name '{0}' not found when attempting to clear the cache. -cacheStorageAlreadyExistsExceptionMessage = Cache Storage with name '{0}' already exists. -pathToIconForGuiDoesNotExistExceptionMessage = Path to the icon for GUI does not exist: {0} -invalidHostnameSuppliedExceptionMessage = Invalid hostname supplied: {0} -endpointAlreadyDefinedExceptionMessage = An endpoint named '{0}' has already been defined. -certificateExpiredExceptionMessage = The certificate '{0}' has expired: {1} -endpointNotDefinedForRedirectingExceptionMessage = An endpoint named '{0}' has not been defined for redirecting. -fileWatcherAlreadyDefinedExceptionMessage = A File Watcher named '{0}' has already been defined. -handlerAlreadyDefinedExceptionMessage = [{0}] {1}: Handler already defined. -maxDaysInvalidExceptionMessage = MaxDays must be 0 or greater, but got: {0} -maxSizeInvalidExceptionMessage = MaxSize must be 0 or greater, but got: {0} -loggingMethodAlreadyDefinedExceptionMessage = Logging method already defined: {0} -loggingMethodRequiresValidScriptBlockExceptionMessage = The supplied output Method for the '{0}' Logging method requires a valid ScriptBlock. -csrfCookieRequiresSecretExceptionMessage = When using cookies for CSRF, a Secret is required. You can either supply a Secret or set the Cookie global secret - (Set-PodeCookieSecret '' -Global) -bodyParserAlreadyDefinedForContentTypeExceptionMessage = A body-parser is already defined for the {0} content-type. -middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: Middleware already defined. -parameterNotSuppliedInRequestExceptionMessage = A parameter called '{0}' was not supplied in the request or has no data available. -noDataForFileUploadedExceptionMessage = No data for file '{0}' was uploaded in the request. -viewsFolderNameAlreadyExistsExceptionMessage = The Views folder name already exists: {0} -viewsPathDoesNotExistExceptionMessage = The Views path does not exist: {0} -timerAlreadyDefinedExceptionMessage = [Timer] {0}: Timer already defined. -timerParameterMustBeGreaterThanZeroExceptionMessage = [Timer] {0}: {1} must be greater than 0. -timerDoesNotExistExceptionMessage = Timer '{0}' does not exist. -mutexAlreadyExistsExceptionMessage = A mutex with the following name already exists: {0} -noMutexFoundExceptionMessage = No mutex found called '{0}' -failedToAcquireMutexOwnershipExceptionMessage = Failed to acquire mutex ownership. Mutex name: {0} -semaphoreAlreadyExistsExceptionMessage = A semaphore with the following name already exists: {0} -failedToAcquireSemaphoreOwnershipExceptionMessage = Failed to acquire semaphore ownership. Semaphore name: {0} -scheduleAlreadyDefinedExceptionMessage = [Schedule] {0}: Schedule already defined. -scheduleCannotHaveNegativeLimitExceptionMessage = [Schedule] {0}: Cannot have a negative limit. -scheduleEndTimeMustBeInFutureExceptionMessage = [Schedule] {0}: The EndTime value must be in the future. -scheduleStartTimeAfterEndTimeExceptionMessage = [Schedule] {0}: Cannot have a StartTime after the EndTime -maximumConcurrentSchedulesInvalidExceptionMessage = Maximum concurrent schedules must be >=1 but got: {0} -maximumConcurrentSchedulesLessThanMinimumExceptionMessage = Maximum concurrent schedules cannot be less than the minimum of {0} but got: {1} -scheduleDoesNotExistExceptionMessage = Schedule '{0}' does not exist. -suppliedDateBeforeScheduleStartTimeExceptionMessage = Supplied date is before the start time of the schedule at {0} -suppliedDateAfterScheduleEndTimeExceptionMessage = Supplied date is after the end time of the schedule at {0} -noSemaphoreFoundExceptionMessage = No semaphore found called '{0}' -noLogicPassedForRouteExceptionMessage = No logic passed for Route: {0} -noPathSuppliedForStaticRouteExceptionMessage = [{0}]: No Path supplied for Static Route. -sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: The Source path supplied for Static Route does not exist: {2} -noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: No logic passed. -moduleDoesNotContainFunctionExceptionMessage = Module {0} does not contain function {1} to convert to a Route. -pageNameShouldBeAlphaNumericExceptionMessage = The Page name should be a valid AlphaNumeric value: {0} -filesHaveChangedMessage = The following files have changed: -multipleEndpointsForGuiMessage = Multiple endpoints defined, only the first will be used for the GUI. -openingGuiMessage = Opening the GUI. -listeningOnEndpointsMessage = Listening on the following {0} endpoint(s) [{1} thread(s)]: -specificationMessage = Specification -documentationMessage = Documentation -restartingServerMessage = Restarting server... -doneMessage = Done -deprecatedTitleVersionDescriptionWarningMessage = WARNING: Title, Version, and Description on 'Enable-PodeOpenApi' are deprecated. Please use 'Add-PodeOAInfo' instead. -undefinedOpenApiReferencesMessage = Undefined OpenAPI References: -definitionTagMessage = Definition {0}: -openApiGenerationDocumentErrorMessage = OpenAPI generation document error: -infoTitleMandatoryMessage = info.title is mandatory. -infoVersionMandatoryMessage = info.version is mandatory. -missingComponentsMessage = Missing component(s) -openApiInfoMessage = OpenAPI Info: -serverLoopingMessage = Server looping every {0}secs -iisShutdownMessage = (IIS Shutdown) -terminatingMessage = Terminating... -eolPowerShellWarningMessage = [WARNING] Pode {0} has not been tested on PowerShell {1}, as it is EOL. -untestedPowerShellVersionWarningMessage = [WARNING] Pode {0} has not been tested on PowerShell {1}, as it was not available when Pode was released. -'@ \ No newline at end of file +@{ + schemaValidationRequiresPowerShell610ExceptionMessage = 'Schema validation required PowerShell version 6.1.0 or greater.' + pathOrScriptBlockRequiredExceptionMessage = 'A Path or ScriptBlock is required for sourcing the Custom access values.' + operationIdMustBeUniqueForArrayExceptionMessage = 'OperationID: {0} has to be unique and cannot be applied to an array.' + endpointNotDefinedForRedirectingExceptionMessage = "An endpoint named '{0}' has not been defined for redirecting." + filesHaveChangedMessage = 'The following files have changed:' + iisAspnetcoreTokenMissingExceptionMessage = 'IIS ASPNETCORE_TOKEN is missing.' + minValueGreaterThanMaxExceptionMessage = 'Min value for {0} should not be greater than the max value.' + noLogicPassedForRouteExceptionMessage = 'No logic passed for Route: {0}' + scriptPathDoesNotExistExceptionMessage = 'The script path does not exist: {0}' + mutexAlreadyExistsExceptionMessage = 'A mutex with the following name already exists: {0}' + listeningOnEndpointsMessage = 'Listening on the following {0} endpoint(s) [{1} thread(s)]:' + unsupportedFunctionInServerlessContextExceptionMessage = 'The {0} function is not supported in a serverless context.' + expectedNoJwtSignatureSuppliedExceptionMessage = 'Expected no JWT signature to be supplied.' + secretAlreadyMountedExceptionMessage = "A Secret with the name '{0}' has already been mounted." + failedToAcquireLockExceptionMessage = 'Failed to acquire a lock on the object.' + noPathSuppliedForStaticRouteExceptionMessage = '[{0}]: No Path supplied for Static Route.' + invalidHostnameSuppliedExceptionMessage = 'Invalid hostname supplied: {0}' + authMethodAlreadyDefinedExceptionMessage = 'Authentication method already defined: {0}' + csrfCookieRequiresSecretExceptionMessage = "When using cookies for CSRF, a Secret is required. You can either supply a Secret or set the Cookie global secret - (Set-PodeCookieSecret '' -Global)" + nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 'A non-empty ScriptBlock is required to create a Page Route.' + noPropertiesMutuallyExclusiveExceptionMessage = "The parameter 'NoProperties' is mutually exclusive with 'Properties', 'MinProperties' and 'MaxProperties'" + incompatiblePodeDllExceptionMessage = 'An existing incompatible Pode.DLL version {0} is loaded. Version {1} is required. Open a new Powershell/pwsh session and retry.' + accessMethodDoesNotExistExceptionMessage = 'Access method does not exist: {0}.' + scheduleAlreadyDefinedExceptionMessage = '[Schedule] {0}: Schedule already defined.' + secondsValueCannotBeZeroOrLessExceptionMessage = 'Seconds value cannot be 0 or less for {0}' + pathToLoadNotFoundExceptionMessage = 'Path to load {0} not found: {1}' + failedToImportModuleExceptionMessage = 'Failed to import module: {0}' + endpointNotExistExceptionMessage = "Endpoint with protocol '{0}' and address '{1}' or local address '{2}' does not exist." + terminatingMessage = 'Terminating...' + noCommandsSuppliedToConvertToRoutesExceptionMessage = 'No commands supplied to convert to Routes.' + invalidTaskTypeExceptionMessage = 'Task type is invalid, expected either [System.Threading.Tasks.Task] or [hashtable]' + alreadyConnectedToWebSocketExceptionMessage = "Already connected to websocket with name '{0}'" + crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = 'The CRLF message end check is only supported on TCP endpoints.' + testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = "'Test-PodeOAComponentchema' need to be enabled using 'Enable-PodeOpenApi -EnableSchemaValidation'" + adModuleNotInstalledExceptionMessage = 'Active Directory module is not installed.' + cronExpressionInvalidExceptionMessage = 'Cron expression should only consist of 5 parts: {0}' + noSessionToSetOnResponseExceptionMessage = 'There is no session available to set on the response.' + valueOutOfRangeExceptionMessage = "Value '{0}' for {1} is invalid, should be between {2} and {3}" + loggingMethodAlreadyDefinedExceptionMessage = 'Logging method already defined: {0}' + noSecretForHmac256ExceptionMessage = 'No secret supplied for HMAC256 hash.' + eolPowerShellWarningMessage = '[WARNING] Pode {0} has not been tested on PowerShell {1}, as it is EOL.' + runspacePoolFailedToLoadExceptionMessage = '{0} RunspacePool failed to load.' + noEventRegisteredExceptionMessage = 'No {0} event registered: {1}' + scheduleCannotHaveNegativeLimitExceptionMessage = '[Schedule] {0}: Cannot have a negative limit.' + openApiRequestStyleInvalidForParameterExceptionMessage = 'OpenApi request Style cannot be {0} for a {1} parameter.' + openApiDocumentNotCompliantExceptionMessage = 'OpenAPI document is not compliant.' + taskDoesNotExistExceptionMessage = "Task '{0}' does not exist." + scopedVariableNotFoundExceptionMessage = 'Scoped Variable not found: {0}' + sessionsRequiredForCsrfExceptionMessage = 'Sessions are required to use CSRF unless you want to use cookies.' + nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 'A non-empty ScriptBlock is required for the logging method.' + credentialsPassedWildcardForHeadersLiteralExceptionMessage = 'When Credentials is passed, The * wildcard for Headers will be taken as a literal string and not a wildcard.' + podeNotInitializedExceptionMessage = 'Pode has not been initialized.' + multipleEndpointsForGuiMessage = 'Multiple endpoints defined, only the first will be used for the GUI.' + operationIdMustBeUniqueExceptionMessage = 'OperationID: {0} has to be unique.' + invalidJsonJwtExceptionMessage = 'Invalid JSON value found in JWT' + noAlgorithmInJwtHeaderExceptionMessage = 'No algorithm supplied in JWT Header.' + openApiVersionPropertyMandatoryExceptionMessage = 'OpenApi Version property is mandatory.' + limitValueCannotBeZeroOrLessExceptionMessage = 'Limit value cannot be 0 or less for {0}' + timerDoesNotExistExceptionMessage = "Timer '{0}' does not exist." + openApiGenerationDocumentErrorMessage = 'OpenAPI generation document error:' + routeAlreadyContainsCustomAccessExceptionMessage = "Route '[{0}] {1}' already contains Custom Access with name '{2}'" + maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 'Maximum concurrent WebSocket threads cannot be less than the minimum of {0} but got: {1}' + middlewareAlreadyDefinedExceptionMessage = '[Middleware] {0}: Middleware already defined.' + invalidAtomCharacterExceptionMessage = 'Invalid atom character: {0}' + cacheStorageNotFoundForRetrieveExceptionMessage = "Cache storage with name '{0}' not found when attempting to retrieve cached item '{1}'" + headerMustHaveNameInEncodingContextExceptionMessage = 'Header must have a name when used in an encoding context.' + moduleDoesNotContainFunctionExceptionMessage = 'Module {0} does not contain function {1} to convert to a Route.' + pathToIconForGuiDoesNotExistExceptionMessage = 'Path to the icon for GUI does not exist: {0}' + noTitleSuppliedForPageExceptionMessage = 'No title supplied for {0} page.' + certificateSuppliedForNonHttpsWssEndpointExceptionMessage = 'Certificate supplied for non-HTTPS/WSS endpoint.' + cannotLockNullObjectExceptionMessage = 'Cannot lock an object that is null.' + showPodeGuiOnlyAvailableOnWindowsExceptionMessage = 'Show-PodeGui is currently only available for Windows PowerShell and PowerShell 7+ on Windows.' + unlockSecretButNoScriptBlockExceptionMessage = 'Unlock secret supplied for custom Secret Vault type, but not Unlock ScriptBlock supplied.' + invalidIpAddressExceptionMessage = 'The IP address supplied is invalid: {0}' + maxDaysInvalidExceptionMessage = 'MaxDays must be 0 or greater, but got: {0}' + noRemoveScriptBlockForVaultExceptionMessage = "No Remove ScriptBlock supplied for removing secrets from the vault '{0}'" + noSecretExpectedForNoSignatureExceptionMessage = 'Expected no secret to be supplied for no signature.' + noCertificateFoundExceptionMessage = "No certificate could be found in {0}{1} for '{2}'" + minValueInvalidExceptionMessage = "Min value '{0}' for {1} is invalid, should be greater than/equal to {2}" + accessRequiresAuthenticationOnRoutesExceptionMessage = 'Access requires Authentication to be supplied on Routes.' + noSecretForHmac384ExceptionMessage = 'No secret supplied for HMAC384 hash.' + windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = 'Windows Local Authentication support is for Windows only.' + definitionTagNotDefinedExceptionMessage = 'DefinitionTag {0} does not exist.' + noComponentInDefinitionExceptionMessage = 'No component of type {0} named {1} is available in the {2} definition.' + noSmtpHandlersDefinedExceptionMessage = 'No SMTP handlers have been defined.' + sessionMiddlewareAlreadyInitializedExceptionMessage = 'Session Middleware has already been initialized.' + reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = "The 'pathItems' reusable component feature is not available in OpenAPI v3.0." + wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 'The * wildcard for Headers is incompatible with the AutoHeaders switch.' + noDataForFileUploadedExceptionMessage = "No data for file '{0}' was uploaded in the request." + sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = 'SSE can only be configured on requests with an Accept header value of text/event-stream' + noSessionAvailableToSaveExceptionMessage = 'There is no session available to save.' + pathParameterRequiresRequiredSwitchExceptionMessage = "If the parameter location is 'Path', the switch parameter 'Required' is mandatory." + noOpenApiUrlSuppliedExceptionMessage = 'No OpenAPI URL supplied for {0}.' + maximumConcurrentSchedulesInvalidExceptionMessage = 'Maximum concurrent schedules must be >=1 but got: {0}' + snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = 'Snapins are only supported on Windows PowerShell.' + eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = 'Event Viewer logging only supported on Windows.' + parametersMutuallyExclusiveExceptionMessage = "Parameters '{0}' and '{1}' are mutually exclusive." + pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 'The PathItems feature is not supported in OpenAPI v3.0.x' + openApiParameterRequiresNameExceptionMessage = 'The OpenApi parameter requires a name to be specified.' + maximumConcurrentTasksLessThanMinimumExceptionMessage = 'Maximum concurrent tasks cannot be less than the minimum of {0} but got: {1}' + noSemaphoreFoundExceptionMessage = "No semaphore found called '{0}'" + singleValueForIntervalExceptionMessage = 'You can only supply a single {0} value when using intervals.' + jwtNotYetValidExceptionMessage = 'The JWT is not yet valid for use.' + verbAlreadyDefinedForUrlExceptionMessage = '[Verb] {0}: Already defined for {1}' + noSecretNamedMountedExceptionMessage = "No Secret named '{0}' has been mounted." + moduleOrVersionNotFoundExceptionMessage = 'Module or version not found on {0}: {1}@{2}' + noScriptBlockSuppliedExceptionMessage = 'No ScriptBlock supplied.' + noSecretVaultRegisteredExceptionMessage = "No Secret Vault with the name '{0}' has been registered." + nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = 'A Name is required for the endpoint if the RedirectTo parameter is supplied.' + openApiLicenseObjectRequiresNameExceptionMessage = "The OpenAPI object 'license' required the property 'name'. Use -LicenseName parameter." + sourcePathDoesNotExistForStaticRouteExceptionMessage = '[{0})] {1}: The Source path supplied for Static Route does not exist: {2}' + noNameForWebSocketDisconnectExceptionMessage = 'No Name for a WebSocket to disconnect from supplied.' + certificateExpiredExceptionMessage = "The certificate '{0}' has expired: {1}" + secretVaultUnlockExpiryDateInPastExceptionMessage = 'Secret Vault unlock expiry date is in the past (UTC): {0}' + invalidExceptionTypeExceptionMessage = 'Exception is of an invalid type, should be either WebException or HttpRequestException, but got: {0}' + invalidSecretValueTypeExceptionMessage = 'Secret value is of an invalid type. Expected types: String, SecureString, HashTable, Byte[], or PSCredential. But got: {0}' + explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 'The Explicit TLS mode is only supported on SMTPS and TCPS endpoints.' + discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = "The parameter 'DiscriminatorMapping' can only be used when 'DiscriminatorProperty' is present." + scriptErrorExceptionMessage = "Error '{0}' in script {1} {2} (line {3}) char {4} executing {5} on {6} object '{7}' Class: {8} BaseClass: {9}" + cannotSupplyIntervalForQuarterExceptionMessage = 'Cannot supply interval value for every quarter.' + scheduleEndTimeMustBeInFutureExceptionMessage = '[Schedule] {0}: The EndTime value must be in the future.' + invalidJwtSignatureSuppliedExceptionMessage = 'Invalid JWT signature supplied.' + noSetScriptBlockForVaultExceptionMessage = "No Set ScriptBlock supplied for updating/creating secrets in the vault '{0}'" + accessMethodNotExistForMergingExceptionMessage = 'Access method does not exist for merging: {0}' + defaultAuthNotInListExceptionMessage = "The Default Authentication '{0}' is not in the Authentication list supplied." + parameterHasNoNameExceptionMessage = "The Parameter has no name. Please give this component a name using the 'Name' parameter." + methodPathAlreadyDefinedForUrlExceptionMessage = '[{0}] {1}: Already defined for {2}' + fileWatcherAlreadyDefinedExceptionMessage = "A File Watcher named '{0}' has already been defined." + noServiceHandlersDefinedExceptionMessage = 'No Service handlers have been defined.' + secretRequiredForCustomSessionStorageExceptionMessage = 'A Secret is required when using custom session storage.' + secretManagementModuleNotInstalledExceptionMessage = 'Microsoft.PowerShell.SecretManagement module not installed.' + noPathSuppliedForRouteExceptionMessage = 'No Path supplied for the Route.' + validationOfAnyOfSchemaNotSupportedExceptionMessage = "Validation of a schema that includes 'anyof' is not supported." + iisAuthSupportIsForWindowsOnlyExceptionMessage = 'IIS Authentication support is for Windows only.' + oauth2InnerSchemeInvalidExceptionMessage = 'OAuth2 InnerScheme can only be one of either Basic or Form authentication, but got: {0}' + noRoutePathSuppliedForPageExceptionMessage = 'No route path supplied for {0} page.' + cacheStorageNotFoundForExistsExceptionMessage = "Cache storage with name '{0}' not found when attempting to check if cached item '{1}' exists." + handlerAlreadyDefinedExceptionMessage = '[{0}] {1}: Handler already defined.' + sessionsNotConfiguredExceptionMessage = 'Sessions have not been configured.' + propertiesTypeObjectAssociationExceptionMessage = 'Only properties of type Object can be associated with {0}.' + sessionsRequiredForSessionPersistentAuthExceptionMessage = 'Sessions are required to use session persistent authentication.' + invalidPathWildcardOrDirectoryExceptionMessage = 'The Path supplied cannot be a wildcard or a directory: {0}' + accessMethodAlreadyDefinedExceptionMessage = 'Access method already defined: {0}' + parametersValueOrExternalValueMandatoryExceptionMessage = "Parameters 'Value' or 'ExternalValue' are mandatory" + maximumConcurrentTasksInvalidExceptionMessage = 'Maximum concurrent tasks must be >=1 but got: {0}' + cannotCreatePropertyWithoutTypeExceptionMessage = 'Cannot create the property because no type is defined.' + authMethodNotExistForMergingExceptionMessage = 'Authentication method does not exist for merging: {0}' + maxValueInvalidExceptionMessage = "Max value '{0}' for {1} is invalid, should be less than/equal to {2}" + endpointAlreadyDefinedExceptionMessage = "An endpoint named '{0}' has already been defined." + eventAlreadyRegisteredExceptionMessage = '{0} event already registered: {1}' + parameterNotSuppliedInRequestExceptionMessage = "A parameter called '{0}' was not supplied in the request or has no data available." + cacheStorageNotFoundForSetExceptionMessage = "Cache storage with name '{0}' not found when attempting to set cached item '{1}'" + methodPathAlreadyDefinedExceptionMessage = '[{0}] {1}: Already defined.' + errorLoggingAlreadyEnabledExceptionMessage = 'Error Logging has already been enabled.' + valueForUsingVariableNotFoundExceptionMessage = "Value for '`$using:{0}' could not be found." + rapidPdfDoesNotSupportOpenApi31ExceptionMessage = "The Document tool RapidPdf doesn't support OpenAPI 3.1" + oauth2ClientSecretRequiredExceptionMessage = 'OAuth2 requires a Client Secret when not using PKCE.' + invalidBase64JwtExceptionMessage = 'Invalid Base64 encoded value found in JWT' + noSessionToCalculateDataHashExceptionMessage = 'No session available to calculate data hash.' + cacheStorageNotFoundForRemoveExceptionMessage = "Cache storage with name '{0}' not found when attempting to remove cached item '{1}'" + csrfMiddlewareNotInitializedExceptionMessage = 'CSRF Middleware has not been initialized.' + infoTitleMandatoryMessage = 'info.title is mandatory.' + typeCanOnlyBeAssociatedWithObjectExceptionMessage = 'Type {0} can only be associated with an Object.' + userFileDoesNotExistExceptionMessage = 'The user file does not exist: {0}' + routeParameterNeedsValidScriptblockExceptionMessage = 'The Route parameter needs a valid, not empty, scriptblock.' + nextTriggerCalculationErrorExceptionMessage = 'Looks like something went wrong trying to calculate the next trigger datetime: {0}' + cannotLockValueTypeExceptionMessage = 'Cannot lock a [ValueTypes]' + failedToCreateOpenSslCertExceptionMessage = 'Failed to create openssl cert: {0}' + jwtExpiredExceptionMessage = 'The JWT has expired.' + openingGuiMessage = 'Opening the GUI.' + multiTypePropertiesRequireOpenApi31ExceptionMessage = 'Multi-type properties require OpenApi Version 3.1 or above.' + noNameForWebSocketRemoveExceptionMessage = 'No Name for a WebSocket to remove supplied.' + maxSizeInvalidExceptionMessage = 'MaxSize must be 0 or greater, but got: {0}' + iisShutdownMessage = '(IIS Shutdown)' + cannotUnlockValueTypeExceptionMessage = 'Cannot unlock a [ValueTypes]' + noJwtSignatureForAlgorithmExceptionMessage = 'No JWT signature supplied for {0}.' + maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 'Maximum concurrent WebSocket threads must be >=1 but got: {0}' + acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 'The Acknowledge message is only supported on SMTP and TCP endpoints.' + failedToConnectToUrlExceptionMessage = 'Failed to connect to URL: {0}' + failedToAcquireMutexOwnershipExceptionMessage = 'Failed to acquire mutex ownership. Mutex name: {0}' + sessionsRequiredForOAuth2WithPKCEExceptionMessage = 'Sessions are required to use OAuth2 with PKCE' + failedToConnectToWebSocketExceptionMessage = 'Failed to connect to websocket: {0}' + unsupportedObjectExceptionMessage = 'Unsupported object' + failedToParseAddressExceptionMessage = "Failed to parse '{0}' as a valid IP/Host:Port address" + mustBeRunningWithAdminPrivilegesExceptionMessage = 'Must be running with administrator privileges to listen on non-localhost addresses.' + specificationMessage = 'Specification' + cacheStorageNotFoundForClearExceptionMessage = "Cache storage with name '{0}' not found when attempting to clear the cache." + restartingServerMessage = 'Restarting server...' + cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = "Cannot supply an interval when the parameter 'Every' is set to None." + unsupportedJwtAlgorithmExceptionMessage = 'The JWT algorithm is not currently supported: {0}' + websocketsNotConfiguredForSignalMessagesExceptionMessage = 'WebSockets have not been configured to send signal messages.' + invalidLogicTypeInHashtableMiddlewareExceptionMessage = 'A Hashtable Middleware supplied has an invalid Logic type. Expected ScriptBlock, but got: {0}' + maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 'Maximum concurrent schedules cannot be less than the minimum of {0} but got: {1}' + failedToAcquireSemaphoreOwnershipExceptionMessage = 'Failed to acquire semaphore ownership. Semaphore name: {0}' + propertiesParameterWithoutNameExceptionMessage = 'The Properties parameters cannot be used if the Property has no name.' + customSessionStorageMethodNotImplementedExceptionMessage = "The custom session storage does not implement the required '{0}()' method." + authenticationMethodDoesNotExistExceptionMessage = 'Authentication method does not exist: {0}' + webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = 'The Webhooks feature is not supported in OpenAPI v3.0.x' + invalidContentTypeForSchemaExceptionMessage = "Invalid 'content-type' found for schema: {0}" + noUnlockScriptBlockForVaultExceptionMessage = "No Unlock ScriptBlock supplied for unlocking the vault '{0}'" + definitionTagMessage = 'Definition {0}:' + failedToOpenRunspacePoolExceptionMessage = 'Failed to open RunspacePool: {0}' + verbNoLogicPassedExceptionMessage = '[Verb] {0}: No logic passed' + noMutexFoundExceptionMessage = "No mutex found called '{0}'" + documentationMessage = 'Documentation' + timerAlreadyDefinedExceptionMessage = '[Timer] {0}: Timer already defined.' + invalidPortExceptionMessage = 'The port cannot be negative: {0}' + viewsFolderNameAlreadyExistsExceptionMessage = 'The Views folder name already exists: {0}' + noNameForWebSocketResetExceptionMessage = 'No Name for a WebSocket to reset supplied.' + mergeDefaultAuthNotInListExceptionMessage = "The MergeDefault Authentication '{0}' is not in the Authentication list supplied." + descriptionRequiredExceptionMessage = 'A Description is required.' + pageNameShouldBeAlphaNumericExceptionMessage = 'The Page name should be a valid AlphaNumeric value: {0}' + defaultValueNotBooleanOrEnumExceptionMessage = 'The default value is not a boolean and is not part of the enum.' + openApiComponentSchemaDoesNotExistExceptionMessage = "The OpenApi component schema {0} doesn't exist." + timerParameterMustBeGreaterThanZeroExceptionMessage = '[Timer] {0}: {1} must be greater than 0.' + taskTimedOutExceptionMessage = 'Task has timed out after {0}ms.' + scheduleStartTimeAfterEndTimeExceptionMessage = '[Schedule] {0}: Cannot have a StartTime after the EndTime' + infoVersionMandatoryMessage = 'info.version is mandatory.' + cannotUnlockNullObjectExceptionMessage = 'Cannot unlock an object that is null.' + nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 'A non-empty ScriptBlock is required for the Custom authentication scheme.' + validationOfOneOfSchemaNotSupportedExceptionMessage = "Validation of a schema that includes 'oneof' is not supported." + routeParameterCannotBeNullExceptionMessage = "The parameter 'Route' cannot be null." + cacheStorageAlreadyExistsExceptionMessage = "Cache Storage with name '{0}' already exists." + loggingMethodRequiresValidScriptBlockExceptionMessage = "The supplied output Method for the '{0}' Logging method requires a valid ScriptBlock." + scopedVariableAlreadyDefinedExceptionMessage = 'Scoped Variable already defined: {0}' + oauth2RequiresAuthorizeUrlExceptionMessage = 'OAuth2 requires an Authorize URL to be supplied' + pathNotExistExceptionMessage = 'Path does not exist: {0}' + noDomainServerNameForWindowsAdAuthExceptionMessage = 'No domain server name has been supplied for Windows AD authentication' + suppliedDateAfterScheduleEndTimeExceptionMessage = 'Supplied date is after the end time of the schedule at {0}' + wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 'The * wildcard for Methods is incompatible with the AutoMethods switch.' + cannotSupplyIntervalForYearExceptionMessage = 'Cannot supply interval value for every year.' + missingComponentsMessage = 'Missing component(s)' + invalidStrictTransportSecurityDurationExceptionMessage = 'Invalid Strict-Transport-Security duration supplied: {0}. It should be greater than 0.' + noSecretForHmac512ExceptionMessage = 'No secret supplied for HMAC512 hash.' + daysInMonthExceededExceptionMessage = '{0} only has {1} days, but {2} was supplied.' + nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 'A non-empty ScriptBlock is required for the Custom logging output method.' + encodingAttributeOnlyAppliesToMultipartExceptionMessage = 'The encoding attribute only applies to multipart and application/x-www-form-urlencoded request bodies.' + suppliedDateBeforeScheduleStartTimeExceptionMessage = 'Supplied date is before the start time of the schedule at {0}' + unlockSecretRequiredExceptionMessage = "An 'UnlockSecret' property is required when using Microsoft.PowerShell.SecretStore" + noLogicPassedForMethodRouteExceptionMessage = '[{0}] {1}: No logic passed.' + bodyParserAlreadyDefinedForContentTypeExceptionMessage = 'A body-parser is already defined for the {0} content-type.' + invalidJwtSuppliedExceptionMessage = 'Invalid JWT supplied.' + sessionsRequiredForFlashMessagesExceptionMessage = 'Sessions are required to use Flash messages.' + outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = 'The supplied output Method for Request Logging requires a valid ScriptBlock.' + semaphoreAlreadyExistsExceptionMessage = 'A semaphore with the following name already exists: {0}' + invalidJwtHeaderAlgorithmSuppliedExceptionMessage = 'Invalid JWT header algorithm supplied.' + oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = "The OAuth2 provider does not support the 'password' grant_type required by using an InnerScheme." + invalidAliasFoundExceptionMessage = 'Invalid {0} alias found: {1}' + scheduleDoesNotExistExceptionMessage = "Schedule '{0}' does not exist." + accessMethodNotExistExceptionMessage = 'Access method does not exist: {0}' + oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = "The OAuth2 provider does not support the 'code' response_type." + untestedPowerShellVersionWarningMessage = '[WARNING] Pode {0} has not been tested on PowerShell {1}, as it was not available when Pode was released.' + secretVaultAlreadyRegisteredAutoImportExceptionMessage = "A Secret Vault with the name '{0}' has already been registered while auto-importing Secret Vaults." + schemeRequiresValidScriptBlockExceptionMessage = "The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock." + serverLoopingMessage = 'Server looping every {0}secs' + certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 'Certificate Thumbprints/Name are only supported on Windows.' + sseConnectionNameRequiredExceptionMessage = "An SSE connection Name is required, either from -Name or `$WebEvent.Sse.Name" + invalidMiddlewareTypeExceptionMessage = 'One of the Middlewares supplied is an invalid type. Expected either a ScriptBlock or Hashtable, but got: {0}' + noSecretForJwtSignatureExceptionMessage = 'No secret supplied for JWT signature.' + modulePathDoesNotExistExceptionMessage = 'The module path does not exist: {0}' + taskAlreadyDefinedExceptionMessage = '[Task] {0}: Task already defined.' + verbAlreadyDefinedExceptionMessage = '[Verb] {0}: Already defined' + clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 'Client certificates are only supported on HTTPS endpoints.' + endpointNameNotExistExceptionMessage = "Endpoint with name '{0}' does not exist." + middlewareNoLogicSuppliedExceptionMessage = '[Middleware]: No logic supplied in ScriptBlock.' + scriptBlockRequiredForMergingUsersExceptionMessage = 'A Scriptblock for merging multiple authenticated users into 1 object is required When Valid is All.' + secretVaultAlreadyRegisteredExceptionMessage = "A Secret Vault with the name '{0}' has already been registered{1}." + deprecatedTitleVersionDescriptionWarningMessage = "WARNING: Title, Version, and Description on 'Enable-PodeOpenApi' are deprecated. Please use 'Add-PodeOAInfo' instead." + undefinedOpenApiReferencesMessage = 'Undefined OpenAPI References:' + doneMessage = 'Done' + swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = "This version on Swagger-Editor doesn't support OpenAPI 3.1" + durationMustBeZeroOrGreaterExceptionMessage = 'Duration must be 0 or greater, but got: {0}s' + viewsPathDoesNotExistExceptionMessage = 'The Views path does not exist: {0}' + discriminatorIncompatibleWithAllOfExceptionMessage = "The parameter 'Discriminator' is incompatible with 'allOf'." + noNameForWebSocketSendMessageExceptionMessage = 'No Name for a WebSocket to send message to supplied.' + hashtableMiddlewareNoLogicExceptionMessage = 'A Hashtable Middleware supplied has no Logic defined.' + openApiInfoMessage = 'OpenAPI Info:' + invalidSchemeForAuthValidatorExceptionMessage = "The supplied '{0}' Scheme for the '{1}' authentication validator requires a valid ScriptBlock." + sseFailedToBroadcastExceptionMessage = 'SSE failed to broadcast due to defined SSE broadcast level for {0}: {1}' + adModuleWindowsOnlyExceptionMessage = 'Active Directory module only available on Windows.' + requestLoggingAlreadyEnabledExceptionMessage = 'Request Logging has already been enabled.' + invalidAccessControlMaxAgeDurationExceptionMessage = 'Invalid Access-Control-Max-Age duration supplied: {0}. Should be greater than 0.' +} + diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 2f3513626..b5e89f0e3 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -1,284 +1,285 @@ -ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyExceptionMessage = El módulo de Active Directory solo está disponible en Windows. -adModuleNotInstalledExceptionMessage = El módulo de Active Directory no está instalado. -secretManagementModuleNotInstalledExceptionMessage = El módulo Microsoft.PowerShell.SecretManagement no está instalado. -secretVaultAlreadyRegisteredAutoImportExceptionMessage = Ya se ha registrado un Bóveda Secreta con el nombre '{0}' al importar automáticamente Bóvedas Secretas. -failedToOpenRunspacePoolExceptionMessage = Error al abrir RunspacePool: {0} -cronExpressionInvalidExceptionMessage = La expresión Cron solo debe consistir en 5 partes: {0} -invalidAliasFoundExceptionMessage = Se encontró un alias {0} no válido: {1} -invalidAtomCharacterExceptionMessage = Carácter atómico no válido: {0} -minValueGreaterThanMaxExceptionMessage = El valor mínimo para {0} no debe ser mayor que el valor máximo. -minValueInvalidExceptionMessage = El valor mínimo '{0}' para {1} no es válido, debe ser mayor o igual a {2} -maxValueInvalidExceptionMessage = El valor máximo '{0}' para {1} no es válido, debe ser menor o igual a {2} -valueOutOfRangeExceptionMessage = El valor '{0}' para {1} no es válido, debe estar entre {2} y {3} -daysInMonthExceededExceptionMessage = {0} solo tiene {1} días, pero se suministró {2}. -nextTriggerCalculationErrorExceptionMessage = Parece que algo salió mal al intentar calcular la siguiente fecha y hora del disparador: {0} -incompatiblePodeDllExceptionMessage = Se ha cargado una versión incompatible existente de Pode.DLL {0}. Se requiere la versión {1}. Abra una nueva sesión de Powershell/pwsh e intente de nuevo. -endpointNotExistExceptionMessage = No existe un punto de conexión con el protocolo '{0}' y la dirección '{1}' o la dirección local '{2}'. -endpointNameNotExistExceptionMessage = No existe un punto de conexión con el nombre '{0}'. -failedToConnectToUrlExceptionMessage = Error al conectar con la URL: {0} -failedToParseAddressExceptionMessage = Error al analizar '{0}' como una dirección IP/Host:Puerto válida -invalidIpAddressExceptionMessage = La dirección IP suministrada no es válida: {0} -invalidPortExceptionMessage = El puerto no puede ser negativo: {0} -pathNotExistExceptionMessage = La ruta no existe: {0} -noSecretForHmac256ExceptionMessage = No se suministró ningún secreto para el hash HMAC256. -noSecretForHmac384ExceptionMessage = No se suministró ningún secreto para el hash HMAC384. -noSecretForHmac512ExceptionMessage = No se suministró ningún secreto para el hash HMAC512. -noSecretForJwtSignatureExceptionMessage = No se suministró ningún secreto para la firma JWT. -noSecretExpectedForNoSignatureExceptionMessage = Se esperaba que no se suministrara ningún secreto para ninguna firma. -unsupportedJwtAlgorithmExceptionMessage = El algoritmo JWT actualmente no es compatible: {0} -invalidBase64JwtExceptionMessage = Valor Base64 no válido encontrado en JWT -invalidJsonJwtExceptionMessage = Valor JSON no válido encontrado en JWT -unsupportedFunctionInServerlessContextExceptionMessage = La función {0} no es compatible en un contexto sin servidor. -invalidPathWildcardOrDirectoryExceptionMessage = La ruta suministrada no puede ser un comodín o un directorio: {0} -invalidExceptionTypeExceptionMessage = La excepción es de un tipo no válido, debe ser WebException o HttpRequestException, pero se obtuvo: {0} -pathToLoadNotFoundExceptionMessage = No se encontró la ruta para cargar {0}: {1} -singleValueForIntervalExceptionMessage = Solo puede suministrar un único valor {0} cuando utiliza intervalos. -scriptErrorExceptionMessage = Error '{0}' en el script {1} {2} (línea {3}) carácter {4} al ejecutar {5} en el objeto {6} '{7}' Clase: {8} ClaseBase: {9} -noScriptBlockSuppliedExceptionMessage = No se suministró ningún ScriptBlock. -iisAspnetcoreTokenMissingExceptionMessage = Falta el token IIS ASPNETCORE_TOKEN. -propertiesParameterWithoutNameExceptionMessage = Los parámetros de propiedades no se pueden usar si la propiedad no tiene nombre. -multiTypePropertiesRequireOpenApi31ExceptionMessage = Las propiedades de tipo múltiple requieren OpenApi versión 3.1 o superior. -openApiVersionPropertyMandatoryExceptionMessage = La propiedad de versión OpenApi es obligatoria. -webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = La función de Webhooks no es compatible con OpenAPI v3.0.x -authenticationMethodDoesNotExistExceptionMessage = El método de autenticación no existe: {0} -unsupportedObjectExceptionMessage = Objeto no compatible -validationOfAnyOfSchemaNotSupportedExceptionMessage = La validación de un esquema que incluye 'anyof' no es compatible. -validationOfOneOfSchemaNotSupportedExceptionMessage = La validación de un esquema que incluye 'oneof' no es compatible. -cannotCreatePropertyWithoutTypeExceptionMessage = No se puede crear la propiedad porque no se ha definido ningún tipo. -headerMustHaveNameInEncodingContextExceptionMessage = El encabezado debe tener un nombre cuando se usa en un contexto de codificación. -descriptionRequiredExceptionMessage = Se requiere una descripción. -openApiDocumentNotCompliantExceptionMessage = El documento OpenAPI no cumple con las normas. -noComponentInDefinitionExceptionMessage = No hay componente del tipo {0} llamado {1} disponible en la definición de {2}. -methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: Ya está definido. -methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: Ya está definido para {2} -invalidMiddlewareTypeExceptionMessage = Uno de los Middlewares suministrados es de un tipo no válido. Se esperaba ScriptBlock o Hashtable, pero se obtuvo: {0} -hashtableMiddlewareNoLogicExceptionMessage = Un Middleware Hashtable suministrado no tiene lógica definida. -invalidLogicTypeInHashtableMiddlewareExceptionMessage = Un Middleware Hashtable suministrado tiene un tipo de lógica no válido. Se esperaba ScriptBlock, pero se obtuvo: {0} -scopedVariableAlreadyDefinedExceptionMessage = La variable con alcance ya está definida: {0} -valueForUsingVariableNotFoundExceptionMessage = No se pudo encontrar el valor para '`$using:{0}'. -unlockSecretRequiredExceptionMessage = Se requiere una propiedad 'UnlockSecret' al usar Microsoft.PowerShell.SecretStore -unlockSecretButNoScriptBlockExceptionMessage = Se suministró un secreto de desbloqueo para el tipo de bóveda secreta personalizada, pero no se suministró ningún ScriptBlock de desbloqueo. -noUnlockScriptBlockForVaultExceptionMessage = No se suministró ningún ScriptBlock de desbloqueo para desbloquear la bóveda '{0}' -noSetScriptBlockForVaultExceptionMessage = No se suministró ningún ScriptBlock de configuración para actualizar/crear secretos en la bóveda '{0}' -noRemoveScriptBlockForVaultExceptionMessage = No se suministró ningún ScriptBlock de eliminación para eliminar secretos de la bóveda '{0}' -invalidSecretValueTypeExceptionMessage = El valor del secreto es de un tipo no válido. Tipos esperados: String, SecureString, HashTable, Byte[], o PSCredential. Pero se obtuvo: {0} -limitValueCannotBeZeroOrLessExceptionMessage = El valor del límite no puede ser 0 o menor para {0} -secondsValueCannotBeZeroOrLessExceptionMessage = El valor en segundos no puede ser 0 o menor para {0} -failedToCreateOpenSslCertExceptionMessage = Error al crear el certificado openssl: {0} -certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Las huellas digitales/nombres de certificados solo son compatibles con Windows. -noCertificateFoundExceptionMessage = No se encontró ningún certificado en {0}\{1} para '{2}' -runspacePoolFailedToLoadExceptionMessage = {0} RunspacePool no se pudo cargar. -noServiceHandlersDefinedExceptionMessage = No se han definido controladores de servicio. -noSessionToSetOnResponseExceptionMessage = No hay ninguna sesión disponible para configurar en la respuesta. -noSessionToCalculateDataHashExceptionMessage = No hay ninguna sesión disponible para calcular el hash de datos. -moduleOrVersionNotFoundExceptionMessage = No se encontró el módulo o la versión en {0}: {1}@{2} -noSmtpHandlersDefinedExceptionMessage = No se han definido controladores SMTP. -taskTimedOutExceptionMessage = La tarea ha agotado el tiempo después de {0}ms. -verbAlreadyDefinedExceptionMessage = [Verbo] {0}: Ya está definido -verbAlreadyDefinedForUrlExceptionMessage = [Verbo] {0}: Ya está definido para {1} -pathOrScriptBlockRequiredExceptionMessage = Se requiere una ruta o un ScriptBlock para obtener los valores de acceso personalizados. -accessMethodAlreadyDefinedExceptionMessage = Método de acceso ya definido: {0} -accessMethodNotExistForMergingExceptionMessage = El método de acceso no existe para fusionarse: {0} -routeAlreadyContainsCustomAccessExceptionMessage = La ruta '[{0}] {1}' ya contiene acceso personalizado con el nombre '{2}' -accessMethodNotExistExceptionMessage = El método de acceso no existe: {0} -pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = La función de elementos de ruta no es compatible con OpenAPI v3.0.x -nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = Se requiere un ScriptBlock no vacío para el esquema de autenticación personalizado. -oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme solo puede ser Basic o Form, pero se obtuvo: {0} -sessionsRequiredForOAuth2WithPKCEExceptionMessage = Se requieren sesiones para usar OAuth2 con PKCE. -oauth2ClientSecretRequiredExceptionMessage = OAuth2 requiere un Client Secret cuando no se usa PKCE. -authMethodAlreadyDefinedExceptionMessage = Método de autenticación ya definido: {0} -invalidSchemeForAuthValidatorExceptionMessage = El esquema '{0}' proporcionado para el validador de autenticación '{1}' requiere un ScriptBlock válido. -sessionsRequiredForSessionPersistentAuthExceptionMessage = Se requieren sesiones para usar la autenticación persistente de sesión. -oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 requiere que se proporcione una URL de autorización. -authMethodNotExistForMergingExceptionMessage = El método de autenticación no existe para la fusión: {0} -mergeDefaultAuthNotInListExceptionMessage = La autenticación MergeDefault '{0}' no está en la lista de autenticación proporcionada. -defaultAuthNotInListExceptionMessage = La autenticación predeterminada '{0}' no está en la lista de autenticación proporcionada. -scriptBlockRequiredForMergingUsersExceptionMessage = Se requiere un ScriptBlock para fusionar múltiples usuarios autenticados en un solo objeto cuando Valid es All. -noDomainServerNameForWindowsAdAuthExceptionMessage = No se ha proporcionado un nombre de servidor de dominio para la autenticación AD de Windows. -sessionsNotConfiguredExceptionMessage = Las sesiones no se han configurado. -windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = El soporte de autenticación local de Windows es solo para Windows. -iisAuthSupportIsForWindowsOnlyExceptionMessage = El soporte de autenticación IIS es solo para Windows. -noAlgorithmInJwtHeaderExceptionMessage = No se proporcionó un algoritmo en el encabezado JWT. -invalidJwtSuppliedExceptionMessage = JWT proporcionado no válido. -invalidJwtHeaderAlgorithmSuppliedExceptionMessage = Algoritmo del encabezado JWT proporcionado no válido. -noJwtSignatureForAlgorithmExceptionMessage = No se proporcionó una firma JWT para {0}. -expectedNoJwtSignatureSuppliedExceptionMessage = No se esperaba que se proporcionara una firma JWT. -invalidJwtSignatureSuppliedExceptionMessage = Firma JWT proporcionada no válida. -jwtExpiredExceptionMessage = El JWT ha expirado. -jwtNotYetValidExceptionMessage = El JWT aún no es válido. -snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Los Snapins solo son compatibles con Windows PowerShell. -userFileDoesNotExistExceptionMessage = El archivo de usuario no existe: {0} -schemeRequiresValidScriptBlockExceptionMessage = El esquema proporcionado para el validador de autenticación '{0}' requiere un ScriptBlock válido. -oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = El proveedor de OAuth2 no admite el tipo de respuesta 'code'. -oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = El proveedor de OAuth2 no admite el tipo de concesión 'password' requerido al usar un InnerScheme. -eventAlreadyRegisteredExceptionMessage = Evento {0} ya registrado: {1} -noEventRegisteredExceptionMessage = No hay evento {0} registrado: {1} -sessionsRequiredForFlashMessagesExceptionMessage = Se requieren sesiones para usar mensajes Flash. -eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = El registro en el Visor de Eventos solo se admite en Windows. -nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = Se requiere un ScriptBlock no vacío para el método de salida de registro personalizado. -requestLoggingAlreadyEnabledExceptionMessage = El registro de solicitudes ya está habilitado. -outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = El método de salida proporcionado para el registro de solicitudes requiere un ScriptBlock válido. -errorLoggingAlreadyEnabledExceptionMessage = El registro de errores ya está habilitado. -nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = Se requiere un ScriptBlock no vacío para el método de registro. -csrfMiddlewareNotInitializedExceptionMessage = El Middleware CSRF no se ha inicializado. -sessionsRequiredForCsrfExceptionMessage = Se requieren sesiones para usar CSRF a menos que desee usar cookies. -middlewareNoLogicSuppliedExceptionMessage = [Middleware]: No se suministró lógica en el ScriptBlock. -parameterHasNoNameExceptionMessage = El parámetro no tiene nombre. Asigne un nombre a este componente usando el parámetro 'Name'. -reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = La característica del componente reutilizable 'pathItems' no está disponible en OpenAPI v3.0. -noPropertiesMutuallyExclusiveExceptionMessage = El parámetro 'NoProperties' es mutuamente excluyente con 'Properties', 'MinProperties' y 'MaxProperties'. -discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = El parámetro 'DiscriminatorMapping' solo se puede usar cuando está presente la propiedad 'DiscriminatorProperty'. -discriminatorIncompatibleWithAllOfExceptionMessage = El parámetro 'Discriminator' es incompatible con 'allOf'. -typeCanOnlyBeAssociatedWithObjectExceptionMessage = El tipo {0} solo se puede asociar con un Objeto. -showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui actualmente solo está disponible para Windows PowerShell y PowerShell 7+ en Windows. -nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = Se requiere un nombre para el endpoint si se proporciona el parámetro RedirectTo. -clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = Los certificados de cliente solo son compatibles con endpoints HTTPS. -explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = El modo TLS explícito solo es compatible con endpoints SMTPS y TCPS. -acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = El mensaje de reconocimiento solo es compatible con endpoints SMTP y TCP. -crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = La verificación de final de mensaje CRLF solo es compatible con endpoints TCP. -mustBeRunningWithAdminPrivilegesExceptionMessage = Debe estar ejecutándose con privilegios de administrador para escuchar en direcciones que no sean localhost. -certificateSuppliedForNonHttpsWssEndpointExceptionMessage = Certificado proporcionado para un endpoint que no es HTTPS/WSS. -websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSockets no están configurados para enviar mensajes de señal. -noPathSuppliedForRouteExceptionMessage = No se proporcionó una ruta para la Ruta. -accessRequiresAuthenticationOnRoutesExceptionMessage = El acceso requiere autenticación en las rutas. -accessMethodDoesNotExistExceptionMessage = El método de acceso no existe: {0}. -routeParameterNeedsValidScriptblockExceptionMessage = El parámetro Route necesita un ScriptBlock válido y no vacío. -noCommandsSuppliedToConvertToRoutesExceptionMessage = No se proporcionaron comandos para convertir a Rutas. -nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Se requiere un ScriptBlock no vacío para crear una Ruta de Página. -sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE solo se puede configurar en solicitudes con un valor de encabezado Accept de text/event-stream. -sseConnectionNameRequiredExceptionMessage = Se requiere un nombre de conexión SSE, ya sea de -Name o $`$WebEvent.Sse.Name -sseFailedToBroadcastExceptionMessage = SSE no pudo transmitir debido al nivel de transmisión SSE definido para {0}: {1}. -podeNotInitializedExceptionMessage = Pode no se ha inicializado. -invalidTaskTypeExceptionMessage = El tipo de tarea no es válido, se esperaba [System.Threading.Tasks.Task] o [hashtable]. -cannotLockValueTypeExceptionMessage = No se puede bloquear un [ValueTypes]. -cannotLockNullObjectExceptionMessage = No se puede bloquear un objeto nulo. -failedToAcquireLockExceptionMessage = No se pudo adquirir un bloqueo en el objeto. -cannotUnlockValueTypeExceptionMessage = No se puede desbloquear un [ValueTypes]. -cannotUnlockNullObjectExceptionMessage = No se puede desbloquear un objeto nulo. -sessionMiddlewareAlreadyInitializedExceptionMessage = El Middleware de Sesión ya se ha inicializado. -customSessionStorageMethodNotImplementedExceptionMessage = El almacenamiento de sesión personalizado no implementa el método requerido '{0}()'. -secretRequiredForCustomSessionStorageExceptionMessage = Se requiere un secreto cuando se utiliza el almacenamiento de sesión personalizado. -noSessionAvailableToSaveExceptionMessage = No hay sesión disponible para guardar. -cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = No se puede proporcionar un intervalo cuando el parámetro 'Every' está configurado en None. -cannotSupplyIntervalForQuarterExceptionMessage = No se puede proporcionar un valor de intervalo para cada trimestre. -cannotSupplyIntervalForYearExceptionMessage = No se puede proporcionar un valor de intervalo para cada año. -secretVaultAlreadyRegisteredExceptionMessage = Un Cofre de Secretos con el nombre '{0}' ya ha sido registrado{1}. -secretVaultUnlockExpiryDateInPastExceptionMessage = La fecha de expiración para desbloquear el Cofre de Secretos está en el pasado (UTC): {0} -secretAlreadyMountedExceptionMessage = Un Secreto con el nombre '{0}' ya ha sido montado. -credentialsPassedWildcardForHeadersLiteralExceptionMessage = Cuando se pasan las Credenciales, el comodín * para los Encabezados se tomará como una cadena literal y no como un comodín. -wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = El comodín * para los Encabezados es incompatible con el interruptor AutoHeaders. -wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = El comodín * para los Métodos es incompatible con el interruptor AutoMethods. -invalidAccessControlMaxAgeDurationExceptionMessage = Duración inválida para Access-Control-Max-Age proporcionada: {0}. Debe ser mayor que 0. -noNameForWebSocketDisconnectExceptionMessage = No se proporcionó ningún nombre para desconectar el WebSocket. -noNameForWebSocketRemoveExceptionMessage = No se proporcionó ningún nombre para eliminar el WebSocket. -noNameForWebSocketSendMessageExceptionMessage = No se proporcionó ningún nombre para enviar un mensaje al WebSocket. -noSecretNamedMountedExceptionMessage = No se ha montado ningún Secreto con el nombre '{0}'. -noNameForWebSocketResetExceptionMessage = No se proporcionó ningún nombre para restablecer el WebSocket. -schemaValidationRequiresPowerShell610ExceptionMessage = La validación del esquema requiere PowerShell versión 6.1.0 o superior. -routeParameterCannotBeNullExceptionMessage = El parámetro 'Route' no puede ser nulo. -encodingAttributeOnlyAppliesToMultipartExceptionMessage = El atributo de codificación solo se aplica a cuerpos de solicitud multipart y application/x-www-form-urlencoded. -testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema' necesita ser habilitado usando 'Enable-PodeOpenApi -EnableSchemaValidation' -openApiComponentSchemaDoesNotExistExceptionMessage = El esquema del componente OpenApi {0} no existe. -openApiParameterRequiresNameExceptionMessage = El parámetro OpenApi requiere un nombre especificado. -openApiLicenseObjectRequiresNameExceptionMessage = El objeto OpenAPI 'license' requiere la propiedad 'name'. Use el parámetro -LicenseName. -parametersValueOrExternalValueMandatoryExceptionMessage = Los parámetros 'Value' o 'ExternalValue' son obligatorios. -parametersMutuallyExclusiveExceptionMessage = Los parámetros '{0}' y '{1}' son mutuamente excluyentes. -maximumConcurrentWebSocketThreadsInvalidExceptionMessage = El número máximo de hilos concurrentes de WebSocket debe ser >=1, pero se obtuvo: {0} -maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = El número máximo de hilos concurrentes de WebSocket no puede ser menor que el mínimo de {0}, pero se obtuvo: {1} -alreadyConnectedToWebSocketExceptionMessage = Ya conectado al WebSocket con el nombre '{0}' -failedToConnectToWebSocketExceptionMessage = Error al conectar con el WebSocket: {0} -verbNoLogicPassedExceptionMessage = [Verbo] {0}: No se pasó ninguna lógica -scriptPathDoesNotExistExceptionMessage = La ruta del script no existe: {0} -failedToImportModuleExceptionMessage = Error al importar el módulo: {0} -modulePathDoesNotExistExceptionMessage = La ruta del módulo no existe: {0} -defaultValueNotBooleanOrEnumExceptionMessage = El valor predeterminado no es un booleano y no forma parte del enum. -propertiesTypeObjectAssociationExceptionMessage = Solo las propiedades de tipo Objeto pueden estar asociadas con {0}. -invalidContentTypeForSchemaExceptionMessage = 'content-type' inválido encontrado para el esquema: {0} -openApiRequestStyleInvalidForParameterExceptionMessage = El estilo de la solicitud OpenApi no puede ser {0} para un parámetro {1}. -pathParameterRequiresRequiredSwitchExceptionMessage = Si la ubicación del parámetro es 'Path', el parámetro switch 'Required' es obligatorio. -operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0} debe ser único y no puede aplicarse a un array. -operationIdMustBeUniqueExceptionMessage = OperationID: {0} debe ser único. -noOpenApiUrlSuppliedExceptionMessage = No se proporcionó URL de OpenAPI para {0}. -noTitleSuppliedForPageExceptionMessage = No se proporcionó título para la página {0}. -noRoutePathSuppliedForPageExceptionMessage = No se proporcionó ruta de acceso para la página {0}. -swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = Esta versión de Swagger-Editor no admite OpenAPI 3.1 -rapidPdfDoesNotSupportOpenApi31ExceptionMessage = La herramienta de documentación RapidPdf no admite OpenAPI 3.1 -definitionTagNotDefinedExceptionMessage = La etiqueta de definición {0} no está definida. -scopedVariableNotFoundExceptionMessage = Variable de alcance no encontrada: {0} -noSecretVaultRegisteredExceptionMessage = No se ha registrado un Cofre de Secretos con el nombre '{0}'. -invalidStrictTransportSecurityDurationExceptionMessage = Duración de Strict-Transport-Security no válida proporcionada: {0}. Debe ser mayor que 0. -durationMustBeZeroOrGreaterExceptionMessage = La duración debe ser igual o mayor a 0, pero se obtuvo: {0}s -taskAlreadyDefinedExceptionMessage = [Tarea] {0}: Tarea ya definida. -maximumConcurrentTasksInvalidExceptionMessage = El número máximo de tareas concurrentes debe ser >=1, pero se obtuvo: {0} -maximumConcurrentTasksLessThanMinimumExceptionMessage = El número máximo de tareas concurrentes no puede ser menor que el mínimo de {0}, pero se obtuvo: {1} -taskDoesNotExistExceptionMessage = La tarea '{0}' no existe. -cacheStorageNotFoundForRetrieveExceptionMessage = No se encontró el almacenamiento en caché con el nombre '{0}' al intentar recuperar el elemento en caché '{1}'. -cacheStorageNotFoundForSetExceptionMessage = No se encontró el almacenamiento en caché con el nombre '{0}' al intentar establecer el elemento en caché '{1}'. -cacheStorageNotFoundForExistsExceptionMessage = No se encontró el almacenamiento en caché con el nombre '{0}' al intentar comprobar si el elemento en caché '{1}' existe. -cacheStorageNotFoundForRemoveExceptionMessage = No se encontró el almacenamiento en caché con el nombre '{0}' al intentar eliminar el elemento en caché '{1}'. -cacheStorageNotFoundForClearExceptionMessage = No se encontró el almacenamiento en caché con el nombre '{0}' al intentar vaciar la caché. -cacheStorageAlreadyExistsExceptionMessage = Ya existe un almacenamiento en caché con el nombre '{0}'. -pathToIconForGuiDoesNotExistExceptionMessage = La ruta del icono para la GUI no existe: {0} -invalidHostnameSuppliedExceptionMessage = Nombre de host no válido proporcionado: {0} -endpointAlreadyDefinedExceptionMessage = Ya se ha definido un punto de conexión llamado '{0}'. -certificateExpiredExceptionMessage = El certificado '{0}' ha expirado: {1} -endpointNotDefinedForRedirectingExceptionMessage = No se ha definido un punto de conexión llamado '{0}' para la redirección. -fileWatcherAlreadyDefinedExceptionMessage = Un Observador de Archivos llamado '{0}' ya ha sido definido. -handlerAlreadyDefinedExceptionMessage = [{0}] {1}: Manejador ya definido. -maxDaysInvalidExceptionMessage = MaxDays debe ser igual o mayor que 0, pero se obtuvo: {0} -maxSizeInvalidExceptionMessage = MaxSize debe ser igual o mayor que 0, pero se obtuvo: {0} -loggingMethodAlreadyDefinedExceptionMessage = Método de registro ya definido: {0} -loggingMethodRequiresValidScriptBlockExceptionMessage = El método de salida proporcionado para el método de registro '{0}' requiere un ScriptBlock válido. -csrfCookieRequiresSecretExceptionMessage = Al usar cookies para CSRF, se requiere un Secreto. Puedes proporcionar un Secreto o establecer el secreto global de la Cookie - (Set-PodeCookieSecret '' -Global) -bodyParserAlreadyDefinedForContentTypeExceptionMessage = Un analizador de cuerpo ya está definido para el tipo de contenido {0}. -middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: Middleware ya definido. -parameterNotSuppliedInRequestExceptionMessage = No se ha proporcionado un parámetro llamado '{0}' en la solicitud o no hay datos disponibles. -noDataForFileUploadedExceptionMessage = No se han subido datos para el archivo '{0}' en la solicitud. -viewsFolderNameAlreadyExistsExceptionMessage = El nombre de la carpeta Views ya existe: {0} -viewsPathDoesNotExistExceptionMessage = La ruta de las Views no existe: {0} -timerAlreadyDefinedExceptionMessage = [Temporizador] {0}: Temporizador ya definido. -timerParameterMustBeGreaterThanZeroExceptionMessage = [Temporizador] {0}: {1} debe ser mayor que 0. -timerDoesNotExistExceptionMessage = El temporizador '{0}' no existe. -mutexAlreadyExistsExceptionMessage = Ya existe un mutex con el siguiente nombre: {0} -noMutexFoundExceptionMessage = No se encontró ningún mutex llamado '{0}' -failedToAcquireMutexOwnershipExceptionMessage = No se pudo adquirir la propiedad del mutex. Nombre del mutex: {0} -semaphoreAlreadyExistsExceptionMessage = Ya existe un semáforo con el siguiente nombre: {0} -failedToAcquireSemaphoreOwnershipExceptionMessage = No se pudo adquirir la propiedad del semáforo. Nombre del semáforo: {0} -scheduleAlreadyDefinedExceptionMessage = [Horario] {0}: Horario ya definido. -scheduleCannotHaveNegativeLimitExceptionMessage = [Horario] {0}: No puede tener un límite negativo. -scheduleEndTimeMustBeInFutureExceptionMessage = [Horario] {0}: El valor de EndTime debe estar en el futuro. -scheduleStartTimeAfterEndTimeExceptionMessage = [Horario] {0}: No puede tener un 'StartTime' después del 'EndTime' -maximumConcurrentSchedulesInvalidExceptionMessage = Los horarios simultáneos máximos deben ser >=1 pero se obtuvo: {0} -maximumConcurrentSchedulesLessThanMinimumExceptionMessage = Los horarios simultáneos máximos no pueden ser inferiores al mínimo de {0} pero se obtuvo: {1} -scheduleDoesNotExistExceptionMessage = El horario '{0}' no existe. -suppliedDateBeforeScheduleStartTimeExceptionMessage = La fecha proporcionada es anterior a la hora de inicio del horario en {0} -suppliedDateAfterScheduleEndTimeExceptionMessage = La fecha proporcionada es posterior a la hora de finalización del horario en {0} -noSemaphoreFoundExceptionMessage = No se encontró ningún semáforo llamado '{0}' -noLogicPassedForRouteExceptionMessage = No se pasó lógica para la Ruta: {0} -noPathSuppliedForStaticRouteExceptionMessage = [{0}]: No se proporcionó una ruta para la Ruta estática. -sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: La ruta de origen proporcionada para la Ruta estática no existe: {2} -noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: No se pasó lógica. -moduleDoesNotContainFunctionExceptionMessage = El módulo {0} no contiene la función {1} para convertir en una Ruta. -pageNameShouldBeAlphaNumericExceptionMessage = El nombre de la página debe ser un valor alfanumérico válido: {0} -filesHaveChangedMessage = Los siguientes archivos han cambiado: -multipleEndpointsForGuiMessage = Se han definido múltiples puntos de conexión, solo se usará el primero para la GUI. -openingGuiMessage = Abriendo la GUI. -listeningOnEndpointsMessage = Escuchando en los siguientes {0} punto(s) de conexión [{1} hilo(s)]: -specificationMessage = Especificación -documentationMessage = Documentación -restartingServerMessage = Reiniciando el servidor... -doneMessage = Hecho -deprecatedTitleVersionDescriptionWarningMessage = ADVERTENCIA: Título, Versión y Descripción en 'Enable-PodeOpenApi' están obsoletos. Utilice 'Add-PodeOAInfo' en su lugar. -undefinedOpenApiReferencesMessage = Referencias OpenAPI indefinidas: -definitionTagMessage = Definición {0}: -openApiGenerationDocumentErrorMessage = Error en el documento de generación de OpenAPI: -infoTitleMandatoryMessage = info.title es obligatorio. -infoVersionMandatoryMessage = info.version es obligatorio. -missingComponentsMessage = Componente(s) faltante(s) -openApiInfoMessage = Información OpenAPI: -serverLoopingMessage = Bucle del servidor cada {0} segundos -iisShutdownMessage = (Apagado de IIS) -terminatingMessage = Terminando... -eolPowerShellWarningMessage = [ADVERTENCIA] Pode {0} no se ha probado en PowerShell {1}, ya que está en fin de vida. -untestedPowerShellVersionWarningMessage = [ADVERTENCIA] Pode {0} no se ha probado en PowerShell {1}, ya que no estaba disponible cuando se lanzó Pode. -'@ \ No newline at end of file +@{ + schemaValidationRequiresPowerShell610ExceptionMessage = 'La validación del esquema requiere PowerShell versión 6.1.0 o superior.' + pathOrScriptBlockRequiredExceptionMessage = 'Se requiere una ruta o un ScriptBlock para obtener los valores de acceso personalizados.' + operationIdMustBeUniqueForArrayExceptionMessage = 'OperationID: {0} debe ser único y no puede aplicarse a un array.' + endpointNotDefinedForRedirectingExceptionMessage = "No se ha definido un punto de conexión llamado '{0}' para la redirección." + filesHaveChangedMessage = 'Los siguientes archivos han cambiado:' + iisAspnetcoreTokenMissingExceptionMessage = 'Falta el token IIS ASPNETCORE_TOKEN.' + minValueGreaterThanMaxExceptionMessage = 'El valor mínimo para {0} no debe ser mayor que el valor máximo.' + noLogicPassedForRouteExceptionMessage = 'No se pasó lógica para la Ruta: {0}' + scriptPathDoesNotExistExceptionMessage = 'La ruta del script no existe: {0}' + mutexAlreadyExistsExceptionMessage = 'Ya existe un mutex con el siguiente nombre: {0}' + listeningOnEndpointsMessage = 'Escuchando en los siguientes {0} punto(s) de conexión [{1} hilo(s)]:' + unsupportedFunctionInServerlessContextExceptionMessage = 'La función {0} no es compatible en un contexto sin servidor.' + expectedNoJwtSignatureSuppliedExceptionMessage = 'No se esperaba que se proporcionara una firma JWT.' + secretAlreadyMountedExceptionMessage = "Un Secreto con el nombre '{0}' ya ha sido montado." + failedToAcquireLockExceptionMessage = 'No se pudo adquirir un bloqueo en el objeto.' + noPathSuppliedForStaticRouteExceptionMessage = '[{0}]: No se proporcionó una ruta para la Ruta estática.' + invalidHostnameSuppliedExceptionMessage = 'Nombre de host no válido proporcionado: {0}' + authMethodAlreadyDefinedExceptionMessage = 'Método de autenticación ya definido: {0}' + csrfCookieRequiresSecretExceptionMessage = "Al usar cookies para CSRF, se requiere un Secreto. Puedes proporcionar un Secreto o establecer el secreto global de la Cookie - (Set-PodeCookieSecret '' -Global)" + nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 'Se requiere un ScriptBlock no vacío para crear una Ruta de Página.' + noPropertiesMutuallyExclusiveExceptionMessage = "El parámetro 'NoProperties' es mutuamente excluyente con 'Properties', 'MinProperties' y 'MaxProperties'." + incompatiblePodeDllExceptionMessage = 'Se ha cargado una versión incompatible existente de Pode.DLL {0}. Se requiere la versión {1}. Abra una nueva sesión de Powershell/pwsh e intente de nuevo.' + accessMethodDoesNotExistExceptionMessage = 'El método de acceso no existe: {0}.' + scheduleAlreadyDefinedExceptionMessage = '[Horario] {0}: Horario ya definido.' + secondsValueCannotBeZeroOrLessExceptionMessage = 'El valor en segundos no puede ser 0 o menor para {0}' + pathToLoadNotFoundExceptionMessage = 'No se encontró la ruta para cargar {0}: {1}' + failedToImportModuleExceptionMessage = 'Error al importar el módulo: {0}' + endpointNotExistExceptionMessage = "No existe un punto de conexión con el protocolo '{0}' y la dirección '{1}' o la dirección local '{2}'." + terminatingMessage = 'Terminando...' + noCommandsSuppliedToConvertToRoutesExceptionMessage = 'No se proporcionaron comandos para convertir a Rutas.' + invalidTaskTypeExceptionMessage = 'El tipo de tarea no es válido, se esperaba [System.Threading.Tasks.Task] o [hashtable].' + alreadyConnectedToWebSocketExceptionMessage = "Ya conectado al WebSocket con el nombre '{0}'" + crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = 'La verificación de final de mensaje CRLF solo es compatible con endpoints TCP.' + testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = "'Test-PodeOAComponentSchema' necesita ser habilitado usando 'Enable-PodeOpenApi -EnableSchemaValidation'" + adModuleNotInstalledExceptionMessage = 'El módulo de Active Directory no está instalado.' + cronExpressionInvalidExceptionMessage = 'La expresión Cron solo debe consistir en 5 partes: {0}' + noSessionToSetOnResponseExceptionMessage = 'No hay ninguna sesión disponible para configurar en la respuesta.' + valueOutOfRangeExceptionMessage = "El valor '{0}' para {1} no es válido, debe estar entre {2} y {3}" + loggingMethodAlreadyDefinedExceptionMessage = 'Método de registro ya definido: {0}' + noSecretForHmac256ExceptionMessage = 'No se suministró ningún secreto para el hash HMAC256.' + eolPowerShellWarningMessage = '[ADVERTENCIA] Pode {0} no se ha probado en PowerShell {1}, ya que está en fin de vida.' + runspacePoolFailedToLoadExceptionMessage = '{0} RunspacePool no se pudo cargar.' + noEventRegisteredExceptionMessage = 'No hay evento {0} registrado: {1}' + scheduleCannotHaveNegativeLimitExceptionMessage = '[Horario] {0}: No puede tener un límite negativo.' + openApiRequestStyleInvalidForParameterExceptionMessage = 'El estilo de la solicitud OpenApi no puede ser {0} para un parámetro {1}.' + openApiDocumentNotCompliantExceptionMessage = 'El documento OpenAPI no cumple con las normas.' + taskDoesNotExistExceptionMessage = "La tarea '{0}' no existe." + scopedVariableNotFoundExceptionMessage = 'Variable de alcance no encontrada: {0}' + sessionsRequiredForCsrfExceptionMessage = 'Se requieren sesiones para usar CSRF a menos que desee usar cookies.' + nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 'Se requiere un ScriptBlock no vacío para el método de registro.' + credentialsPassedWildcardForHeadersLiteralExceptionMessage = 'Cuando se pasan las Credenciales, el comodín * para los Encabezados se tomará como una cadena literal y no como un comodín.' + podeNotInitializedExceptionMessage = 'Pode no se ha inicializado.' + multipleEndpointsForGuiMessage = 'Se han definido múltiples puntos de conexión, solo se usará el primero para la GUI.' + operationIdMustBeUniqueExceptionMessage = 'OperationID: {0} debe ser único.' + invalidJsonJwtExceptionMessage = 'Valor JSON no válido encontrado en JWT' + noAlgorithmInJwtHeaderExceptionMessage = 'No se proporcionó un algoritmo en el encabezado JWT.' + openApiVersionPropertyMandatoryExceptionMessage = 'La propiedad de versión OpenApi es obligatoria.' + limitValueCannotBeZeroOrLessExceptionMessage = 'El valor del límite no puede ser 0 o menor para {0}' + timerDoesNotExistExceptionMessage = "El temporizador '{0}' no existe." + openApiGenerationDocumentErrorMessage = 'Error en el documento de generación de OpenAPI:' + routeAlreadyContainsCustomAccessExceptionMessage = "La ruta '[{0}] {1}' ya contiene acceso personalizado con el nombre '{2}'" + maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 'El número máximo de hilos concurrentes de WebSocket no puede ser menor que el mínimo de {0}, pero se obtuvo: {1}' + middlewareAlreadyDefinedExceptionMessage = '[Middleware] {0}: Middleware ya definido.' + invalidAtomCharacterExceptionMessage = 'Carácter atómico no válido: {0}' + cacheStorageNotFoundForRetrieveExceptionMessage = "No se encontró el almacenamiento en caché con el nombre '{0}' al intentar recuperar el elemento en caché '{1}'." + headerMustHaveNameInEncodingContextExceptionMessage = 'El encabezado debe tener un nombre cuando se usa en un contexto de codificación.' + moduleDoesNotContainFunctionExceptionMessage = 'El módulo {0} no contiene la función {1} para convertir en una Ruta.' + pathToIconForGuiDoesNotExistExceptionMessage = 'La ruta del icono para la GUI no existe: {0}' + noTitleSuppliedForPageExceptionMessage = 'No se proporcionó título para la página {0}.' + certificateSuppliedForNonHttpsWssEndpointExceptionMessage = 'Certificado proporcionado para un endpoint que no es HTTPS/WSS.' + cannotLockNullObjectExceptionMessage = 'No se puede bloquear un objeto nulo.' + showPodeGuiOnlyAvailableOnWindowsExceptionMessage = 'Show-PodeGui actualmente solo está disponible para Windows PowerShell y PowerShell 7+ en Windows.' + unlockSecretButNoScriptBlockExceptionMessage = 'Se suministró un secreto de desbloqueo para el tipo de bóveda secreta personalizada, pero no se suministró ningún ScriptBlock de desbloqueo.' + invalidIpAddressExceptionMessage = 'La dirección IP suministrada no es válida: {0}' + maxDaysInvalidExceptionMessage = 'MaxDays debe ser igual o mayor que 0, pero se obtuvo: {0}' + noRemoveScriptBlockForVaultExceptionMessage = "No se suministró ningún ScriptBlock de eliminación para eliminar secretos de la bóveda '{0}'" + noSecretExpectedForNoSignatureExceptionMessage = 'Se esperaba que no se suministrara ningún secreto para ninguna firma.' + noCertificateFoundExceptionMessage = "No se encontró ningún certificado en {0}{1} para '{2}'" + minValueInvalidExceptionMessage = "El valor mínimo '{0}' para {1} no es válido, debe ser mayor o igual a {2}" + accessRequiresAuthenticationOnRoutesExceptionMessage = 'El acceso requiere autenticación en las rutas.' + noSecretForHmac384ExceptionMessage = 'No se suministró ningún secreto para el hash HMAC384.' + windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = 'El soporte de autenticación local de Windows es solo para Windows.' + definitionTagNotDefinedExceptionMessage = 'La etiqueta de definición {0} no está definida.' + noComponentInDefinitionExceptionMessage = 'No hay componente del tipo {0} llamado {1} disponible en la definición de {2}.' + noSmtpHandlersDefinedExceptionMessage = 'No se han definido controladores SMTP.' + sessionMiddlewareAlreadyInitializedExceptionMessage = 'El Middleware de Sesión ya se ha inicializado.' + reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = "La característica del componente reutilizable 'pathItems' no está disponible en OpenAPI v3.0." + wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 'El comodín * para los Encabezados es incompatible con el interruptor AutoHeaders.' + noDataForFileUploadedExceptionMessage = "No se han subido datos para el archivo '{0}' en la solicitud." + sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = 'SSE solo se puede configurar en solicitudes con un valor de encabezado Accept de text/event-stream.' + noSessionAvailableToSaveExceptionMessage = 'No hay sesión disponible para guardar.' + pathParameterRequiresRequiredSwitchExceptionMessage = "Si la ubicación del parámetro es 'Path', el parámetro switch 'Required' es obligatorio." + noOpenApiUrlSuppliedExceptionMessage = 'No se proporcionó URL de OpenAPI para {0}.' + maximumConcurrentSchedulesInvalidExceptionMessage = 'Los horarios simultáneos máximos deben ser >=1 pero se obtuvo: {0}' + snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = 'Los Snapins solo son compatibles con Windows PowerShell.' + eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = 'El registro en el Visor de Eventos solo se admite en Windows.' + parametersMutuallyExclusiveExceptionMessage = "Los parámetros '{0}' y '{1}' son mutuamente excluyentes." + pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 'La función de elementos de ruta no es compatible con OpenAPI v3.0.x' + openApiParameterRequiresNameExceptionMessage = 'El parámetro OpenApi requiere un nombre especificado.' + maximumConcurrentTasksLessThanMinimumExceptionMessage = 'El número máximo de tareas concurrentes no puede ser menor que el mínimo de {0}, pero se obtuvo: {1}' + noSemaphoreFoundExceptionMessage = "No se encontró ningún semáforo llamado '{0}'" + singleValueForIntervalExceptionMessage = 'Solo puede suministrar un único valor {0} cuando utiliza intervalos.' + jwtNotYetValidExceptionMessage = 'El JWT aún no es válido.' + verbAlreadyDefinedForUrlExceptionMessage = '[Verbo] {0}: Ya está definido para {1}' + noSecretNamedMountedExceptionMessage = "No se ha montado ningún Secreto con el nombre '{0}'." + moduleOrVersionNotFoundExceptionMessage = 'No se encontró el módulo o la versión en {0}: {1}@{2}' + noScriptBlockSuppliedExceptionMessage = 'No se suministró ningún ScriptBlock.' + noSecretVaultRegisteredExceptionMessage = "No se ha registrado un Cofre de Secretos con el nombre '{0}'." + nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = 'Se requiere un nombre para el endpoint si se proporciona el parámetro RedirectTo.' + openApiLicenseObjectRequiresNameExceptionMessage = "El objeto OpenAPI 'license' requiere la propiedad 'name'. Use el parámetro -LicenseName." + sourcePathDoesNotExistForStaticRouteExceptionMessage = '[{0})] {1}: La ruta de origen proporcionada para la Ruta estática no existe: {2}' + noNameForWebSocketDisconnectExceptionMessage = 'No se proporcionó ningún nombre para desconectar el WebSocket.' + certificateExpiredExceptionMessage = "El certificado '{0}' ha expirado: {1}" + secretVaultUnlockExpiryDateInPastExceptionMessage = 'La fecha de expiración para desbloquear el Cofre de Secretos está en el pasado (UTC): {0}' + invalidExceptionTypeExceptionMessage = 'La excepción es de un tipo no válido, debe ser WebException o HttpRequestException, pero se obtuvo: {0}' + invalidSecretValueTypeExceptionMessage = 'El valor del secreto es de un tipo no válido. Tipos esperados: String, SecureString, HashTable, Byte[], o PSCredential. Pero se obtuvo: {0}' + explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 'El modo TLS explícito solo es compatible con endpoints SMTPS y TCPS.' + discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = "El parámetro 'DiscriminatorMapping' solo se puede usar cuando está presente la propiedad 'DiscriminatorProperty'." + scriptErrorExceptionMessage = "Error '{0}' en el script {1} {2} (línea {3}) carácter {4} al ejecutar {5} en el objeto {6} '{7}' Clase: {8} ClaseBase: {9}" + cannotSupplyIntervalForQuarterExceptionMessage = 'No se puede proporcionar un valor de intervalo para cada trimestre.' + scheduleEndTimeMustBeInFutureExceptionMessage = '[Horario] {0}: El valor de EndTime debe estar en el futuro.' + invalidJwtSignatureSuppliedExceptionMessage = 'Firma JWT proporcionada no válida.' + noSetScriptBlockForVaultExceptionMessage = "No se suministró ningún ScriptBlock de configuración para actualizar/crear secretos en la bóveda '{0}'" + accessMethodNotExistForMergingExceptionMessage = 'El método de acceso no existe para fusionarse: {0}' + defaultAuthNotInListExceptionMessage = "La autenticación predeterminada '{0}' no está en la lista de autenticación proporcionada." + parameterHasNoNameExceptionMessage = "El parámetro no tiene nombre. Asigne un nombre a este componente usando el parámetro 'Name'." + methodPathAlreadyDefinedForUrlExceptionMessage = '[{0}] {1}: Ya está definido para {2}' + fileWatcherAlreadyDefinedExceptionMessage = "Un Observador de Archivos llamado '{0}' ya ha sido definido." + noServiceHandlersDefinedExceptionMessage = 'No se han definido controladores de servicio.' + secretRequiredForCustomSessionStorageExceptionMessage = 'Se requiere un secreto cuando se utiliza el almacenamiento de sesión personalizado.' + secretManagementModuleNotInstalledExceptionMessage = 'El módulo Microsoft.PowerShell.SecretManagement no está instalado.' + noPathSuppliedForRouteExceptionMessage = 'No se proporcionó una ruta para la Ruta.' + validationOfAnyOfSchemaNotSupportedExceptionMessage = "La validación de un esquema que incluye 'anyof' no es compatible." + iisAuthSupportIsForWindowsOnlyExceptionMessage = 'El soporte de autenticación IIS es solo para Windows.' + oauth2InnerSchemeInvalidExceptionMessage = 'OAuth2 InnerScheme solo puede ser Basic o Form, pero se obtuvo: {0}' + noRoutePathSuppliedForPageExceptionMessage = 'No se proporcionó ruta de acceso para la página {0}.' + cacheStorageNotFoundForExistsExceptionMessage = "No se encontró el almacenamiento en caché con el nombre '{0}' al intentar comprobar si el elemento en caché '{1}' existe." + handlerAlreadyDefinedExceptionMessage = '[{0}] {1}: Manejador ya definido.' + sessionsNotConfiguredExceptionMessage = 'Las sesiones no se han configurado.' + propertiesTypeObjectAssociationExceptionMessage = 'Solo las propiedades de tipo Objeto pueden estar asociadas con {0}.' + sessionsRequiredForSessionPersistentAuthExceptionMessage = 'Se requieren sesiones para usar la autenticación persistente de sesión.' + invalidPathWildcardOrDirectoryExceptionMessage = 'La ruta suministrada no puede ser un comodín o un directorio: {0}' + accessMethodAlreadyDefinedExceptionMessage = 'Método de acceso ya definido: {0}' + parametersValueOrExternalValueMandatoryExceptionMessage = "Los parámetros 'Value' o 'ExternalValue' son obligatorios." + maximumConcurrentTasksInvalidExceptionMessage = 'El número máximo de tareas concurrentes debe ser >=1, pero se obtuvo: {0}' + cannotCreatePropertyWithoutTypeExceptionMessage = 'No se puede crear la propiedad porque no se ha definido ningún tipo.' + authMethodNotExistForMergingExceptionMessage = 'El método de autenticación no existe para la fusión: {0}' + maxValueInvalidExceptionMessage = "El valor máximo '{0}' para {1} no es válido, debe ser menor o igual a {2}" + endpointAlreadyDefinedExceptionMessage = "Ya se ha definido un punto de conexión llamado '{0}'." + eventAlreadyRegisteredExceptionMessage = 'Evento {0} ya registrado: {1}' + parameterNotSuppliedInRequestExceptionMessage = "No se ha proporcionado un parámetro llamado '{0}' en la solicitud o no hay datos disponibles." + cacheStorageNotFoundForSetExceptionMessage = "No se encontró el almacenamiento en caché con el nombre '{0}' al intentar establecer el elemento en caché '{1}'." + methodPathAlreadyDefinedExceptionMessage = '[{0}] {1}: Ya está definido.' + errorLoggingAlreadyEnabledExceptionMessage = 'El registro de errores ya está habilitado.' + valueForUsingVariableNotFoundExceptionMessage = "No se pudo encontrar el valor para '`$using:{0}'." + rapidPdfDoesNotSupportOpenApi31ExceptionMessage = 'La herramienta de documentación RapidPdf no admite OpenAPI 3.1' + oauth2ClientSecretRequiredExceptionMessage = 'OAuth2 requiere un Client Secret cuando no se usa PKCE.' + invalidBase64JwtExceptionMessage = 'Valor Base64 no válido encontrado en JWT' + noSessionToCalculateDataHashExceptionMessage = 'No hay ninguna sesión disponible para calcular el hash de datos.' + cacheStorageNotFoundForRemoveExceptionMessage = "No se encontró el almacenamiento en caché con el nombre '{0}' al intentar eliminar el elemento en caché '{1}'." + csrfMiddlewareNotInitializedExceptionMessage = 'El Middleware CSRF no se ha inicializado.' + infoTitleMandatoryMessage = 'info.title es obligatorio.' + typeCanOnlyBeAssociatedWithObjectExceptionMessage = 'El tipo {0} solo se puede asociar con un Objeto.' + userFileDoesNotExistExceptionMessage = 'El archivo de usuario no existe: {0}' + routeParameterNeedsValidScriptblockExceptionMessage = 'El parámetro Route necesita un ScriptBlock válido y no vacío.' + nextTriggerCalculationErrorExceptionMessage = 'Parece que algo salió mal al intentar calcular la siguiente fecha y hora del disparador: {0}' + cannotLockValueTypeExceptionMessage = 'No se puede bloquear un [ValueTypes].' + failedToCreateOpenSslCertExceptionMessage = 'Error al crear el certificado openssl: {0}' + jwtExpiredExceptionMessage = 'El JWT ha expirado.' + openingGuiMessage = 'Abriendo la GUI.' + multiTypePropertiesRequireOpenApi31ExceptionMessage = 'Las propiedades de tipo múltiple requieren OpenApi versión 3.1 o superior.' + noNameForWebSocketRemoveExceptionMessage = 'No se proporcionó ningún nombre para eliminar el WebSocket.' + maxSizeInvalidExceptionMessage = 'MaxSize debe ser igual o mayor que 0, pero se obtuvo: {0}' + iisShutdownMessage = '(Apagado de IIS)' + cannotUnlockValueTypeExceptionMessage = 'No se puede desbloquear un [ValueTypes].' + noJwtSignatureForAlgorithmExceptionMessage = 'No se proporcionó una firma JWT para {0}.' + maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 'El número máximo de hilos concurrentes de WebSocket debe ser >=1, pero se obtuvo: {0}' + acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 'El mensaje de reconocimiento solo es compatible con endpoints SMTP y TCP.' + failedToConnectToUrlExceptionMessage = 'Error al conectar con la URL: {0}' + failedToAcquireMutexOwnershipExceptionMessage = 'No se pudo adquirir la propiedad del mutex. Nombre del mutex: {0}' + sessionsRequiredForOAuth2WithPKCEExceptionMessage = 'Se requieren sesiones para usar OAuth2 con PKCE.' + failedToConnectToWebSocketExceptionMessage = 'Error al conectar con el WebSocket: {0}' + unsupportedObjectExceptionMessage = 'Objeto no compatible' + failedToParseAddressExceptionMessage = "Error al analizar '{0}' como una dirección IP/Host:Puerto válida" + mustBeRunningWithAdminPrivilegesExceptionMessage = 'Debe estar ejecutándose con privilegios de administrador para escuchar en direcciones que no sean localhost.' + specificationMessage = 'Especificación' + cacheStorageNotFoundForClearExceptionMessage = "No se encontró el almacenamiento en caché con el nombre '{0}' al intentar vaciar la caché." + restartingServerMessage = 'Reiniciando el servidor...' + cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = "No se puede proporcionar un intervalo cuando el parámetro 'Every' está configurado en None." + unsupportedJwtAlgorithmExceptionMessage = 'El algoritmo JWT actualmente no es compatible: {0}' + websocketsNotConfiguredForSignalMessagesExceptionMessage = 'WebSockets no están configurados para enviar mensajes de señal.' + invalidLogicTypeInHashtableMiddlewareExceptionMessage = 'Un Middleware Hashtable suministrado tiene un tipo de lógica no válido. Se esperaba ScriptBlock, pero se obtuvo: {0}' + maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 'Los horarios simultáneos máximos no pueden ser inferiores al mínimo de {0} pero se obtuvo: {1}' + failedToAcquireSemaphoreOwnershipExceptionMessage = 'No se pudo adquirir la propiedad del semáforo. Nombre del semáforo: {0}' + propertiesParameterWithoutNameExceptionMessage = 'Los parámetros de propiedades no se pueden usar si la propiedad no tiene nombre.' + customSessionStorageMethodNotImplementedExceptionMessage = "El almacenamiento de sesión personalizado no implementa el método requerido '{0}()'." + authenticationMethodDoesNotExistExceptionMessage = 'El método de autenticación no existe: {0}' + webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = 'La función de Webhooks no es compatible con OpenAPI v3.0.x' + invalidContentTypeForSchemaExceptionMessage = "'content-type' inválido encontrado para el esquema: {0}" + noUnlockScriptBlockForVaultExceptionMessage = "No se suministró ningún ScriptBlock de desbloqueo para desbloquear la bóveda '{0}'" + definitionTagMessage = 'Definición {0}:' + failedToOpenRunspacePoolExceptionMessage = 'Error al abrir RunspacePool: {0}' + verbNoLogicPassedExceptionMessage = '[Verbo] {0}: No se pasó ninguna lógica' + noMutexFoundExceptionMessage = "No se encontró ningún mutex llamado '{0}'" + documentationMessage = 'Documentación' + timerAlreadyDefinedExceptionMessage = '[Temporizador] {0}: Temporizador ya definido.' + invalidPortExceptionMessage = 'El puerto no puede ser negativo: {0}' + viewsFolderNameAlreadyExistsExceptionMessage = 'El nombre de la carpeta Views ya existe: {0}' + noNameForWebSocketResetExceptionMessage = 'No se proporcionó ningún nombre para restablecer el WebSocket.' + mergeDefaultAuthNotInListExceptionMessage = "La autenticación MergeDefault '{0}' no está en la lista de autenticación proporcionada." + descriptionRequiredExceptionMessage = 'Se requiere una descripción.' + pageNameShouldBeAlphaNumericExceptionMessage = 'El nombre de la página debe ser un valor alfanumérico válido: {0}' + defaultValueNotBooleanOrEnumExceptionMessage = 'El valor predeterminado no es un booleano y no forma parte del enum.' + openApiComponentSchemaDoesNotExistExceptionMessage = 'El esquema del componente OpenApi {0} no existe.' + timerParameterMustBeGreaterThanZeroExceptionMessage = '[Temporizador] {0}: {1} debe ser mayor que 0.' + taskTimedOutExceptionMessage = 'La tarea ha agotado el tiempo después de {0}ms.' + scheduleStartTimeAfterEndTimeExceptionMessage = "[Horario] {0}: No puede tener un 'StartTime' después del 'EndTime'" + infoVersionMandatoryMessage = 'info.version es obligatorio.' + cannotUnlockNullObjectExceptionMessage = 'No se puede desbloquear un objeto nulo.' + nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 'Se requiere un ScriptBlock no vacío para el esquema de autenticación personalizado.' + validationOfOneOfSchemaNotSupportedExceptionMessage = "La validación de un esquema que incluye 'oneof' no es compatible." + routeParameterCannotBeNullExceptionMessage = "El parámetro 'Route' no puede ser nulo." + cacheStorageAlreadyExistsExceptionMessage = "Ya existe un almacenamiento en caché con el nombre '{0}'." + loggingMethodRequiresValidScriptBlockExceptionMessage = "El método de salida proporcionado para el método de registro '{0}' requiere un ScriptBlock válido." + scopedVariableAlreadyDefinedExceptionMessage = 'La variable con alcance ya está definida: {0}' + oauth2RequiresAuthorizeUrlExceptionMessage = 'OAuth2 requiere que se proporcione una URL de autorización.' + pathNotExistExceptionMessage = 'La ruta no existe: {0}' + noDomainServerNameForWindowsAdAuthExceptionMessage = 'No se ha proporcionado un nombre de servidor de dominio para la autenticación AD de Windows.' + suppliedDateAfterScheduleEndTimeExceptionMessage = 'La fecha proporcionada es posterior a la hora de finalización del horario en {0}' + wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 'El comodín * para los Métodos es incompatible con el interruptor AutoMethods.' + cannotSupplyIntervalForYearExceptionMessage = 'No se puede proporcionar un valor de intervalo para cada año.' + missingComponentsMessage = 'Componente(s) faltante(s)' + invalidStrictTransportSecurityDurationExceptionMessage = 'Duración de Strict-Transport-Security no válida proporcionada: {0}. Debe ser mayor que 0.' + noSecretForHmac512ExceptionMessage = 'No se suministró ningún secreto para el hash HMAC512.' + daysInMonthExceededExceptionMessage = '{0} solo tiene {1} días, pero se suministró {2}.' + nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 'Se requiere un ScriptBlock no vacío para el método de salida de registro personalizado.' + encodingAttributeOnlyAppliesToMultipartExceptionMessage = 'El atributo de codificación solo se aplica a cuerpos de solicitud multipart y application/x-www-form-urlencoded.' + suppliedDateBeforeScheduleStartTimeExceptionMessage = 'La fecha proporcionada es anterior a la hora de inicio del horario en {0}' + unlockSecretRequiredExceptionMessage = "Se requiere una propiedad 'UnlockSecret' al usar Microsoft.PowerShell.SecretStore" + noLogicPassedForMethodRouteExceptionMessage = '[{0}] {1}: No se pasó lógica.' + bodyParserAlreadyDefinedForContentTypeExceptionMessage = 'Un analizador de cuerpo ya está definido para el tipo de contenido {0}.' + invalidJwtSuppliedExceptionMessage = 'JWT proporcionado no válido.' + sessionsRequiredForFlashMessagesExceptionMessage = 'Se requieren sesiones para usar mensajes Flash.' + outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = 'El método de salida proporcionado para el registro de solicitudes requiere un ScriptBlock válido.' + semaphoreAlreadyExistsExceptionMessage = 'Ya existe un semáforo con el siguiente nombre: {0}' + invalidJwtHeaderAlgorithmSuppliedExceptionMessage = 'Algoritmo del encabezado JWT proporcionado no válido.' + oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = "El proveedor de OAuth2 no admite el tipo de concesión 'password' requerido al usar un InnerScheme." + invalidAliasFoundExceptionMessage = 'Se encontró un alias {0} no válido: {1}' + scheduleDoesNotExistExceptionMessage = "El horario '{0}' no existe." + accessMethodNotExistExceptionMessage = 'El método de acceso no existe: {0}' + oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = "El proveedor de OAuth2 no admite el tipo de respuesta 'code'." + untestedPowerShellVersionWarningMessage = '[ADVERTENCIA] Pode {0} no se ha probado en PowerShell {1}, ya que no estaba disponible cuando se lanzó Pode.' + secretVaultAlreadyRegisteredAutoImportExceptionMessage = "Ya se ha registrado un Bóveda Secreta con el nombre '{0}' al importar automáticamente Bóvedas Secretas." + schemeRequiresValidScriptBlockExceptionMessage = "El esquema proporcionado para el validador de autenticación '{0}' requiere un ScriptBlock válido." + serverLoopingMessage = 'Bucle del servidor cada {0} segundos' + certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 'Las huellas digitales/nombres de certificados solo son compatibles con Windows.' + sseConnectionNameRequiredExceptionMessage = "Se requiere un nombre de conexión SSE, ya sea de -Name o $`$WebEvent.Sse.Name" + invalidMiddlewareTypeExceptionMessage = 'Uno de los Middlewares suministrados es de un tipo no válido. Se esperaba ScriptBlock o Hashtable, pero se obtuvo: {0}' + noSecretForJwtSignatureExceptionMessage = 'No se suministró ningún secreto para la firma JWT.' + modulePathDoesNotExistExceptionMessage = 'La ruta del módulo no existe: {0}' + taskAlreadyDefinedExceptionMessage = '[Tarea] {0}: Tarea ya definida.' + verbAlreadyDefinedExceptionMessage = '[Verbo] {0}: Ya está definido' + clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 'Los certificados de cliente solo son compatibles con endpoints HTTPS.' + endpointNameNotExistExceptionMessage = "No existe un punto de conexión con el nombre '{0}'." + middlewareNoLogicSuppliedExceptionMessage = '[Middleware]: No se suministró lógica en el ScriptBlock.' + scriptBlockRequiredForMergingUsersExceptionMessage = 'Se requiere un ScriptBlock para fusionar múltiples usuarios autenticados en un solo objeto cuando Valid es All.' + secretVaultAlreadyRegisteredExceptionMessage = "Un Cofre de Secretos con el nombre '{0}' ya ha sido registrado{1}." + deprecatedTitleVersionDescriptionWarningMessage = "ADVERTENCIA: Título, Versión y Descripción en 'Enable-PodeOpenApi' están obsoletos. Utilice 'Add-PodeOAInfo' en su lugar." + undefinedOpenApiReferencesMessage = 'Referencias OpenAPI indefinidas:' + doneMessage = 'Hecho' + swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = 'Esta versión de Swagger-Editor no admite OpenAPI 3.1' + durationMustBeZeroOrGreaterExceptionMessage = 'La duración debe ser igual o mayor a 0, pero se obtuvo: {0}s' + viewsPathDoesNotExistExceptionMessage = 'La ruta de las Views no existe: {0}' + discriminatorIncompatibleWithAllOfExceptionMessage = "El parámetro 'Discriminator' es incompatible con 'allOf'." + noNameForWebSocketSendMessageExceptionMessage = 'No se proporcionó ningún nombre para enviar un mensaje al WebSocket.' + hashtableMiddlewareNoLogicExceptionMessage = 'Un Middleware Hashtable suministrado no tiene lógica definida.' + openApiInfoMessage = 'Información OpenAPI:' + invalidSchemeForAuthValidatorExceptionMessage = "El esquema '{0}' proporcionado para el validador de autenticación '{1}' requiere un ScriptBlock válido." + sseFailedToBroadcastExceptionMessage = 'SSE no pudo transmitir debido al nivel de transmisión SSE definido para {0}: {1}.' + adModuleWindowsOnlyExceptionMessage = 'El módulo de Active Directory solo está disponible en Windows.' + requestLoggingAlreadyEnabledExceptionMessage = 'El registro de solicitudes ya está habilitado.' + invalidAccessControlMaxAgeDurationExceptionMessage = 'Duración inválida para Access-Control-Max-Age proporcionada: {0}. Debe ser mayor que 0.' +} + diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index c6c9ebb43..e59d204e6 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -1,284 +1,285 @@ -ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyExceptionMessage = Le module Active Directory est uniquement disponible sur Windows. -adModuleNotInstalledExceptionMessage = Le module Active Directory n'est pas installé. -secretManagementModuleNotInstalledExceptionMessage = Le module Microsoft.PowerShell.SecretManagement n'est pas installé. -secretVaultAlreadyRegisteredAutoImportExceptionMessage = Un coffre-fort secret avec le nom '{0}' a déjà été enregistré lors de l'importation automatique des coffres-forts secrets. -failedToOpenRunspacePoolExceptionMessage = Échec de l'ouverture de RunspacePool : {0} -cronExpressionInvalidExceptionMessage = L'expression Cron doit uniquement comporter 5 parties : {0} -invalidAliasFoundExceptionMessage = Alias {0} non valide trouvé : {1} -invalidAtomCharacterExceptionMessage = Caractère atomique non valide : {0} -minValueGreaterThanMaxExceptionMessage = La valeur minimale pour {0} ne doit pas être supérieure à la valeur maximale. -minValueInvalidExceptionMessage = La valeur minimale '{0}' pour {1} n'est pas valide, elle doit être supérieure ou égale à {2} -maxValueInvalidExceptionMessage = La valeur maximale '{0}' pour {1} n'est pas valide, elle doit être inférieure ou égale à {2} -valueOutOfRangeExceptionMessage = La valeur '{0}' pour {1} n'est pas valide, elle doit être comprise entre {2} et {3} -daysInMonthExceededExceptionMessage = {0} n'a que {1} jours, mais {2} a été fourni. -nextTriggerCalculationErrorExceptionMessage = Il semble que quelque chose ait mal tourné lors de la tentative de calcul de la prochaine date et heure de déclenchement : {0} -incompatiblePodeDllExceptionMessage = Une version incompatible existante de Pode.DLL {0} est chargée. La version {1} est requise. Ouvrez une nouvelle session Powershell/pwsh et réessayez. -endpointNotExistExceptionMessage = Un point de terminaison avec le protocole '{0}' et l'adresse '{1}' ou l'adresse locale '{2}' n'existe pas. -endpointNameNotExistExceptionMessage = Un point de terminaison avec le nom '{0}' n'existe pas. -failedToConnectToUrlExceptionMessage = Échec de la connexion à l'URL : {0} -failedToParseAddressExceptionMessage = Échec de l'analyse de '{0}' en tant qu'adresse IP/Hôte:Port valide -invalidIpAddressExceptionMessage = L'adresse IP fournie n'est pas valide : {0} -invalidPortExceptionMessage = Le port ne peut pas être négatif : {0} -pathNotExistExceptionMessage = Le chemin n'existe pas : {0} -noSecretForHmac256ExceptionMessage = Aucun secret fourni pour le hachage HMAC256. -noSecretForHmac384ExceptionMessage = Aucun secret fourni pour le hachage HMAC384. -noSecretForHmac512ExceptionMessage = Aucun secret fourni pour le hachage HMAC512. -noSecretForJwtSignatureExceptionMessage = Aucun secret fourni pour la signature JWT. -noSecretExpectedForNoSignatureExceptionMessage = Aucun secret attendu pour aucune signature. -unsupportedJwtAlgorithmExceptionMessage = L'algorithme JWT n'est actuellement pas pris en charge : {0} -invalidBase64JwtExceptionMessage = Valeur encodée en Base64 non valide trouvée dans le JWT -invalidJsonJwtExceptionMessage = Valeur JSON non valide trouvée dans le JWT -unsupportedFunctionInServerlessContextExceptionMessage = La fonction {0} n'est pas prise en charge dans un contexte sans serveur. -invalidPathWildcardOrDirectoryExceptionMessage = Le chemin fourni ne peut pas être un caractère générique ou un répertoire : {0} -invalidExceptionTypeExceptionMessage = L'exception est d'un type non valide, doit être soit WebException soit HttpRequestException, mais a obtenu : {0} -pathToLoadNotFoundExceptionMessage = Chemin à charger {0} non trouvé : {1} -singleValueForIntervalExceptionMessage = Vous ne pouvez fournir qu'une seule valeur {0} lorsque vous utilisez des intervalles. -scriptErrorExceptionMessage = Erreur '{0}' dans le script {1} {2} (ligne {3}) char {4} en exécutant {5} sur l'objet {6} '{7}' Classe : {8} ClasseBase : {9} -noScriptBlockSuppliedExceptionMessage = Aucun ScriptBlock fourni. -iisAspnetcoreTokenMissingExceptionMessage = Le jeton IIS ASPNETCORE_TOKEN est manquant. -propertiesParameterWithoutNameExceptionMessage = Les paramètres Properties ne peuvent pas être utilisés si la propriété n'a pas de nom. -multiTypePropertiesRequireOpenApi31ExceptionMessage = Les propriétés multi-types nécessitent OpenApi Version 3.1 ou supérieure. -openApiVersionPropertyMandatoryExceptionMessage = La propriété Version OpenApi est obligatoire. -webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = La fonction Webhooks n'est pas prise en charge dans OpenAPI v3.0.x -authenticationMethodDoesNotExistExceptionMessage = La méthode d'authentification n'existe pas : {0} -unsupportedObjectExceptionMessage = Objet non pris en charge -validationOfAnyOfSchemaNotSupportedExceptionMessage = La validation d'un schéma qui inclut 'anyof' n'est pas prise en charge. -validationOfOneOfSchemaNotSupportedExceptionMessage = La validation d'un schéma qui inclut 'oneof' n'est pas prise en charge. -cannotCreatePropertyWithoutTypeExceptionMessage = Impossible de créer la propriété car aucun type n'est défini. -headerMustHaveNameInEncodingContextExceptionMessage = L'en-tête doit avoir un nom lorsqu'il est utilisé dans un contexte de codage. -descriptionRequiredExceptionMessage = Une description est requise. -openApiDocumentNotCompliantExceptionMessage = Le document OpenAPI n'est pas conforme. -noComponentInDefinitionExceptionMessage = Aucun composant du type {0} nommé {1} n'est disponible dans la définition {2}. -methodPathAlreadyDefinedExceptionMessage = [{0}] {1} : Déjà défini. -methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1} : Déjà défini pour {2} -invalidMiddlewareTypeExceptionMessage = Un des Middlewares fournis est d'un type non valide. Attendu ScriptBlock ou Hashtable, mais a obtenu : {0} -hashtableMiddlewareNoLogicExceptionMessage = Un Middleware Hashtable fourni n'a aucune logique définie. -invalidLogicTypeInHashtableMiddlewareExceptionMessage = Un Middleware Hashtable fourni a un type de logique non valide. Attendu ScriptBlock, mais a obtenu : {0} -scopedVariableAlreadyDefinedExceptionMessage = La variable à portée est déjà définie : {0} -valueForUsingVariableNotFoundExceptionMessage = Valeur pour '`$using:{0}' introuvable. -unlockSecretRequiredExceptionMessage = Une propriété 'UnlockSecret' est requise lors de l'utilisation de Microsoft.PowerShell.SecretStore -unlockSecretButNoScriptBlockExceptionMessage = Secret de déverrouillage fourni pour le type de coffre-fort personnalisé, mais aucun ScriptBlock de déverrouillage fourni. -noUnlockScriptBlockForVaultExceptionMessage = Aucun ScriptBlock de déverrouillage fourni pour déverrouiller le coffre '{0}' -noSetScriptBlockForVaultExceptionMessage = Aucun ScriptBlock de configuration fourni pour mettre à jour/créer des secrets dans le coffre '{0}' -noRemoveScriptBlockForVaultExceptionMessage = Aucun ScriptBlock de suppression fourni pour supprimer des secrets du coffre '{0}' -invalidSecretValueTypeExceptionMessage = La valeur du secret est d'un type non valide. Types attendus : String, SecureString, HashTable, Byte[], ou PSCredential. Mais a obtenu : {0} -limitValueCannotBeZeroOrLessExceptionMessage = La valeur de la limite ne peut pas être 0 ou inférieure pour {0} -secondsValueCannotBeZeroOrLessExceptionMessage = La valeur en secondes ne peut pas être 0 ou inférieure pour {0} -failedToCreateOpenSslCertExceptionMessage = Échec de la création du certificat openssl : {0} -certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Les empreintes digitales/Noms de certificat ne sont pris en charge que sous Windows. -noCertificateFoundExceptionMessage = Aucun certificat n'a été trouvé dans {0}\{1} pour '{2}' -runspacePoolFailedToLoadExceptionMessage = {0} RunspacePool n'a pas pu être chargé. -noServiceHandlersDefinedExceptionMessage = Aucun gestionnaire de service défini. -noSessionToSetOnResponseExceptionMessage = Aucune session disponible pour être définie sur la réponse. -noSessionToCalculateDataHashExceptionMessage = Aucune session disponible pour calculer le hachage de données. -moduleOrVersionNotFoundExceptionMessage = Module ou version introuvable sur {0} : {1}@{2} -noSmtpHandlersDefinedExceptionMessage = Aucun gestionnaire SMTP défini. -taskTimedOutExceptionMessage = La tâche a expiré après {0}ms. -verbAlreadyDefinedExceptionMessage = [Verbe] {0} : Déjà défini -verbAlreadyDefinedForUrlExceptionMessage = [Verbe] {0} : Déjà défini pour {1} -pathOrScriptBlockRequiredExceptionMessage = Un chemin ou un ScriptBlock est requis pour obtenir les valeurs d'accès personnalisées. -accessMethodAlreadyDefinedExceptionMessage = Méthode d'accès déjà définie : {0} -accessMethodNotExistForMergingExceptionMessage = La méthode d'accès n'existe pas pour la fusion : {0} -routeAlreadyContainsCustomAccessExceptionMessage = La route '[{0}] {1}' contient déjà un accès personnalisé avec le nom '{2}' -accessMethodNotExistExceptionMessage = La méthode d'accès n'existe pas : {0} -pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = La fonction PathItems n'est pas prise en charge dans OpenAPI v3.0.x -nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = Un ScriptBlock non vide est requis pour le schéma d'authentification personnalisé. -oauth2InnerSchemeInvalidExceptionMessage = Le OAuth2 InnerScheme ne peut être que Basic ou Form, mais obtenu : {0} -sessionsRequiredForOAuth2WithPKCEExceptionMessage = Des sessions sont nécessaires pour utiliser OAuth2 avec PKCE. -oauth2ClientSecretRequiredExceptionMessage = OAuth2 nécessite un Client Secret lorsque PKCE n'est pas utilisé. -authMethodAlreadyDefinedExceptionMessage = Méthode d'authentification déjà définie : {0} -invalidSchemeForAuthValidatorExceptionMessage = Le schéma '{0}' fourni pour le validateur d'authentification '{1}' nécessite un ScriptBlock valide. -sessionsRequiredForSessionPersistentAuthExceptionMessage = Des sessions sont nécessaires pour utiliser l'authentification persistante par session. -oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 nécessite une URL d'autorisation. -authMethodNotExistForMergingExceptionMessage = La méthode d'authentification n'existe pas pour la fusion : {0} -mergeDefaultAuthNotInListExceptionMessage = L'authentification MergeDefault '{0}' n'est pas dans la liste d'authentification fournie. -defaultAuthNotInListExceptionMessage = L'authentification par défaut '{0}' n'est pas dans la liste d'authentification fournie. -scriptBlockRequiredForMergingUsersExceptionMessage = Un ScriptBlock est requis pour fusionner plusieurs utilisateurs authentifiés en un seul objet lorsque Valid est All. -noDomainServerNameForWindowsAdAuthExceptionMessage = Aucun nom de serveur de domaine n'a été fourni pour l'authentification Windows AD. -sessionsNotConfiguredExceptionMessage = Les sessions n'ont pas été configurées. -windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Le support de l'authentification locale Windows est uniquement pour Windows. -iisAuthSupportIsForWindowsOnlyExceptionMessage = Le support de l'authentification IIS est uniquement pour Windows. -noAlgorithmInJwtHeaderExceptionMessage = Aucun algorithme fourni dans l'en-tête JWT. -invalidJwtSuppliedExceptionMessage = JWT fourni invalide. -invalidJwtHeaderAlgorithmSuppliedExceptionMessage = Algorithme de l'en-tête JWT fourni invalide. -noJwtSignatureForAlgorithmExceptionMessage = Aucune signature JWT fournie pour {0}. -expectedNoJwtSignatureSuppliedExceptionMessage = Aucune signature JWT n'était attendue. -invalidJwtSignatureSuppliedExceptionMessage = Signature JWT fournie invalide. -jwtExpiredExceptionMessage = Le JWT a expiré. -jwtNotYetValidExceptionMessage = Le JWT n'est pas encore valide pour une utilisation. -snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Les Snapins sont uniquement pris en charge sur Windows PowerShell. -userFileDoesNotExistExceptionMessage = Le fichier utilisateur n'existe pas : {0} -schemeRequiresValidScriptBlockExceptionMessage = Le schéma fourni pour le validateur d'authentification '{0}' nécessite un ScriptBlock valide. -oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = Le fournisseur OAuth2 ne supporte pas le type de réponse 'code'. -oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = Le fournisseur OAuth2 ne supporte pas le type de subvention 'password' requis par l'utilisation d'un InnerScheme. -eventAlreadyRegisteredExceptionMessage = Événement {0} déjà enregistré : {1} -noEventRegisteredExceptionMessage = Aucun événement {0} enregistré : {1} -sessionsRequiredForFlashMessagesExceptionMessage = Des sessions sont nécessaires pour utiliser les messages Flash. -eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = La journalisation dans le Visualisateur d'événements n'est prise en charge que sous Windows. -nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = Un ScriptBlock non vide est requis pour la méthode de journalisation personnalisée. -requestLoggingAlreadyEnabledExceptionMessage = La journalisation des requêtes est déjà activée. -outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = La méthode de sortie fournie pour la journalisation des requêtes nécessite un ScriptBlock valide. -errorLoggingAlreadyEnabledExceptionMessage = La journalisation des erreurs est déjà activée. -nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = Un ScriptBlock non vide est requis pour la méthode de journalisation. -csrfMiddlewareNotInitializedExceptionMessage = Le Middleware CSRF n'a pas été initialisé. -sessionsRequiredForCsrfExceptionMessage = Des sessions sont nécessaires pour utiliser CSRF sauf si vous souhaitez utiliser des cookies. -middlewareNoLogicSuppliedExceptionMessage = [Middleware] : Aucune logique fournie dans le ScriptBlock. -parameterHasNoNameExceptionMessage = Le paramètre n'a pas de nom. Veuillez donner un nom à ce composant en utilisant le paramètre 'Name'. -reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = La fonctionnalité du composant réutilisable 'pathItems' n'est pas disponible dans OpenAPI v3.0. -noPropertiesMutuallyExclusiveExceptionMessage = Le paramètre 'NoProperties' est mutuellement exclusif avec 'Properties', 'MinProperties' et 'MaxProperties'. -discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = Le paramètre 'DiscriminatorMapping' ne peut être utilisé que lorsque 'DiscriminatorProperty' est présent. -discriminatorIncompatibleWithAllOfExceptionMessage = Le paramètre 'Discriminator' est incompatible avec 'allOf'. -typeCanOnlyBeAssociatedWithObjectExceptionMessage = Le type {0} ne peut être associé qu'à un Objet. -showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui est actuellement disponible uniquement pour Windows PowerShell et PowerShell 7+ sur Windows. -nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = Un nom est requis pour le point de terminaison si le paramètre RedirectTo est fourni. -clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = Les certificats client ne sont pris en charge que sur les points de terminaison HTTPS. -explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = Le mode TLS explicite n'est pris en charge que sur les points de terminaison SMTPS et TCPS. -acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = Le message de reconnaissance n'est pris en charge que sur les points de terminaison SMTP et TCP. -crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = La vérification de fin de message CRLF n'est prise en charge que sur les points de terminaison TCP. -mustBeRunningWithAdminPrivilegesExceptionMessage = Doit être exécuté avec des privilèges administratifs pour écouter sur des adresses autres que localhost. -certificateSuppliedForNonHttpsWssEndpointExceptionMessage = Certificat fourni pour un point de terminaison non HTTPS/WSS. -websocketsNotConfiguredForSignalMessagesExceptionMessage = Les WebSockets ne sont pas configurés pour envoyer des messages de signal. -noPathSuppliedForRouteExceptionMessage = Aucun chemin fourni pour la route. -accessRequiresAuthenticationOnRoutesExceptionMessage = L'accès nécessite une authentification sur les routes. -accessMethodDoesNotExistExceptionMessage = La méthode d'accès n'existe pas : {0}. -routeParameterNeedsValidScriptblockExceptionMessage = Le paramètre de la route nécessite un ScriptBlock valide et non vide. -noCommandsSuppliedToConvertToRoutesExceptionMessage = Aucune commande fournie pour convertir en routes. -nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Un ScriptBlock non vide est requis pour créer une route de page. -sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE ne peut être configuré que sur les requêtes avec une valeur d'en-tête Accept de text/event-stream. -sseConnectionNameRequiredExceptionMessage = Un nom de connexion SSE est requis, soit de -Name soit de $`$WebEvent.Sse.Name -sseFailedToBroadcastExceptionMessage = SSE a échoué à diffuser en raison du niveau de diffusion SSE défini pour {0} : {1}. -podeNotInitializedExceptionMessage = Pode n'a pas été initialisé. -invalidTaskTypeExceptionMessage = Le type de tâche n'est pas valide, attendu [System.Threading.Tasks.Task] ou [hashtable]. -cannotLockValueTypeExceptionMessage = Impossible de verrouiller un [ValueTypes]. -cannotLockNullObjectExceptionMessage = Impossible de verrouiller un objet nul. -failedToAcquireLockExceptionMessage = Impossible d'acquérir un verrou sur l'objet. -cannotUnlockValueTypeExceptionMessage = Impossible de déverrouiller un [ValueTypes]. -cannotUnlockNullObjectExceptionMessage = Impossible de déverrouiller un objet nul. -sessionMiddlewareAlreadyInitializedExceptionMessage = Le Middleware de session a déjà été initialisé. -customSessionStorageMethodNotImplementedExceptionMessage = Le stockage de session personnalisé n'implémente pas la méthode requise '{0}()'. -secretRequiredForCustomSessionStorageExceptionMessage = Un secret est requis lors de l'utilisation d'un stockage de session personnalisé. -noSessionAvailableToSaveExceptionMessage = Aucune session disponible pour sauvegarder. -cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Impossible de fournir un intervalle lorsque le paramètre 'Every' est défini sur None. -cannotSupplyIntervalForQuarterExceptionMessage = Impossible de fournir une valeur d'intervalle pour chaque trimestre. -cannotSupplyIntervalForYearExceptionMessage = Impossible de fournir une valeur d'intervalle pour chaque année. -secretVaultAlreadyRegisteredExceptionMessage = Un Coffre-Fort de Secrets avec le nom '{0}' a déjà été enregistré{1}. -secretVaultUnlockExpiryDateInPastExceptionMessage = La date d'expiration du déverrouillage du Coffre-Fort de Secrets est dans le passé (UTC) : {0} -secretAlreadyMountedExceptionMessage = Un Secret avec le nom '{0}' a déjà été monté. -credentialsPassedWildcardForHeadersLiteralExceptionMessage = Lorsque des Identifiants sont passés, le caractère générique * pour les En-têtes sera pris comme une chaîne littérale et non comme un caractère générique. -wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = Le caractère générique * pour les En-têtes est incompatible avec le commutateur AutoHeaders. -wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = Le caractère générique * pour les Méthodes est incompatible avec le commutateur AutoMethods. -invalidAccessControlMaxAgeDurationExceptionMessage = Durée Access-Control-Max-Age invalide fournie : {0}. Doit être supérieure à 0. -noNameForWebSocketDisconnectExceptionMessage = Aucun Nom fourni pour déconnecter le WebSocket. -noNameForWebSocketRemoveExceptionMessage = Aucun Nom fourni pour supprimer le WebSocket. -noNameForWebSocketSendMessageExceptionMessage = Aucun Nom fourni pour envoyer un message au WebSocket. -noSecretNamedMountedExceptionMessage = Aucun Secret nommé '{0}' n'a été monté. -noNameForWebSocketResetExceptionMessage = Aucun Nom fourni pour réinitialiser le WebSocket. -schemaValidationRequiresPowerShell610ExceptionMessage = La validation du schéma nécessite PowerShell version 6.1.0 ou supérieure. -routeParameterCannotBeNullExceptionMessage = Le paramètre 'Route' ne peut pas être nul. -encodingAttributeOnlyAppliesToMultipartExceptionMessage = L'attribut d'encodage s'applique uniquement aux corps de requête multipart et application/x-www-form-urlencoded. -testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema' doit être activé en utilisant 'Enable-PodeOpenApi -EnableSchemaValidation' -openApiComponentSchemaDoesNotExistExceptionMessage = Le schéma du composant OpenApi {0} n'existe pas. -openApiParameterRequiresNameExceptionMessage = Le paramètre OpenApi nécessite un nom spécifié. -openApiLicenseObjectRequiresNameExceptionMessage = L'objet OpenAPI 'license' nécessite la propriété 'name'. Utilisez le paramètre -LicenseName. -parametersValueOrExternalValueMandatoryExceptionMessage = Les paramètres 'Value' ou 'ExternalValue' sont obligatoires. -parametersMutuallyExclusiveExceptionMessage = Les paramètres '{0}' et '{1}' sont mutuellement exclusifs. -maximumConcurrentWebSocketThreadsInvalidExceptionMessage = Le nombre maximum de threads WebSocket simultanés doit être >=1, mais a obtenu : {0} -maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = Le nombre maximum de threads WebSocket simultanés ne peut pas être inférieur au minimum de {0}, mais a obtenu : {1} -alreadyConnectedToWebSocketExceptionMessage = Déjà connecté au WebSocket avec le nom '{0}' -failedToConnectToWebSocketExceptionMessage = Échec de la connexion au WebSocket : {0} -verbNoLogicPassedExceptionMessage = [Verbe] {0} : Aucune logique transmise -scriptPathDoesNotExistExceptionMessage = Le chemin du script n'existe pas : {0} -failedToImportModuleExceptionMessage = Échec de l'importation du module : {0} -modulePathDoesNotExistExceptionMessage = Le chemin du module n'existe pas : {0} -defaultValueNotBooleanOrEnumExceptionMessage = La valeur par défaut n'est pas un booléen et ne fait pas partie de l'énumération. -propertiesTypeObjectAssociationExceptionMessage = Seules les propriétés de type Objet peuvent être associées à {0}. -invalidContentTypeForSchemaExceptionMessage = 'content-type' invalide trouvé pour le schéma : {0} -openApiRequestStyleInvalidForParameterExceptionMessage = Le style de la requête OpenApi ne peut pas être {0} pour un paramètre {1}. -pathParameterRequiresRequiredSwitchExceptionMessage = Si l'emplacement du paramètre est 'Path', le paramètre switch 'Required' est obligatoire. -operationIdMustBeUniqueForArrayExceptionMessage = OperationID : {0} doit être unique et ne peut pas être appliqué à un tableau. -operationIdMustBeUniqueExceptionMessage = OperationID : {0} doit être unique. -noOpenApiUrlSuppliedExceptionMessage = Aucune URL OpenAPI fournie pour {0}. -noTitleSuppliedForPageExceptionMessage = Aucun titre fourni pour la page {0}. -noRoutePathSuppliedForPageExceptionMessage = Aucun chemin de route fourni pour la page {0}. -swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = Cette version de Swagger-Editor ne prend pas en charge OpenAPI 3.1 -rapidPdfDoesNotSupportOpenApi31ExceptionMessage = L'outil de documentation RapidPdf ne prend pas en charge OpenAPI 3.1 -definitionTagNotDefinedExceptionMessage = Tag de définition {0} non défini. -scopedVariableNotFoundExceptionMessage = Variable d'étendue non trouvée : {0} -noSecretVaultRegisteredExceptionMessage = Aucun coffre-fort de secrets enregistré sous le nom '{0}'. -invalidStrictTransportSecurityDurationExceptionMessage = Durée Strict-Transport-Security invalide fournie : {0}. Doit être supérieure à 0. -durationMustBeZeroOrGreaterExceptionMessage = La durée doit être égale ou supérieure à 0, mais a obtenu : {0}s -taskAlreadyDefinedExceptionMessage = [Tâche] {0} : Tâche déjà définie. -maximumConcurrentTasksInvalidExceptionMessage = Le nombre maximum de tâches simultanées doit être >=1, mais a obtenu : {0} -maximumConcurrentTasksLessThanMinimumExceptionMessage = Le nombre maximum de tâches simultanées ne peut pas être inférieur au minimum de {0}, mais a obtenu : {1} -taskDoesNotExistExceptionMessage = La tâche '{0}' n'existe pas. -cacheStorageNotFoundForRetrieveExceptionMessage = Le stockage de cache nommé '{0}' est introuvable lors de la tentative de récupération de l'élément mis en cache '{1}'. -cacheStorageNotFoundForSetExceptionMessage = Le stockage de cache nommé '{0}' est introuvable lors de la tentative de définition de l'élément mis en cache '{1}'. -cacheStorageNotFoundForExistsExceptionMessage = Le stockage de cache nommé '{0}' est introuvable lors de la tentative de vérification de l'existence de l'élément mis en cache '{1}'. -cacheStorageNotFoundForRemoveExceptionMessage = Le stockage de cache nommé '{0}' est introuvable lors de la tentative de suppression de l'élément mis en cache '{1}'. -cacheStorageNotFoundForClearExceptionMessage = Le stockage de cache nommé '{0}' est introuvable lors de la tentative de vider le cache. -cacheStorageAlreadyExistsExceptionMessage = Un stockage de cache nommé '{0}' existe déjà. -pathToIconForGuiDoesNotExistExceptionMessage = Le chemin vers l'icône pour l'interface graphique n'existe pas: {0} -invalidHostnameSuppliedExceptionMessage = Nom d'hôte fourni invalide: {0} -endpointAlreadyDefinedExceptionMessage = Un point de terminaison nommé '{0}' a déjà été défini. -certificateExpiredExceptionMessage = Le certificat '{0}' a expiré: {1} -endpointNotDefinedForRedirectingExceptionMessage = Un point de terminaison nommé '{0}' n'a pas été défini pour la redirection. -fileWatcherAlreadyDefinedExceptionMessage = Un Observateur de fichiers nommé '{0}' a déjà été défini. -handlerAlreadyDefinedExceptionMessage = [{0}] {1}: Handler déjà défini. -maxDaysInvalidExceptionMessage = MaxDays doit être égal ou supérieur à 0, mais a obtenu: {0} -maxSizeInvalidExceptionMessage = MaxSize doit être égal ou supérieur à 0, mais a obtenu: {0} -loggingMethodAlreadyDefinedExceptionMessage = Méthode de journalisation déjà définie: {0} -loggingMethodRequiresValidScriptBlockExceptionMessage = La méthode de sortie fournie pour la méthode de journalisation '{0}' nécessite un ScriptBlock valide. -csrfCookieRequiresSecretExceptionMessage = Lors de l'utilisation de cookies pour CSRF, un Secret est requis. Vous pouvez soit fournir un Secret, soit définir le Secret global du Cookie - (Set-PodeCookieSecret '' -Global) -bodyParserAlreadyDefinedForContentTypeExceptionMessage = Un analyseur de corps est déjà défini pour le type de contenu {0}. -middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: Middleware déjà défini. -parameterNotSuppliedInRequestExceptionMessage = Un paramètre nommé '{0}' n'a pas été fourni dans la demande ou aucune donnée n'est disponible. -noDataForFileUploadedExceptionMessage = Aucune donnée pour le fichier '{0}' n'a été téléchargée dans la demande. -viewsFolderNameAlreadyExistsExceptionMessage = Le nom du dossier Views existe déjà: {0} -viewsPathDoesNotExistExceptionMessage = Le chemin des Views n'existe pas: {0} -timerAlreadyDefinedExceptionMessage = [Minuteur] {0}: Minuteur déjà défini. -timerParameterMustBeGreaterThanZeroExceptionMessage = [Minuteur] {0}: {1} doit être supérieur à 0. -timerDoesNotExistExceptionMessage = Minuteur '{0}' n'existe pas. -mutexAlreadyExistsExceptionMessage = Un mutex avec le nom suivant existe déjà: {0} -noMutexFoundExceptionMessage = Aucun mutex trouvé appelé '{0}' -failedToAcquireMutexOwnershipExceptionMessage = Échec de l'acquisition de la propriété du mutex. Nom du mutex: {0} -semaphoreAlreadyExistsExceptionMessage = Un sémaphore avec le nom suivant existe déjà: {0} -failedToAcquireSemaphoreOwnershipExceptionMessage = Échec de l'acquisition de la propriété du sémaphore. Nom du sémaphore: {0} -scheduleAlreadyDefinedExceptionMessage = [Calendrier] {0}: Calendrier déjà défini. -scheduleCannotHaveNegativeLimitExceptionMessage = [Calendrier] {0}: Ne peut pas avoir de limite négative. -scheduleEndTimeMustBeInFutureExceptionMessage = [Calendrier] {0}: La valeur de EndTime doit être dans le futur. -scheduleStartTimeAfterEndTimeExceptionMessage = [Calendrier] {0}: Ne peut pas avoir un 'StartTime' après 'EndTime' -maximumConcurrentSchedulesInvalidExceptionMessage = Les calendriers simultanés maximum doivent être >=1 mais obtenu: {0} -maximumConcurrentSchedulesLessThanMinimumExceptionMessage = Les calendriers simultanés maximum ne peuvent pas être inférieurs au minimum de {0} mais obtenu: {1} -scheduleDoesNotExistExceptionMessage = Le calendrier '{0}' n'existe pas. -suppliedDateBeforeScheduleStartTimeExceptionMessage = La date fournie est antérieure à l'heure de début du calendrier à {0} -suppliedDateAfterScheduleEndTimeExceptionMessage = La date fournie est postérieure à l'heure de fin du calendrier à {0} -noSemaphoreFoundExceptionMessage = Aucun sémaphore trouvé appelé '{0}' -noLogicPassedForRouteExceptionMessage = Aucune logique passée pour la Route: {0} -noPathSuppliedForStaticRouteExceptionMessage = [{0}]: Aucun chemin fourni pour la Route statique. -sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: Le chemin source fourni pour la Route statique n'existe pas: {2} -noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Aucune logique passée. -moduleDoesNotContainFunctionExceptionMessage = Le module {0} ne contient pas la fonction {1} à convertir en une Route. -pageNameShouldBeAlphaNumericExceptionMessage = Le nom de la page doit être une valeur alphanumérique valide: {0} -filesHaveChangedMessage = Les fichiers suivants ont été modifiés : -multipleEndpointsForGuiMessage = Plusieurs points de terminaison définis, seul le premier sera utilisé pour l'interface graphique. -openingGuiMessage = Ouverture de l'interface graphique. -listeningOnEndpointsMessage = Écoute sur les {0} point(s) de terminaison suivant(s) [{1} thread(s)] : -specificationMessage = Spécification -documentationMessage = Documentation -restartingServerMessage = Redémarrage du serveur... -doneMessage = Terminé -deprecatedTitleVersionDescriptionWarningMessage = AVERTISSEMENT : Titre, Version et Description sur 'Enable-PodeOpenApi' sont obsolètes. Veuillez utiliser 'Add-PodeOAInfo' à la place. -undefinedOpenApiReferencesMessage = Références OpenAPI non définies : -definitionTagMessage = Définition {0} : -openApiGenerationDocumentErrorMessage = Erreur de génération du document OpenAPI : -infoTitleMandatoryMessage = info.title est obligatoire. -infoVersionMandatoryMessage = info.version est obligatoire. -missingComponentsMessage = Composant(s) manquant(s) -openApiInfoMessage = Informations OpenAPI : -serverLoopingMessage = Boucle du serveur toutes les {0} secondes -iisShutdownMessage = (Arrêt de l'IIS) -terminatingMessage = Terminaison... -eolPowerShellWarningMessage = [AVERTISSEMENT] Pode {0} n'a pas été testé sur PowerShell {1}, car il est en fin de vie. -untestedPowerShellVersionWarningMessage = [AVERTISSEMENT] Pode {0} n'a pas été testé sur PowerShell {1}, car il n'était pas disponible lors de la sortie de Pode. -'@ \ No newline at end of file +@{ + schemaValidationRequiresPowerShell610ExceptionMessage = 'La validation du schéma nécessite PowerShell version 6.1.0 ou supérieure.' + pathOrScriptBlockRequiredExceptionMessage = "Un chemin ou un ScriptBlock est requis pour obtenir les valeurs d'accès personnalisées." + operationIdMustBeUniqueForArrayExceptionMessage = 'OperationID : {0} doit être unique et ne peut pas être appliqué à un tableau.' + endpointNotDefinedForRedirectingExceptionMessage = "Un point de terminaison nommé '{0}' n'a pas été défini pour la redirection." + filesHaveChangedMessage = 'Les fichiers suivants ont été modifiés :' + iisAspnetcoreTokenMissingExceptionMessage = 'Le jeton IIS ASPNETCORE_TOKEN est manquant.' + minValueGreaterThanMaxExceptionMessage = 'La valeur minimale pour {0} ne doit pas être supérieure à la valeur maximale.' + noLogicPassedForRouteExceptionMessage = 'Aucune logique passée pour la Route: {0}' + scriptPathDoesNotExistExceptionMessage = "Le chemin du script n'existe pas : {0}" + mutexAlreadyExistsExceptionMessage = 'Un mutex avec le nom suivant existe déjà: {0}' + listeningOnEndpointsMessage = 'Écoute sur les {0} point(s) de terminaison suivant(s) [{1} thread(s)] :' + unsupportedFunctionInServerlessContextExceptionMessage = "La fonction {0} n'est pas prise en charge dans un contexte sans serveur." + expectedNoJwtSignatureSuppliedExceptionMessage = "Aucune signature JWT n'était attendue." + secretAlreadyMountedExceptionMessage = "Un Secret avec le nom '{0}' a déjà été monté." + failedToAcquireLockExceptionMessage = "Impossible d'acquérir un verrou sur l'objet." + noPathSuppliedForStaticRouteExceptionMessage = '[{0}]: Aucun chemin fourni pour la Route statique.' + invalidHostnameSuppliedExceptionMessage = "Nom d'hôte fourni invalide: {0}" + authMethodAlreadyDefinedExceptionMessage = "Méthode d'authentification déjà définie : {0}" + csrfCookieRequiresSecretExceptionMessage = "Lors de l'utilisation de cookies pour CSRF, un Secret est requis. Vous pouvez soit fournir un Secret, soit définir le Secret global du Cookie - (Set-PodeCookieSecret '' -Global)" + nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 'Un ScriptBlock non vide est requis pour créer une route de page.' + noPropertiesMutuallyExclusiveExceptionMessage = "Le paramètre 'NoProperties' est mutuellement exclusif avec 'Properties', 'MinProperties' et 'MaxProperties'." + incompatiblePodeDllExceptionMessage = 'Une version incompatible existante de Pode.DLL {0} est chargée. La version {1} est requise. Ouvrez une nouvelle session Powershell/pwsh et réessayez.' + accessMethodDoesNotExistExceptionMessage = "La méthode d'accès n'existe pas : {0}." + scheduleAlreadyDefinedExceptionMessage = '[Calendrier] {0}: Calendrier déjà défini.' + secondsValueCannotBeZeroOrLessExceptionMessage = 'La valeur en secondes ne peut pas être 0 ou inférieure pour {0}' + pathToLoadNotFoundExceptionMessage = 'Chemin à charger {0} non trouvé : {1}' + failedToImportModuleExceptionMessage = "Échec de l'importation du module : {0}" + endpointNotExistExceptionMessage = "Un point de terminaison avec le protocole '{0}' et l'adresse '{1}' ou l'adresse locale '{2}' n'existe pas." + terminatingMessage = 'Terminaison...' + noCommandsSuppliedToConvertToRoutesExceptionMessage = 'Aucune commande fournie pour convertir en routes.' + invalidTaskTypeExceptionMessage = "Le type de tâche n'est pas valide, attendu [System.Threading.Tasks.Task] ou [hashtable]." + alreadyConnectedToWebSocketExceptionMessage = "Déjà connecté au WebSocket avec le nom '{0}'" + crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = "La vérification de fin de message CRLF n'est prise en charge que sur les points de terminaison TCP." + testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = "'Test-PodeOAComponentSchema' doit être activé en utilisant 'Enable-PodeOpenApi -EnableSchemaValidation'" + adModuleNotInstalledExceptionMessage = "Le module Active Directory n'est pas installé." + cronExpressionInvalidExceptionMessage = "L'expression Cron doit uniquement comporter 5 parties : {0}" + noSessionToSetOnResponseExceptionMessage = 'Aucune session disponible pour être définie sur la réponse.' + valueOutOfRangeExceptionMessage = "La valeur '{0}' pour {1} n'est pas valide, elle doit être comprise entre {2} et {3}" + loggingMethodAlreadyDefinedExceptionMessage = 'Méthode de journalisation déjà définie: {0}' + noSecretForHmac256ExceptionMessage = 'Aucun secret fourni pour le hachage HMAC256.' + eolPowerShellWarningMessage = "[AVERTISSEMENT] Pode {0} n'a pas été testé sur PowerShell {1}, car il est en fin de vie." + runspacePoolFailedToLoadExceptionMessage = "{0} RunspacePool n'a pas pu être chargé." + noEventRegisteredExceptionMessage = 'Aucun événement {0} enregistré : {1}' + scheduleCannotHaveNegativeLimitExceptionMessage = '[Calendrier] {0}: Ne peut pas avoir de limite négative.' + openApiRequestStyleInvalidForParameterExceptionMessage = 'Le style de la requête OpenApi ne peut pas être {0} pour un paramètre {1}.' + openApiDocumentNotCompliantExceptionMessage = "Le document OpenAPI n'est pas conforme." + taskDoesNotExistExceptionMessage = "La tâche '{0}' n'existe pas." + scopedVariableNotFoundExceptionMessage = "Variable d'étendue non trouvée : {0}" + sessionsRequiredForCsrfExceptionMessage = 'Des sessions sont nécessaires pour utiliser CSRF sauf si vous souhaitez utiliser des cookies.' + nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 'Un ScriptBlock non vide est requis pour la méthode de journalisation.' + credentialsPassedWildcardForHeadersLiteralExceptionMessage = 'Lorsque des Identifiants sont passés, le caractère générique * pour les En-têtes sera pris comme une chaîne littérale et non comme un caractère générique.' + podeNotInitializedExceptionMessage = "Pode n'a pas été initialisé." + multipleEndpointsForGuiMessage = "Plusieurs points de terminaison définis, seul le premier sera utilisé pour l'interface graphique." + operationIdMustBeUniqueExceptionMessage = 'OperationID : {0} doit être unique.' + invalidJsonJwtExceptionMessage = 'Valeur JSON non valide trouvée dans le JWT' + noAlgorithmInJwtHeaderExceptionMessage = "Aucun algorithme fourni dans l'en-tête JWT." + openApiVersionPropertyMandatoryExceptionMessage = 'La propriété Version OpenApi est obligatoire.' + limitValueCannotBeZeroOrLessExceptionMessage = 'La valeur de la limite ne peut pas être 0 ou inférieure pour {0}' + timerDoesNotExistExceptionMessage = "Minuteur '{0}' n'existe pas." + openApiGenerationDocumentErrorMessage = 'Erreur de génération du document OpenAPI :' + routeAlreadyContainsCustomAccessExceptionMessage = "La route '[{0}] {1}' contient déjà un accès personnalisé avec le nom '{2}'" + maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 'Le nombre maximum de threads WebSocket simultanés ne peut pas être inférieur au minimum de {0}, mais a obtenu : {1}' + middlewareAlreadyDefinedExceptionMessage = '[Middleware] {0}: Middleware déjà défini.' + invalidAtomCharacterExceptionMessage = 'Caractère atomique non valide : {0}' + cacheStorageNotFoundForRetrieveExceptionMessage = "Le stockage de cache nommé '{0}' est introuvable lors de la tentative de récupération de l'élément mis en cache '{1}'." + headerMustHaveNameInEncodingContextExceptionMessage = "L'en-tête doit avoir un nom lorsqu'il est utilisé dans un contexte de codage." + moduleDoesNotContainFunctionExceptionMessage = 'Le module {0} ne contient pas la fonction {1} à convertir en une Route.' + pathToIconForGuiDoesNotExistExceptionMessage = "Le chemin vers l'icône pour l'interface graphique n'existe pas: {0}" + noTitleSuppliedForPageExceptionMessage = 'Aucun titre fourni pour la page {0}.' + certificateSuppliedForNonHttpsWssEndpointExceptionMessage = 'Certificat fourni pour un point de terminaison non HTTPS/WSS.' + cannotLockNullObjectExceptionMessage = 'Impossible de verrouiller un objet nul.' + showPodeGuiOnlyAvailableOnWindowsExceptionMessage = 'Show-PodeGui est actuellement disponible uniquement pour Windows PowerShell et PowerShell 7+ sur Windows.' + unlockSecretButNoScriptBlockExceptionMessage = 'Secret de déverrouillage fourni pour le type de coffre-fort personnalisé, mais aucun ScriptBlock de déverrouillage fourni.' + invalidIpAddressExceptionMessage = "L'adresse IP fournie n'est pas valide : {0}" + maxDaysInvalidExceptionMessage = 'MaxDays doit être égal ou supérieur à 0, mais a obtenu: {0}' + noRemoveScriptBlockForVaultExceptionMessage = "Aucun ScriptBlock de suppression fourni pour supprimer des secrets du coffre '{0}'" + noSecretExpectedForNoSignatureExceptionMessage = 'Aucun secret attendu pour aucune signature.' + noCertificateFoundExceptionMessage = "Aucun certificat n'a été trouvé dans {0}{1} pour '{2}'" + minValueInvalidExceptionMessage = "La valeur minimale '{0}' pour {1} n'est pas valide, elle doit être supérieure ou égale à {2}" + accessRequiresAuthenticationOnRoutesExceptionMessage = "L'accès nécessite une authentification sur les routes." + noSecretForHmac384ExceptionMessage = 'Aucun secret fourni pour le hachage HMAC384.' + windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = "Le support de l'authentification locale Windows est uniquement pour Windows." + definitionTagNotDefinedExceptionMessage = 'Tag de définition {0} non défini.' + noComponentInDefinitionExceptionMessage = "Aucun composant du type {0} nommé {1} n'est disponible dans la définition {2}." + noSmtpHandlersDefinedExceptionMessage = 'Aucun gestionnaire SMTP défini.' + sessionMiddlewareAlreadyInitializedExceptionMessage = 'Le Middleware de session a déjà été initialisé.' + reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = "La fonctionnalité du composant réutilisable 'pathItems' n'est pas disponible dans OpenAPI v3.0." + wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 'Le caractère générique * pour les En-têtes est incompatible avec le commutateur AutoHeaders.' + noDataForFileUploadedExceptionMessage = "Aucune donnée pour le fichier '{0}' n'a été téléchargée dans la demande." + sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = "SSE ne peut être configuré que sur les requêtes avec une valeur d'en-tête Accept de text/event-stream." + noSessionAvailableToSaveExceptionMessage = 'Aucune session disponible pour sauvegarder.' + pathParameterRequiresRequiredSwitchExceptionMessage = "Si l'emplacement du paramètre est 'Path', le paramètre switch 'Required' est obligatoire." + noOpenApiUrlSuppliedExceptionMessage = 'Aucune URL OpenAPI fournie pour {0}.' + maximumConcurrentSchedulesInvalidExceptionMessage = 'Les calendriers simultanés maximum doivent être >=1 mais obtenu: {0}' + snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = 'Les Snapins sont uniquement pris en charge sur Windows PowerShell.' + eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = "La journalisation dans le Visualisateur d'événements n'est prise en charge que sous Windows." + parametersMutuallyExclusiveExceptionMessage = "Les paramètres '{0}' et '{1}' sont mutuellement exclusifs." + pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = "La fonction PathItems n'est pas prise en charge dans OpenAPI v3.0.x" + openApiParameterRequiresNameExceptionMessage = 'Le paramètre OpenApi nécessite un nom spécifié.' + maximumConcurrentTasksLessThanMinimumExceptionMessage = 'Le nombre maximum de tâches simultanées ne peut pas être inférieur au minimum de {0}, mais a obtenu : {1}' + noSemaphoreFoundExceptionMessage = "Aucun sémaphore trouvé appelé '{0}'" + singleValueForIntervalExceptionMessage = "Vous ne pouvez fournir qu'une seule valeur {0} lorsque vous utilisez des intervalles." + jwtNotYetValidExceptionMessage = "Le JWT n'est pas encore valide pour une utilisation." + verbAlreadyDefinedForUrlExceptionMessage = '[Verbe] {0} : Déjà défini pour {1}' + noSecretNamedMountedExceptionMessage = "Aucun Secret nommé '{0}' n'a été monté." + moduleOrVersionNotFoundExceptionMessage = 'Module ou version introuvable sur {0} : {1}@{2}' + noScriptBlockSuppliedExceptionMessage = 'Aucun ScriptBlock fourni.' + noSecretVaultRegisteredExceptionMessage = "Aucun coffre-fort de secrets enregistré sous le nom '{0}'." + nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = 'Un nom est requis pour le point de terminaison si le paramètre RedirectTo est fourni.' + openApiLicenseObjectRequiresNameExceptionMessage = "L'objet OpenAPI 'license' nécessite la propriété 'name'. Utilisez le paramètre -LicenseName." + sourcePathDoesNotExistForStaticRouteExceptionMessage = "[{0})] {1}: Le chemin source fourni pour la Route statique n'existe pas: {2}" + noNameForWebSocketDisconnectExceptionMessage = 'Aucun Nom fourni pour déconnecter le WebSocket.' + certificateExpiredExceptionMessage = "Le certificat '{0}' a expiré: {1}" + secretVaultUnlockExpiryDateInPastExceptionMessage = "La date d'expiration du déverrouillage du Coffre-Fort de Secrets est dans le passé (UTC) : {0}" + invalidExceptionTypeExceptionMessage = "L'exception est d'un type non valide, doit être soit WebException soit HttpRequestException, mais a obtenu : {0}" + invalidSecretValueTypeExceptionMessage = "La valeur du secret est d'un type non valide. Types attendus : String, SecureString, HashTable, Byte[], ou PSCredential. Mais a obtenu : {0}" + explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = "Le mode TLS explicite n'est pris en charge que sur les points de terminaison SMTPS et TCPS." + discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = "Le paramètre 'DiscriminatorMapping' ne peut être utilisé que lorsque 'DiscriminatorProperty' est présent." + scriptErrorExceptionMessage = "Erreur '{0}' dans le script {1} {2} (ligne {3}) char {4} en exécutant {5} sur l'objet {6} '{7}' Classe : {8} ClasseBase : {9}" + cannotSupplyIntervalForQuarterExceptionMessage = "Impossible de fournir une valeur d'intervalle pour chaque trimestre." + scheduleEndTimeMustBeInFutureExceptionMessage = '[Calendrier] {0}: La valeur de EndTime doit être dans le futur.' + invalidJwtSignatureSuppliedExceptionMessage = 'Signature JWT fournie invalide.' + noSetScriptBlockForVaultExceptionMessage = "Aucun ScriptBlock de configuration fourni pour mettre à jour/créer des secrets dans le coffre '{0}'" + accessMethodNotExistForMergingExceptionMessage = "La méthode d'accès n'existe pas pour la fusion : {0}" + defaultAuthNotInListExceptionMessage = "L'authentification par défaut '{0}' n'est pas dans la liste d'authentification fournie." + parameterHasNoNameExceptionMessage = "Le paramètre n'a pas de nom. Veuillez donner un nom à ce composant en utilisant le paramètre 'Name'." + methodPathAlreadyDefinedForUrlExceptionMessage = '[{0}] {1} : Déjà défini pour {2}' + fileWatcherAlreadyDefinedExceptionMessage = "Un Observateur de fichiers nommé '{0}' a déjà été défini." + noServiceHandlersDefinedExceptionMessage = 'Aucun gestionnaire de service défini.' + secretRequiredForCustomSessionStorageExceptionMessage = "Un secret est requis lors de l'utilisation d'un stockage de session personnalisé." + secretManagementModuleNotInstalledExceptionMessage = "Le module Microsoft.PowerShell.SecretManagement n'est pas installé." + noPathSuppliedForRouteExceptionMessage = 'Aucun chemin fourni pour la route.' + validationOfAnyOfSchemaNotSupportedExceptionMessage = "La validation d'un schéma qui inclut 'anyof' n'est pas prise en charge." + iisAuthSupportIsForWindowsOnlyExceptionMessage = "Le support de l'authentification IIS est uniquement pour Windows." + oauth2InnerSchemeInvalidExceptionMessage = 'Le OAuth2 InnerScheme ne peut être que Basic ou Form, mais obtenu : {0}' + noRoutePathSuppliedForPageExceptionMessage = 'Aucun chemin de route fourni pour la page {0}.' + cacheStorageNotFoundForExistsExceptionMessage = "Le stockage de cache nommé '{0}' est introuvable lors de la tentative de vérification de l'existence de l'élément mis en cache '{1}'." + handlerAlreadyDefinedExceptionMessage = '[{0}] {1}: Handler déjà défini.' + sessionsNotConfiguredExceptionMessage = "Les sessions n'ont pas été configurées." + propertiesTypeObjectAssociationExceptionMessage = 'Seules les propriétés de type Objet peuvent être associées à {0}.' + sessionsRequiredForSessionPersistentAuthExceptionMessage = "Des sessions sont nécessaires pour utiliser l'authentification persistante par session." + invalidPathWildcardOrDirectoryExceptionMessage = 'Le chemin fourni ne peut pas être un caractère générique ou un répertoire : {0}' + accessMethodAlreadyDefinedExceptionMessage = "Méthode d'accès déjà définie : {0}" + parametersValueOrExternalValueMandatoryExceptionMessage = "Les paramètres 'Value' ou 'ExternalValue' sont obligatoires." + maximumConcurrentTasksInvalidExceptionMessage = 'Le nombre maximum de tâches simultanées doit être >=1, mais a obtenu : {0}' + cannotCreatePropertyWithoutTypeExceptionMessage = "Impossible de créer la propriété car aucun type n'est défini." + authMethodNotExistForMergingExceptionMessage = "La méthode d'authentification n'existe pas pour la fusion : {0}" + maxValueInvalidExceptionMessage = "La valeur maximale '{0}' pour {1} n'est pas valide, elle doit être inférieure ou égale à {2}" + endpointAlreadyDefinedExceptionMessage = "Un point de terminaison nommé '{0}' a déjà été défini." + eventAlreadyRegisteredExceptionMessage = 'Événement {0} déjà enregistré : {1}' + parameterNotSuppliedInRequestExceptionMessage = "Un paramètre nommé '{0}' n'a pas été fourni dans la demande ou aucune donnée n'est disponible." + cacheStorageNotFoundForSetExceptionMessage = "Le stockage de cache nommé '{0}' est introuvable lors de la tentative de définition de l'élément mis en cache '{1}'." + methodPathAlreadyDefinedExceptionMessage = '[{0}] {1} : Déjà défini.' + errorLoggingAlreadyEnabledExceptionMessage = 'La journalisation des erreurs est déjà activée.' + valueForUsingVariableNotFoundExceptionMessage = "Valeur pour '`$using:{0}' introuvable." + rapidPdfDoesNotSupportOpenApi31ExceptionMessage = "L'outil de documentation RapidPdf ne prend pas en charge OpenAPI 3.1" + oauth2ClientSecretRequiredExceptionMessage = "OAuth2 nécessite un Client Secret lorsque PKCE n'est pas utilisé." + invalidBase64JwtExceptionMessage = 'Valeur encodée en Base64 non valide trouvée dans le JWT' + noSessionToCalculateDataHashExceptionMessage = 'Aucune session disponible pour calculer le hachage de données.' + cacheStorageNotFoundForRemoveExceptionMessage = "Le stockage de cache nommé '{0}' est introuvable lors de la tentative de suppression de l'élément mis en cache '{1}'." + csrfMiddlewareNotInitializedExceptionMessage = "Le Middleware CSRF n'a pas été initialisé." + infoTitleMandatoryMessage = 'info.title est obligatoire.' + typeCanOnlyBeAssociatedWithObjectExceptionMessage = "Le type {0} ne peut être associé qu'à un Objet." + userFileDoesNotExistExceptionMessage = "Le fichier utilisateur n'existe pas : {0}" + routeParameterNeedsValidScriptblockExceptionMessage = 'Le paramètre de la route nécessite un ScriptBlock valide et non vide.' + nextTriggerCalculationErrorExceptionMessage = 'Il semble que quelque chose ait mal tourné lors de la tentative de calcul de la prochaine date et heure de déclenchement : {0}' + cannotLockValueTypeExceptionMessage = 'Impossible de verrouiller un [ValueTypes].' + failedToCreateOpenSslCertExceptionMessage = 'Échec de la création du certificat openssl : {0}' + jwtExpiredExceptionMessage = 'Le JWT a expiré.' + openingGuiMessage = "Ouverture de l'interface graphique." + multiTypePropertiesRequireOpenApi31ExceptionMessage = 'Les propriétés multi-types nécessitent OpenApi Version 3.1 ou supérieure.' + noNameForWebSocketRemoveExceptionMessage = 'Aucun Nom fourni pour supprimer le WebSocket.' + maxSizeInvalidExceptionMessage = 'MaxSize doit être égal ou supérieur à 0, mais a obtenu: {0}' + iisShutdownMessage = "(Arrêt de l'IIS)" + cannotUnlockValueTypeExceptionMessage = 'Impossible de déverrouiller un [ValueTypes].' + noJwtSignatureForAlgorithmExceptionMessage = 'Aucune signature JWT fournie pour {0}.' + maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 'Le nombre maximum de threads WebSocket simultanés doit être >=1, mais a obtenu : {0}' + acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = "Le message de reconnaissance n'est pris en charge que sur les points de terminaison SMTP et TCP." + failedToConnectToUrlExceptionMessage = "Échec de la connexion à l'URL : {0}" + failedToAcquireMutexOwnershipExceptionMessage = "Échec de l'acquisition de la propriété du mutex. Nom du mutex: {0}" + sessionsRequiredForOAuth2WithPKCEExceptionMessage = 'Des sessions sont nécessaires pour utiliser OAuth2 avec PKCE.' + failedToConnectToWebSocketExceptionMessage = 'Échec de la connexion au WebSocket : {0}' + unsupportedObjectExceptionMessage = 'Objet non pris en charge' + failedToParseAddressExceptionMessage = "Échec de l'analyse de '{0}' en tant qu'adresse IP/Hôte:Port valide" + mustBeRunningWithAdminPrivilegesExceptionMessage = 'Doit être exécuté avec des privilèges administratifs pour écouter sur des adresses autres que localhost.' + specificationMessage = 'Spécification' + cacheStorageNotFoundForClearExceptionMessage = "Le stockage de cache nommé '{0}' est introuvable lors de la tentative de vider le cache." + restartingServerMessage = 'Redémarrage du serveur...' + cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = "Impossible de fournir un intervalle lorsque le paramètre 'Every' est défini sur None." + unsupportedJwtAlgorithmExceptionMessage = "L'algorithme JWT n'est actuellement pas pris en charge : {0}" + websocketsNotConfiguredForSignalMessagesExceptionMessage = 'Les WebSockets ne sont pas configurés pour envoyer des messages de signal.' + invalidLogicTypeInHashtableMiddlewareExceptionMessage = 'Un Middleware Hashtable fourni a un type de logique non valide. Attendu ScriptBlock, mais a obtenu : {0}' + maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 'Les calendriers simultanés maximum ne peuvent pas être inférieurs au minimum de {0} mais obtenu: {1}' + failedToAcquireSemaphoreOwnershipExceptionMessage = "Échec de l'acquisition de la propriété du sémaphore. Nom du sémaphore: {0}" + propertiesParameterWithoutNameExceptionMessage = "Les paramètres Properties ne peuvent pas être utilisés si la propriété n'a pas de nom." + customSessionStorageMethodNotImplementedExceptionMessage = "Le stockage de session personnalisé n'implémente pas la méthode requise '{0}()'." + authenticationMethodDoesNotExistExceptionMessage = "La méthode d'authentification n'existe pas : {0}" + webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = "La fonction Webhooks n'est pas prise en charge dans OpenAPI v3.0.x" + invalidContentTypeForSchemaExceptionMessage = "'content-type' invalide trouvé pour le schéma : {0}" + noUnlockScriptBlockForVaultExceptionMessage = "Aucun ScriptBlock de déverrouillage fourni pour déverrouiller le coffre '{0}'" + definitionTagMessage = 'Définition {0} :' + failedToOpenRunspacePoolExceptionMessage = "Échec de l'ouverture de RunspacePool : {0}" + verbNoLogicPassedExceptionMessage = '[Verbe] {0} : Aucune logique transmise' + noMutexFoundExceptionMessage = "Aucun mutex trouvé appelé '{0}'" + documentationMessage = 'Documentation' + timerAlreadyDefinedExceptionMessage = '[Minuteur] {0}: Minuteur déjà défini.' + invalidPortExceptionMessage = 'Le port ne peut pas être négatif : {0}' + viewsFolderNameAlreadyExistsExceptionMessage = 'Le nom du dossier Views existe déjà: {0}' + noNameForWebSocketResetExceptionMessage = 'Aucun Nom fourni pour réinitialiser le WebSocket.' + mergeDefaultAuthNotInListExceptionMessage = "L'authentification MergeDefault '{0}' n'est pas dans la liste d'authentification fournie." + descriptionRequiredExceptionMessage = 'Une description est requise.' + pageNameShouldBeAlphaNumericExceptionMessage = 'Le nom de la page doit être une valeur alphanumérique valide: {0}' + defaultValueNotBooleanOrEnumExceptionMessage = "La valeur par défaut n'est pas un booléen et ne fait pas partie de l'énumération." + openApiComponentSchemaDoesNotExistExceptionMessage = "Le schéma du composant OpenApi {0} n'existe pas." + timerParameterMustBeGreaterThanZeroExceptionMessage = '[Minuteur] {0}: {1} doit être supérieur à 0.' + taskTimedOutExceptionMessage = 'La tâche a expiré après {0}ms.' + scheduleStartTimeAfterEndTimeExceptionMessage = "[Calendrier] {0}: Ne peut pas avoir un 'StartTime' après 'EndTime'" + infoVersionMandatoryMessage = 'info.version est obligatoire.' + cannotUnlockNullObjectExceptionMessage = 'Impossible de déverrouiller un objet nul.' + nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = "Un ScriptBlock non vide est requis pour le schéma d'authentification personnalisé." + validationOfOneOfSchemaNotSupportedExceptionMessage = "La validation d'un schéma qui inclut 'oneof' n'est pas prise en charge." + routeParameterCannotBeNullExceptionMessage = "Le paramètre 'Route' ne peut pas être nul." + cacheStorageAlreadyExistsExceptionMessage = "Un stockage de cache nommé '{0}' existe déjà." + loggingMethodRequiresValidScriptBlockExceptionMessage = "La méthode de sortie fournie pour la méthode de journalisation '{0}' nécessite un ScriptBlock valide." + scopedVariableAlreadyDefinedExceptionMessage = 'La variable à portée est déjà définie : {0}' + oauth2RequiresAuthorizeUrlExceptionMessage = "OAuth2 nécessite une URL d'autorisation." + pathNotExistExceptionMessage = "Le chemin n'existe pas : {0}" + noDomainServerNameForWindowsAdAuthExceptionMessage = "Aucun nom de serveur de domaine n'a été fourni pour l'authentification Windows AD." + suppliedDateAfterScheduleEndTimeExceptionMessage = "La date fournie est postérieure à l'heure de fin du calendrier à {0}" + wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 'Le caractère générique * pour les Méthodes est incompatible avec le commutateur AutoMethods.' + cannotSupplyIntervalForYearExceptionMessage = "Impossible de fournir une valeur d'intervalle pour chaque année." + missingComponentsMessage = 'Composant(s) manquant(s)' + invalidStrictTransportSecurityDurationExceptionMessage = 'Durée Strict-Transport-Security invalide fournie : {0}. Doit être supérieure à 0.' + noSecretForHmac512ExceptionMessage = 'Aucun secret fourni pour le hachage HMAC512.' + daysInMonthExceededExceptionMessage = "{0} n'a que {1} jours, mais {2} a été fourni." + nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 'Un ScriptBlock non vide est requis pour la méthode de journalisation personnalisée.' + encodingAttributeOnlyAppliesToMultipartExceptionMessage = "L'attribut d'encodage s'applique uniquement aux corps de requête multipart et application/x-www-form-urlencoded." + suppliedDateBeforeScheduleStartTimeExceptionMessage = "La date fournie est antérieure à l'heure de début du calendrier à {0}" + unlockSecretRequiredExceptionMessage = "Une propriété 'UnlockSecret' est requise lors de l'utilisation de Microsoft.PowerShell.SecretStore" + noLogicPassedForMethodRouteExceptionMessage = '[{0}] {1}: Aucune logique passée.' + bodyParserAlreadyDefinedForContentTypeExceptionMessage = 'Un analyseur de corps est déjà défini pour le type de contenu {0}.' + invalidJwtSuppliedExceptionMessage = 'JWT fourni invalide.' + sessionsRequiredForFlashMessagesExceptionMessage = 'Des sessions sont nécessaires pour utiliser les messages Flash.' + outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = 'La méthode de sortie fournie pour la journalisation des requêtes nécessite un ScriptBlock valide.' + semaphoreAlreadyExistsExceptionMessage = 'Un sémaphore avec le nom suivant existe déjà: {0}' + invalidJwtHeaderAlgorithmSuppliedExceptionMessage = "Algorithme de l'en-tête JWT fourni invalide." + oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = "Le fournisseur OAuth2 ne supporte pas le type de subvention 'password' requis par l'utilisation d'un InnerScheme." + invalidAliasFoundExceptionMessage = 'Alias {0} non valide trouvé : {1}' + scheduleDoesNotExistExceptionMessage = "Le calendrier '{0}' n'existe pas." + accessMethodNotExistExceptionMessage = "La méthode d'accès n'existe pas : {0}" + oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = "Le fournisseur OAuth2 ne supporte pas le type de réponse 'code'." + untestedPowerShellVersionWarningMessage = "[AVERTISSEMENT] Pode {0} n'a pas été testé sur PowerShell {1}, car il n'était pas disponible lors de la sortie de Pode." + secretVaultAlreadyRegisteredAutoImportExceptionMessage = "Un coffre-fort secret avec le nom '{0}' a déjà été enregistré lors de l'importation automatique des coffres-forts secrets." + schemeRequiresValidScriptBlockExceptionMessage = "Le schéma fourni pour le validateur d'authentification '{0}' nécessite un ScriptBlock valide." + serverLoopingMessage = 'Boucle du serveur toutes les {0} secondes' + certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 'Les empreintes digitales/Noms de certificat ne sont pris en charge que sous Windows.' + sseConnectionNameRequiredExceptionMessage = "Un nom de connexion SSE est requis, soit de -Name soit de $`$WebEvent.Sse.Name" + invalidMiddlewareTypeExceptionMessage = "Un des Middlewares fournis est d'un type non valide. Attendu ScriptBlock ou Hashtable, mais a obtenu : {0}" + noSecretForJwtSignatureExceptionMessage = 'Aucun secret fourni pour la signature JWT.' + modulePathDoesNotExistExceptionMessage = "Le chemin du module n'existe pas : {0}" + taskAlreadyDefinedExceptionMessage = '[Tâche] {0} : Tâche déjà définie.' + verbAlreadyDefinedExceptionMessage = '[Verbe] {0} : Déjà défini' + clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 'Les certificats client ne sont pris en charge que sur les points de terminaison HTTPS.' + endpointNameNotExistExceptionMessage = "Un point de terminaison avec le nom '{0}' n'existe pas." + middlewareNoLogicSuppliedExceptionMessage = '[Middleware] : Aucune logique fournie dans le ScriptBlock.' + scriptBlockRequiredForMergingUsersExceptionMessage = 'Un ScriptBlock est requis pour fusionner plusieurs utilisateurs authentifiés en un seul objet lorsque Valid est All.' + secretVaultAlreadyRegisteredExceptionMessage = "Un Coffre-Fort de Secrets avec le nom '{0}' a déjà été enregistré{1}." + deprecatedTitleVersionDescriptionWarningMessage = "AVERTISSEMENT : Titre, Version et Description sur 'Enable-PodeOpenApi' sont obsolètes. Veuillez utiliser 'Add-PodeOAInfo' à la place." + undefinedOpenApiReferencesMessage = 'Références OpenAPI non définies :' + doneMessage = 'Terminé' + swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = 'Cette version de Swagger-Editor ne prend pas en charge OpenAPI 3.1' + durationMustBeZeroOrGreaterExceptionMessage = 'La durée doit être égale ou supérieure à 0, mais a obtenu : {0}s' + viewsPathDoesNotExistExceptionMessage = "Le chemin des Views n'existe pas: {0}" + discriminatorIncompatibleWithAllOfExceptionMessage = "Le paramètre 'Discriminator' est incompatible avec 'allOf'." + noNameForWebSocketSendMessageExceptionMessage = 'Aucun Nom fourni pour envoyer un message au WebSocket.' + hashtableMiddlewareNoLogicExceptionMessage = "Un Middleware Hashtable fourni n'a aucune logique définie." + openApiInfoMessage = 'Informations OpenAPI :' + invalidSchemeForAuthValidatorExceptionMessage = "Le schéma '{0}' fourni pour le validateur d'authentification '{1}' nécessite un ScriptBlock valide." + sseFailedToBroadcastExceptionMessage = 'SSE a échoué à diffuser en raison du niveau de diffusion SSE défini pour {0} : {1}.' + adModuleWindowsOnlyExceptionMessage = 'Le module Active Directory est uniquement disponible sur Windows.' + requestLoggingAlreadyEnabledExceptionMessage = 'La journalisation des requêtes est déjà activée.' + invalidAccessControlMaxAgeDurationExceptionMessage = 'Durée Access-Control-Max-Age invalide fournie : {0}. Doit être supérieure à 0.' +} + diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index da2d67c0a..d936a6ff0 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -1,284 +1,285 @@ -ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyExceptionMessage = Il modulo Active Directory è disponibile solo su Windows. -adModuleNotInstalledExceptionMessage = Il modulo Active Directory non è installato. -secretManagementModuleNotInstalledExceptionMessage = Il modulo Microsoft.PowerShell.SecretManagement non è installato. -secretVaultAlreadyRegisteredAutoImportExceptionMessage = Una cassaforte segreta con il nome '{0}' è già stata registrata durante l'importazione automatica delle cassaforti segrete. -failedToOpenRunspacePoolExceptionMessage = Impossibile aprire RunspacePool: {0} -cronExpressionInvalidExceptionMessage = L'espressione Cron dovrebbe essere composta solo da 5 parti: {0} -invalidAliasFoundExceptionMessage = Alias {0} non valido trovato: {1} -invalidAtomCharacterExceptionMessage = Carattere atomo non valido: {0} -minValueGreaterThanMaxExceptionMessage = Il valore minimo per {0} non deve essere maggiore del valore massimo. -minValueInvalidExceptionMessage = Il valore minimo '{0}' per {1} non è valido, dovrebbe essere maggiore o uguale a {2} -maxValueInvalidExceptionMessage = Il valore massimo '{0}' per {1} non è valido, dovrebbe essere minore o uguale a {2} -valueOutOfRangeExceptionMessage = Il valore '{0}' per {1} non è valido, dovrebbe essere compreso tra {2} e {3} -daysInMonthExceededExceptionMessage = {0} ha solo {1} giorni, ma è stato fornito {2}. -nextTriggerCalculationErrorExceptionMessage = Sembra che ci sia stato un errore nel tentativo di calcolare la prossima data e ora del trigger: {0} -incompatiblePodeDllExceptionMessage = È caricata una versione incompatibile esistente di Pode.DLL {0}. È richiesta la versione {1}. Apri una nuova sessione Powershell/pwsh e riprova. -endpointNotExistExceptionMessage = Endpoint con protocollo '{0}' e indirizzo '{1}' o indirizzo locale '{2}' non esiste. -endpointNameNotExistExceptionMessage = Endpoint con nome '{0}' non esiste. -failedToConnectToUrlExceptionMessage = Impossibile connettersi all'URL: {0} -failedToParseAddressExceptionMessage = Impossibile analizzare '{0}' come indirizzo IP/Host:Port valido -invalidIpAddressExceptionMessage = L'indirizzo IP fornito non è valido: {0} -invalidPortExceptionMessage = La porta non può essere negativa: {0} -pathNotExistExceptionMessage = Il percorso non esiste: {0} -noSecretForHmac256ExceptionMessage = Nessun segreto fornito per l'hash HMAC256. -noSecretForHmac384ExceptionMessage = Nessun segreto fornito per l'hash HMAC384. -noSecretForHmac512ExceptionMessage = Nessun segreto fornito per l'hash HMAC512. -noSecretForJwtSignatureExceptionMessage = Nessun segreto fornito per la firma JWT. -noSecretExpectedForNoSignatureExceptionMessage = Non era previsto alcun segreto per nessuna firma. -unsupportedJwtAlgorithmExceptionMessage = L'algoritmo JWT non è attualmente supportato: {0} -invalidBase64JwtExceptionMessage = Valore codificato Base64 non valido trovato in JWT -invalidJsonJwtExceptionMessage = Valore JSON non valido trovato in JWT -unsupportedFunctionInServerlessContextExceptionMessage = La funzione {0} non è supportata in un contesto senza server. -invalidPathWildcardOrDirectoryExceptionMessage = Il percorso fornito non può essere un carattere jolly o una directory: {0} -invalidExceptionTypeExceptionMessage = L'eccezione è di un tipo non valido, dovrebbe essere WebException o HttpRequestException, ma è stato ottenuto: {0} -pathToLoadNotFoundExceptionMessage = Percorso per caricare {0} non trovato: {1} -singleValueForIntervalExceptionMessage = Puoi fornire solo un singolo valore {0} quando si utilizzano gli intervalli. -scriptErrorExceptionMessage = Errore '{0}' nello script {1} {2} (riga {3}) carattere {4} eseguendo {5} su {6} oggetto '{7}' Classe: {8} Classe di base: {9} -noScriptBlockSuppliedExceptionMessage = Nessun ScriptBlock fornito. -iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN è mancante. -propertiesParameterWithoutNameExceptionMessage = I parametri Properties non possono essere utilizzati se la proprietà non ha un nome. -multiTypePropertiesRequireOpenApi31ExceptionMessage = Le proprietà multi-tipo richiedono OpenApi versione 3.1 o superiore. -openApiVersionPropertyMandatoryExceptionMessage = La proprietà della versione OpenApi è obbligatoria. -webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = La funzionalità Webhooks non è supportata in OpenAPI v3.0.x -authenticationMethodDoesNotExistExceptionMessage = Il metodo di autenticazione non esiste: {0} -unsupportedObjectExceptionMessage = Oggetto non supportato -validationOfAnyOfSchemaNotSupportedExceptionMessage = La validazione di uno schema che include 'anyof' non è supportata. -validationOfOneOfSchemaNotSupportedExceptionMessage = La validazione di uno schema che include 'oneof' non è supportata. -cannotCreatePropertyWithoutTypeExceptionMessage = Impossibile creare la proprietà perché non è definito alcun tipo. -headerMustHaveNameInEncodingContextExceptionMessage = L'intestazione deve avere un nome quando viene utilizzata in un contesto di codifica. -descriptionRequiredExceptionMessage = È necessaria una descrizione. -openApiDocumentNotCompliantExceptionMessage = Il documento OpenAPI non è conforme. -noComponentInDefinitionExceptionMessage = Nessun componente del tipo {0} chiamato {1} è disponibile nella definizione {2}. -methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: Già definito. -methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: Già definito per {2} -invalidMiddlewareTypeExceptionMessage = Uno dei Middleware forniti è di un tipo non valido. Previsto ScriptBlock o Hashtable, ma ottenuto: {0} -hashtableMiddlewareNoLogicExceptionMessage = Un Middleware di tipo Hashtable fornito non ha una logica definita. -invalidLogicTypeInHashtableMiddlewareExceptionMessage = Un Middleware di tipo Hashtable fornito ha un tipo di logica non valido. Previsto ScriptBlock, ma ottenuto: {0} -scopedVariableAlreadyDefinedExceptionMessage = Variabile con ambito già definita: {0} -valueForUsingVariableNotFoundExceptionMessage = Impossibile trovare il valore per '`$using:{0}'. -unlockSecretRequiredExceptionMessage = È necessaria una proprietà 'UnlockSecret' quando si utilizza Microsoft.PowerShell.SecretStore -unlockSecretButNoScriptBlockExceptionMessage = Segreto di sblocco fornito per tipo di cassaforte segreta personalizzata, ma nessun ScriptBlock di sblocco fornito. -noUnlockScriptBlockForVaultExceptionMessage = Nessun ScriptBlock di sblocco fornito per sbloccare la cassaforte '{0}' -noSetScriptBlockForVaultExceptionMessage = Nessun ScriptBlock fornito per aggiornare/creare segreti nella cassaforte '{0}' -noRemoveScriptBlockForVaultExceptionMessage = Nessun ScriptBlock fornito per rimuovere segreti dalla cassaforte '{0}' -invalidSecretValueTypeExceptionMessage = Il valore segreto è di un tipo non valido. Tipi previsti: String, SecureString, HashTable, Byte[] o PSCredential. Ma ottenuto: {0} -limitValueCannotBeZeroOrLessExceptionMessage = Il valore limite non può essere 0 o inferiore per {0} -secondsValueCannotBeZeroOrLessExceptionMessage = Il valore dei secondi non può essere 0 o inferiore per {0} -failedToCreateOpenSslCertExceptionMessage = Impossibile creare il certificato openssl: {0} -certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Impronte digitali/nome del certificato supportati solo su Windows. -noCertificateFoundExceptionMessage = Nessun certificato trovato in {0}\{1} per '{2}' -runspacePoolFailedToLoadExceptionMessage = Impossibile caricare RunspacePool per {0}. -noServiceHandlersDefinedExceptionMessage = Non sono stati definiti gestori di servizio. -noSessionToSetOnResponseExceptionMessage = Non c'è nessuna sessione disponibile da impostare sulla risposta. -noSessionToCalculateDataHashExceptionMessage = Nessuna sessione disponibile per calcolare l'hash dei dati. -moduleOrVersionNotFoundExceptionMessage = Modulo o versione non trovati su {0}: {1}@{2} -noSmtpHandlersDefinedExceptionMessage = Non sono stati definiti gestori SMTP. -taskTimedOutExceptionMessage = Il compito è scaduto dopo {0}ms. -verbAlreadyDefinedExceptionMessage = [Verbo] {0}: Già definito -verbAlreadyDefinedForUrlExceptionMessage = [Verbo] {0}: Già definito per {1} -pathOrScriptBlockRequiredExceptionMessage = È necessario un percorso o un ScriptBlock per ottenere i valori di accesso personalizzati. -accessMethodAlreadyDefinedExceptionMessage = Metodo di accesso già definito: {0} -accessMethodNotExistForMergingExceptionMessage = Il metodo di accesso non esiste per l'unione: {0} -routeAlreadyContainsCustomAccessExceptionMessage = Il percorso '[{0}] {1}' contiene già un accesso personalizzato con nome '{2}' -accessMethodNotExistExceptionMessage = Il metodo di accesso non esiste: {0} -pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = La funzionalità PathItems non è supportata in OpenAPI v3.0.x -nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = È richiesto uno ScriptBlock non vuoto per lo schema di autenticazione personalizzato. -oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme può essere solo uno tra Basic o Form, ma è stato ottenuto: {0} -sessionsRequiredForOAuth2WithPKCEExceptionMessage = Sono necessarie sessioni per utilizzare OAuth2 con PKCE -oauth2ClientSecretRequiredExceptionMessage = OAuth2 richiede un Client Secret quando non si utilizza PKCE. -authMethodAlreadyDefinedExceptionMessage = Metodo di autenticazione già definito: {0} -invalidSchemeForAuthValidatorExceptionMessage = Lo schema '{0}' fornito per il validatore di autenticazione '{1}' richiede uno ScriptBlock valido. -sessionsRequiredForSessionPersistentAuthExceptionMessage = Sono necessarie sessioni per utilizzare l'autenticazione persistente della sessione. -oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 richiede che venga fornita un'URL di autorizzazione -authMethodNotExistForMergingExceptionMessage = Il metodo di autenticazione non esiste per la fusione: {0} -mergeDefaultAuthNotInListExceptionMessage = L'autenticazione MergeDefault '{0}' non è nella lista di autenticazione fornita. -defaultAuthNotInListExceptionMessage = L'autenticazione predefinita '{0}' non è nella lista di autenticazione fornita. -scriptBlockRequiredForMergingUsersExceptionMessage = È richiesto uno ScriptBlock per unire più utenti autenticati in un unico oggetto quando Valid è All. -noDomainServerNameForWindowsAdAuthExceptionMessage = Non è stato fornito alcun nome di server di dominio per l'autenticazione AD di Windows -sessionsNotConfiguredExceptionMessage = Le sessioni non sono state configurate. -windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Il supporto per l'autenticazione locale di Windows è solo per Windows. -iisAuthSupportIsForWindowsOnlyExceptionMessage = Il supporto per l'autenticazione IIS è solo per Windows. -noAlgorithmInJwtHeaderExceptionMessage = Nessun algoritmo fornito nell'header JWT. -invalidJwtSuppliedExceptionMessage = JWT fornito non valido. -invalidJwtHeaderAlgorithmSuppliedExceptionMessage = Algoritmo dell'header JWT fornito non valido. -noJwtSignatureForAlgorithmExceptionMessage = Nessuna firma JWT fornita per {0}. -expectedNoJwtSignatureSuppliedExceptionMessage = Si prevedeva che non fosse fornita alcuna firma JWT. -invalidJwtSignatureSuppliedExceptionMessage = Firma JWT fornita non valida. -jwtExpiredExceptionMessage = JWT è scaduto. -jwtNotYetValidExceptionMessage = JWT non è ancora valido per l'uso. -snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Gli Snapin sono supportati solo su Windows PowerShell. -userFileDoesNotExistExceptionMessage = Il file utente non esiste: {0} -schemeRequiresValidScriptBlockExceptionMessage = Lo schema fornito per il validatore di autenticazione '{0}' richiede uno ScriptBlock valido. -oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = Il provider OAuth2 non supporta il tipo di risposta 'code'. -oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = Il provider OAuth2 non supporta il tipo di concessione 'password' richiesto dall'utilizzo di un InnerScheme. -eventAlreadyRegisteredExceptionMessage = Evento {0} già registrato: {1} -noEventRegisteredExceptionMessage = Nessun evento {0} registrato: {1} -sessionsRequiredForFlashMessagesExceptionMessage = Le sessioni sono necessarie per utilizzare i messaggi Flash. -eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = La registrazione nel Visualizzatore eventi è supportata solo su Windows. -nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = È richiesto uno ScriptBlock non vuoto per il metodo di registrazione personalizzato. -requestLoggingAlreadyEnabledExceptionMessage = La registrazione delle richieste è già abilitata. -outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = Il metodo di output fornito per la registrazione delle richieste richiede uno ScriptBlock valido. -errorLoggingAlreadyEnabledExceptionMessage = La registrazione degli errori è già abilitata. -nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = È richiesto uno ScriptBlock non vuoto per il metodo di registrazione. -csrfMiddlewareNotInitializedExceptionMessage = Il Middleware CSRF non è stato inizializzato. -sessionsRequiredForCsrfExceptionMessage = Le sessioni sono necessarie per utilizzare CSRF a meno che non si vogliano usare i cookie. -middlewareNoLogicSuppliedExceptionMessage = [Middleware]: Nessuna logica fornita nello ScriptBlock. -parameterHasNoNameExceptionMessage = Il parametro non ha un nome. Assegna un nome a questo componente usando il parametro 'Name'. -reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = La funzione del componente riutilizzabile 'pathItems' non è disponibile in OpenAPI v3.0. -noPropertiesMutuallyExclusiveExceptionMessage = Il parametro 'NoProperties' è mutuamente esclusivo con 'Properties', 'MinProperties' e 'MaxProperties'. -discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = Il parametro 'DiscriminatorMapping' può essere utilizzato solo quando è presente 'DiscriminatorProperty'. -discriminatorIncompatibleWithAllOfExceptionMessage = Il parametro 'Discriminator' è incompatibile con 'allOf'. -typeCanOnlyBeAssociatedWithObjectExceptionMessage = Il tipo {0} può essere associato solo a un oggetto. -showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui è attualmente disponibile solo per Windows PowerShell e PowerShell 7+ su Windows. -nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = È richiesto un nome per l'endpoint se viene fornito il parametro RedirectTo. -clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = I certificati client sono supportati solo sugli endpoint HTTPS. -explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = La modalità TLS esplicita è supportata solo sugli endpoint SMTPS e TCPS. -acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = Il messaggio di conferma è supportato solo sugli endpoint SMTP e TCP. -crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = Il controllo di fine messaggio CRLF è supportato solo sugli endpoint TCP. -mustBeRunningWithAdminPrivilegesExceptionMessage = Deve essere eseguito con privilegi di amministratore per ascoltare gli indirizzi non locali. -certificateSuppliedForNonHttpsWssEndpointExceptionMessage = Certificato fornito per un endpoint non HTTPS/WSS. -websocketsNotConfiguredForSignalMessagesExceptionMessage = I WebSockets non sono configurati per inviare messaggi di segnale. -noPathSuppliedForRouteExceptionMessage = Nessun percorso fornito per la rotta. -accessRequiresAuthenticationOnRoutesExceptionMessage = L'accesso richiede l'autenticazione sulle rotte. -accessMethodDoesNotExistExceptionMessage = Il metodo di accesso non esiste: {0}. -routeParameterNeedsValidScriptblockExceptionMessage = Il parametro della rotta richiede uno ScriptBlock valido e non vuoto. -noCommandsSuppliedToConvertToRoutesExceptionMessage = Nessun comando fornito per convertirlo in rotte. -nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = È richiesto uno ScriptBlock non vuoto per creare una rotta di pagina. -sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE può essere configurato solo su richieste con un valore di intestazione Accept di text/event-stream. -sseConnectionNameRequiredExceptionMessage = È richiesto un nome di connessione SSE, sia da -Name che da $`$WebEvent.Sse.Name -sseFailedToBroadcastExceptionMessage = SSE non è riuscito a trasmettere a causa del livello di trasmissione SSE definito per {0}: {1}. -podeNotInitializedExceptionMessage = Pode non è stato inizializzato. -invalidTaskTypeExceptionMessage = Il tipo di attività non è valido, previsto [System.Threading.Tasks.Task] o [hashtable]. -cannotLockValueTypeExceptionMessage = Non è possibile bloccare un [ValueTypes]. -cannotLockNullObjectExceptionMessage = Non è possibile bloccare un oggetto nullo. -failedToAcquireLockExceptionMessage = Impossibile acquisire un blocco sull'oggetto. -cannotUnlockValueTypeExceptionMessage = Non è possibile sbloccare un [ValueTypes]. -cannotUnlockNullObjectExceptionMessage = Non è possibile sbloccare un oggetto nullo. -sessionMiddlewareAlreadyInitializedExceptionMessage = Il Middleware della sessione è già stato inizializzato. -customSessionStorageMethodNotImplementedExceptionMessage = L'archiviazione delle sessioni personalizzata non implementa il metodo richiesto '{0}()'. -secretRequiredForCustomSessionStorageExceptionMessage = È necessario un segreto quando si utilizza l'archiviazione delle sessioni personalizzata. -noSessionAvailableToSaveExceptionMessage = Nessuna sessione disponibile per il salvataggio. -cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Impossibile fornire un intervallo quando il parametro 'Every' è impostato su None. -cannotSupplyIntervalForQuarterExceptionMessage = Impossibile fornire un valore di intervallo per ogni trimestre. -cannotSupplyIntervalForYearExceptionMessage = Impossibile fornire un valore di intervallo per ogni anno. -secretVaultAlreadyRegisteredExceptionMessage = Un Vault dei Segreti con il nome '{0}' è già stato registrato{1}. -secretVaultUnlockExpiryDateInPastExceptionMessage = La data di scadenza per sbloccare il Vault dei Segreti è nel passato (UTC): {0} -secretAlreadyMountedExceptionMessage = Un Segreto con il nome '{0}' è già stato montato. -credentialsPassedWildcardForHeadersLiteralExceptionMessage = Quando vengono passate le Credenziali, il carattere jolly * per le Intestazioni sarà considerato come una stringa letterale e non come un carattere jolly. -wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = Il carattere jolly * per le Intestazioni è incompatibile con l'opzione AutoHeaders. -wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = Il carattere jolly * per i Metodi è incompatibile con l'opzione AutoMethods. -invalidAccessControlMaxAgeDurationExceptionMessage = Durata non valida fornita per Access-Control-Max-Age: {0}. Deve essere maggiore di 0. -noNameForWebSocketDisconnectExceptionMessage = Nessun nome fornito per disconnettere il WebSocket. -noNameForWebSocketRemoveExceptionMessage = Nessun nome fornito per rimuovere il WebSocket. -noNameForWebSocketSendMessageExceptionMessage = Nessun nome fornito per inviare un messaggio al WebSocket. -noSecretNamedMountedExceptionMessage = Nessun Segreto con il nome '{0}' è stato montato. -noNameForWebSocketResetExceptionMessage = Nessun nome fornito per reimpostare il WebSocket. -schemaValidationRequiresPowerShell610ExceptionMessage = La convalida dello schema richiede PowerShell versione 6.1.0 o superiore. -routeParameterCannotBeNullExceptionMessage = Il parametro 'Route' non può essere null. -encodingAttributeOnlyAppliesToMultipartExceptionMessage = L'attributo di codifica si applica solo ai corpi delle richieste multipart e application/x-www-form-urlencoded. -testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema' deve essere abilitato utilizzando 'Enable-PodeOpenApi -EnableSchemaValidation' -openApiComponentSchemaDoesNotExistExceptionMessage = Lo schema del componente OpenApi {0} non esiste. -openApiParameterRequiresNameExceptionMessage = Il parametro OpenApi richiede un nome specificato. -openApiLicenseObjectRequiresNameExceptionMessage = L'oggetto OpenAPI 'license' richiede la proprietà 'name'. Utilizzare il parametro -LicenseName. -parametersValueOrExternalValueMandatoryExceptionMessage = I parametri 'Value' o 'ExternalValue' sono obbligatori. -parametersMutuallyExclusiveExceptionMessage = I parametri '{0}' e '{1}' sono mutuamente esclusivi. -maximumConcurrentWebSocketThreadsInvalidExceptionMessage = Il numero massimo di thread WebSocket simultanei deve essere >=1, ma è stato ottenuto: {0} -maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = Il numero massimo di thread WebSocket simultanei non può essere inferiore al minimo di {0}, ma è stato ottenuto: {1} -alreadyConnectedToWebSocketExceptionMessage = Già connesso al WebSocket con il nome '{0}' -failedToConnectToWebSocketExceptionMessage = Connessione al WebSocket non riuscita: {0} -verbNoLogicPassedExceptionMessage = [Verbo] {0}: Nessuna logica passata -scriptPathDoesNotExistExceptionMessage = Il percorso dello script non esiste: {0} -failedToImportModuleExceptionMessage = Importazione del modulo non riuscita: {0} -modulePathDoesNotExistExceptionMessage = Il percorso del modulo non esiste: {0} -defaultValueNotBooleanOrEnumExceptionMessage = Il valore predefinito non è un booleano e non fa parte dell'enum. -propertiesTypeObjectAssociationExceptionMessage = Solo le proprietà di tipo Oggetto possono essere associate a {0}. -invalidContentTypeForSchemaExceptionMessage = 'content-type' non valido trovato per lo schema: {0} -openApiRequestStyleInvalidForParameterExceptionMessage = Lo stile della richiesta OpenApi non può essere {0} per un parametro {1}. -pathParameterRequiresRequiredSwitchExceptionMessage = Se la posizione del parametro è 'Path', il parametro switch 'Required' è obbligatorio. -operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0} deve essere univoco e non può essere applicato a una matrice. -operationIdMustBeUniqueExceptionMessage = OperationID: {0} deve essere univoco. -noOpenApiUrlSuppliedExceptionMessage = Nessun URL OpenAPI fornito per {0}. -noTitleSuppliedForPageExceptionMessage = Nessun titolo fornito per la pagina {0}. -noRoutePathSuppliedForPageExceptionMessage = Nessun percorso di rotta fornito per la pagina {0}. -swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = Questa versione di Swagger-Editor non supporta OpenAPI 3.1 -rapidPdfDoesNotSupportOpenApi31ExceptionMessage = Lo strumento di documentazione RapidPdf non supporta OpenAPI 3.1 -definitionTagNotDefinedExceptionMessage = Tag di definizione {0} non definito. -scopedVariableNotFoundExceptionMessage = Variabile di ambito non trovata: {0} -noSecretVaultRegisteredExceptionMessage = Nessun Vault dei Segreti con il nome '{0}' è stato registrato. -invalidStrictTransportSecurityDurationExceptionMessage = Durata Strict-Transport-Security non valida fornita: {0}. Deve essere maggiore di 0. -durationMustBeZeroOrGreaterExceptionMessage = La durata deve essere 0 o superiore, ma è stato ottenuto: {0}s -taskAlreadyDefinedExceptionMessage = [Attività] {0}: Attività già definita. -maximumConcurrentTasksInvalidExceptionMessage = Il numero massimo di attività simultanee deve essere >=1, ma è stato ottenuto: {0} -maximumConcurrentTasksLessThanMinimumExceptionMessage = Il numero massimo di attività simultanee non può essere inferiore al minimo di {0}, ma è stato ottenuto: {1} -taskDoesNotExistExceptionMessage = L'attività '{0}' non esiste. -cacheStorageNotFoundForRetrieveExceptionMessage = Memoria cache con nome '{0}' non trovata durante il tentativo di recuperare l'elemento memorizzato nella cache '{1}'. -cacheStorageNotFoundForSetExceptionMessage = Memoria cache con nome '{0}' non trovata durante il tentativo di impostare l'elemento memorizzato nella cache '{1}'. -cacheStorageNotFoundForExistsExceptionMessage = Memoria cache con nome '{0}' non trovata durante il tentativo di verificare se l'elemento memorizzato nella cache '{1}' esiste. -cacheStorageNotFoundForRemoveExceptionMessage = Memoria cache con nome '{0}' non trovata durante il tentativo di rimuovere l'elemento memorizzato nella cache '{1}'. -cacheStorageNotFoundForClearExceptionMessage = Memoria cache con nome '{0}' non trovata durante il tentativo di cancellare la cache. -cacheStorageAlreadyExistsExceptionMessage = Memoria cache con nome '{0}' esiste già. -pathToIconForGuiDoesNotExistExceptionMessage = Il percorso dell'icona per la GUI non esiste: {0} -invalidHostnameSuppliedExceptionMessage = Nome host fornito non valido: {0} -endpointAlreadyDefinedExceptionMessage = Un endpoint denominato '{0}' è già stato definito. -certificateExpiredExceptionMessage = Il certificato '{0}' è scaduto: {1} -endpointNotDefinedForRedirectingExceptionMessage = Non è stato definito un endpoint denominato '{0}' per il reindirizzamento. -fileWatcherAlreadyDefinedExceptionMessage = Un File Watcher con il nome '{0}' è già stato definito. -handlerAlreadyDefinedExceptionMessage = [{0}] {1}: Handler già definito. -maxDaysInvalidExceptionMessage = MaxDays deve essere 0 o superiore, ma è stato ottenuto: {0} -maxSizeInvalidExceptionMessage = MaxSize deve essere 0 o superiore, ma è stato ottenuto: {0} -loggingMethodAlreadyDefinedExceptionMessage = Metodo di registrazione già definito: {0} -loggingMethodRequiresValidScriptBlockExceptionMessage = Il metodo di output fornito per il metodo di registrazione '{0}' richiede un ScriptBlock valido. -csrfCookieRequiresSecretExceptionMessage = Quando si usano i cookie per CSRF, è necessario un Segreto. Puoi fornire un Segreto o impostare il segreto globale del Cookie - (Set-PodeCookieSecret '' -Global) -bodyParserAlreadyDefinedForContentTypeExceptionMessage = Un body-parser è già definito per il tipo di contenuto {0}. -middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: Middleware già definito. -parameterNotSuppliedInRequestExceptionMessage = Un parametro chiamato '{0}' non è stato fornito nella richiesta o non ci sono dati disponibili. -noDataForFileUploadedExceptionMessage = Nessun dato per il file '{0}' è stato caricato nella richiesta. -viewsFolderNameAlreadyExistsExceptionMessage = Il nome della cartella Views esiste già: {0} -viewsPathDoesNotExistExceptionMessage = Il percorso delle Views non esiste: {0} -timerAlreadyDefinedExceptionMessage = [Timer] {0}: Timer già definito. -timerParameterMustBeGreaterThanZeroExceptionMessage = [Timer] {0}: {1} deve essere maggiore di 0. -timerDoesNotExistExceptionMessage = Timer '{0}' non esiste. -mutexAlreadyExistsExceptionMessage = Un mutex con il seguente nome esiste già: {0} -noMutexFoundExceptionMessage = Nessun mutex trovato chiamato '{0}' -failedToAcquireMutexOwnershipExceptionMessage = Impossibile acquisire la proprietà del mutex. Nome del mutex: {0} -semaphoreAlreadyExistsExceptionMessage = Un semaforo con il seguente nome esiste già: {0} -failedToAcquireSemaphoreOwnershipExceptionMessage = Impossibile acquisire la proprietà del semaforo. Nome del semaforo: {0} -scheduleAlreadyDefinedExceptionMessage = [Pianificazione] {0}: Pianificazione già definita. -scheduleCannotHaveNegativeLimitExceptionMessage = [Pianificazione] {0}: Non può avere un limite negativo. -scheduleEndTimeMustBeInFutureExceptionMessage = [Pianificazione] {0}: Il valore di EndTime deve essere nel futuro. -scheduleStartTimeAfterEndTimeExceptionMessage = [Pianificazione] {0}: Non può avere un 'StartTime' dopo 'EndTime' -maximumConcurrentSchedulesInvalidExceptionMessage = I programmi concorrenti massimi devono essere >=1 ma ottenuto: {0} -maximumConcurrentSchedulesLessThanMinimumExceptionMessage = I programmi concorrenti massimi non possono essere inferiori al minimo di {0} ma ottenuto: {1} -scheduleDoesNotExistExceptionMessage = Il programma '{0}' non esiste. -suppliedDateBeforeScheduleStartTimeExceptionMessage = La data fornita è precedente all'ora di inizio del programma a {0} -suppliedDateAfterScheduleEndTimeExceptionMessage = La data fornita è successiva all'ora di fine del programma a {0} -noSemaphoreFoundExceptionMessage = Nessun semaforo trovato chiamato '{0}' -noLogicPassedForRouteExceptionMessage = Nessuna logica passata per la rotta: {0} -noPathSuppliedForStaticRouteExceptionMessage = [{0}]: Nessun percorso fornito per la rotta statica. -sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: Il percorso sorgente fornito per la rotta statica non esiste: {2} -noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Nessuna logica passata. -moduleDoesNotContainFunctionExceptionMessage = Il modulo {0} non contiene la funzione {1} da convertire in una rotta. -pageNameShouldBeAlphaNumericExceptionMessage = Il nome della pagina dovrebbe essere un valore alfanumerico valido: {0} -filesHaveChangedMessage = I seguenti file sono stati modificati: -multipleEndpointsForGuiMessage = Sono stati definiti più endpoint, solo il primo sarà utilizzato per la GUI. -openingGuiMessage = Apertura della GUI. -listeningOnEndpointsMessage = In ascolto sui seguenti {0} endpoint [{1} thread]: -specificationMessage = Specifica -documentationMessage = Documentazione -restartingServerMessage = Riavvio del server... -doneMessage = Fatto -deprecatedTitleVersionDescriptionWarningMessage = AVVERTENZA: Titolo, Versione e Descrizione su 'Enable-PodeOpenApi' sono deprecati. Si prega di utilizzare 'Add-PodeOAInfo' invece. -undefinedOpenApiReferencesMessage = Riferimenti OpenAPI non definiti: -definitionTagMessage = Definizione {0}: -openApiGenerationDocumentErrorMessage = Errore nella generazione del documento OpenAPI: -infoTitleMandatoryMessage = info.title è obbligatorio. -infoVersionMandatoryMessage = info.version è obbligatorio. -missingComponentsMessage = Componenti mancanti -openApiInfoMessage = Informazioni OpenAPI: -serverLoopingMessage = Ciclo del server ogni {0} secondi -iisShutdownMessage = (Chiusura IIS) -terminatingMessage = Terminazione... -eolPowerShellWarningMessage = [AVVERTENZA] Pode {0} non è stato testato su PowerShell {1}, poiché è EOL. -untestedPowerShellVersionWarningMessage = [AVVERTENZA] Pode {0} non è stato testato su PowerShell {1}, poiché non era disponibile quando Pode è stato rilasciato. -'@ \ No newline at end of file +@{ + schemaValidationRequiresPowerShell610ExceptionMessage = 'La convalida dello schema richiede PowerShell versione 6.1.0 o superiore.' + pathOrScriptBlockRequiredExceptionMessage = 'È necessario un percorso o un ScriptBlock per ottenere i valori di accesso personalizzati.' + operationIdMustBeUniqueForArrayExceptionMessage = 'OperationID: {0} deve essere univoco e non può essere applicato a una matrice.' + endpointNotDefinedForRedirectingExceptionMessage = "Non è stato definito un endpoint denominato '{0}' per il reindirizzamento." + filesHaveChangedMessage = 'I seguenti file sono stati modificati:' + iisAspnetcoreTokenMissingExceptionMessage = 'IIS ASPNETCORE_TOKEN è mancante.' + minValueGreaterThanMaxExceptionMessage = 'Il valore minimo per {0} non deve essere maggiore del valore massimo.' + noLogicPassedForRouteExceptionMessage = 'Nessuna logica passata per la rotta: {0}' + scriptPathDoesNotExistExceptionMessage = 'Il percorso dello script non esiste: {0}' + mutexAlreadyExistsExceptionMessage = 'Un mutex con il seguente nome esiste già: {0}' + listeningOnEndpointsMessage = 'In ascolto sui seguenti {0} endpoint [{1} thread]:' + unsupportedFunctionInServerlessContextExceptionMessage = 'La funzione {0} non è supportata in un contesto senza server.' + expectedNoJwtSignatureSuppliedExceptionMessage = 'Si prevedeva che non fosse fornita alcuna firma JWT.' + secretAlreadyMountedExceptionMessage = "Un Segreto con il nome '{0}' è già stato montato." + failedToAcquireLockExceptionMessage = "Impossibile acquisire un blocco sull'oggetto." + noPathSuppliedForStaticRouteExceptionMessage = '[{0}]: Nessun percorso fornito per la rotta statica.' + invalidHostnameSuppliedExceptionMessage = 'Nome host fornito non valido: {0}' + authMethodAlreadyDefinedExceptionMessage = 'Metodo di autenticazione già definito: {0}' + csrfCookieRequiresSecretExceptionMessage = "Quando si usano i cookie per CSRF, è necessario un Segreto. Puoi fornire un Segreto o impostare il segreto globale del Cookie - (Set-PodeCookieSecret '' -Global)" + nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 'È richiesto uno ScriptBlock non vuoto per creare una rotta di pagina.' + noPropertiesMutuallyExclusiveExceptionMessage = "Il parametro 'NoProperties' è mutuamente esclusivo con 'Properties', 'MinProperties' e 'MaxProperties'." + incompatiblePodeDllExceptionMessage = 'È caricata una versione incompatibile esistente di Pode.DLL {0}. È richiesta la versione {1}. Apri una nuova sessione Powershell/pwsh e riprova.' + accessMethodDoesNotExistExceptionMessage = 'Il metodo di accesso non esiste: {0}.' + scheduleAlreadyDefinedExceptionMessage = '[Pianificazione] {0}: Pianificazione già definita.' + secondsValueCannotBeZeroOrLessExceptionMessage = 'Il valore dei secondi non può essere 0 o inferiore per {0}' + pathToLoadNotFoundExceptionMessage = 'Percorso per caricare {0} non trovato: {1}' + failedToImportModuleExceptionMessage = 'Importazione del modulo non riuscita: {0}' + endpointNotExistExceptionMessage = "Endpoint con protocollo '{0}' e indirizzo '{1}' o indirizzo locale '{2}' non esiste." + terminatingMessage = 'Terminazione...' + noCommandsSuppliedToConvertToRoutesExceptionMessage = 'Nessun comando fornito per convertirlo in rotte.' + invalidTaskTypeExceptionMessage = 'Il tipo di attività non è valido, previsto [System.Threading.Tasks.Task] o [hashtable].' + alreadyConnectedToWebSocketExceptionMessage = "Già connesso al WebSocket con il nome '{0}'" + crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = 'Il controllo di fine messaggio CRLF è supportato solo sugli endpoint TCP.' + testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = "'Test-PodeOAComponentSchema' deve essere abilitato utilizzando 'Enable-PodeOpenApi -EnableSchemaValidation'" + adModuleNotInstalledExceptionMessage = 'Il modulo Active Directory non è installato.' + cronExpressionInvalidExceptionMessage = "L'espressione Cron dovrebbe essere composta solo da 5 parti: {0}" + noSessionToSetOnResponseExceptionMessage = "Non c'è nessuna sessione disponibile da impostare sulla risposta." + valueOutOfRangeExceptionMessage = "Il valore '{0}' per {1} non è valido, dovrebbe essere compreso tra {2} e {3}" + loggingMethodAlreadyDefinedExceptionMessage = 'Metodo di registrazione già definito: {0}' + noSecretForHmac256ExceptionMessage = "Nessun segreto fornito per l'hash HMAC256." + eolPowerShellWarningMessage = '[AVVERTENZA] Pode {0} non è stato testato su PowerShell {1}, poiché è EOL.' + runspacePoolFailedToLoadExceptionMessage = 'Impossibile caricare RunspacePool per {0}.' + noEventRegisteredExceptionMessage = 'Nessun evento {0} registrato: {1}' + scheduleCannotHaveNegativeLimitExceptionMessage = '[Pianificazione] {0}: Non può avere un limite negativo.' + openApiRequestStyleInvalidForParameterExceptionMessage = 'Lo stile della richiesta OpenApi non può essere {0} per un parametro {1}.' + openApiDocumentNotCompliantExceptionMessage = 'Il documento OpenAPI non è conforme.' + taskDoesNotExistExceptionMessage = "L'attività '{0}' non esiste." + scopedVariableNotFoundExceptionMessage = 'Variabile di ambito non trovata: {0}' + sessionsRequiredForCsrfExceptionMessage = 'Le sessioni sono necessarie per utilizzare CSRF a meno che non si vogliano usare i cookie.' + nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 'È richiesto uno ScriptBlock non vuoto per il metodo di registrazione.' + credentialsPassedWildcardForHeadersLiteralExceptionMessage = 'Quando vengono passate le Credenziali, il carattere jolly * per le Intestazioni sarà considerato come una stringa letterale e non come un carattere jolly.' + podeNotInitializedExceptionMessage = 'Pode non è stato inizializzato.' + multipleEndpointsForGuiMessage = 'Sono stati definiti più endpoint, solo il primo sarà utilizzato per la GUI.' + operationIdMustBeUniqueExceptionMessage = 'OperationID: {0} deve essere univoco.' + invalidJsonJwtExceptionMessage = 'Valore JSON non valido trovato in JWT' + noAlgorithmInJwtHeaderExceptionMessage = "Nessun algoritmo fornito nell'header JWT." + openApiVersionPropertyMandatoryExceptionMessage = 'La proprietà della versione OpenApi è obbligatoria.' + limitValueCannotBeZeroOrLessExceptionMessage = 'Il valore limite non può essere 0 o inferiore per {0}' + timerDoesNotExistExceptionMessage = "Timer '{0}' non esiste." + openApiGenerationDocumentErrorMessage = 'Errore nella generazione del documento OpenAPI:' + routeAlreadyContainsCustomAccessExceptionMessage = "Il percorso '[{0}] {1}' contiene già un accesso personalizzato con nome '{2}'" + maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 'Il numero massimo di thread WebSocket simultanei non può essere inferiore al minimo di {0}, ma è stato ottenuto: {1}' + middlewareAlreadyDefinedExceptionMessage = '[Middleware] {0}: Middleware già definito.' + invalidAtomCharacterExceptionMessage = 'Carattere atomo non valido: {0}' + cacheStorageNotFoundForRetrieveExceptionMessage = "Memoria cache con nome '{0}' non trovata durante il tentativo di recuperare l'elemento memorizzato nella cache '{1}'." + headerMustHaveNameInEncodingContextExceptionMessage = "L'intestazione deve avere un nome quando viene utilizzata in un contesto di codifica." + moduleDoesNotContainFunctionExceptionMessage = 'Il modulo {0} non contiene la funzione {1} da convertire in una rotta.' + pathToIconForGuiDoesNotExistExceptionMessage = "Il percorso dell'icona per la GUI non esiste: {0}" + noTitleSuppliedForPageExceptionMessage = 'Nessun titolo fornito per la pagina {0}.' + certificateSuppliedForNonHttpsWssEndpointExceptionMessage = 'Certificato fornito per un endpoint non HTTPS/WSS.' + cannotLockNullObjectExceptionMessage = 'Non è possibile bloccare un oggetto nullo.' + showPodeGuiOnlyAvailableOnWindowsExceptionMessage = 'Show-PodeGui è attualmente disponibile solo per Windows PowerShell e PowerShell 7+ su Windows.' + unlockSecretButNoScriptBlockExceptionMessage = 'Segreto di sblocco fornito per tipo di cassaforte segreta personalizzata, ma nessun ScriptBlock di sblocco fornito.' + invalidIpAddressExceptionMessage = "L'indirizzo IP fornito non è valido: {0}" + maxDaysInvalidExceptionMessage = 'MaxDays deve essere 0 o superiore, ma è stato ottenuto: {0}' + noRemoveScriptBlockForVaultExceptionMessage = "Nessun ScriptBlock fornito per rimuovere segreti dalla cassaforte '{0}'" + noSecretExpectedForNoSignatureExceptionMessage = 'Non era previsto alcun segreto per nessuna firma.' + noCertificateFoundExceptionMessage = "Nessun certificato trovato in {0}{1} per '{2}'" + minValueInvalidExceptionMessage = "Il valore minimo '{0}' per {1} non è valido, dovrebbe essere maggiore o uguale a {2}" + accessRequiresAuthenticationOnRoutesExceptionMessage = "L'accesso richiede l'autenticazione sulle rotte." + noSecretForHmac384ExceptionMessage = "Nessun segreto fornito per l'hash HMAC384." + windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = "Il supporto per l'autenticazione locale di Windows è solo per Windows." + definitionTagNotDefinedExceptionMessage = 'Tag di definizione {0} non definito.' + noComponentInDefinitionExceptionMessage = 'Nessun componente del tipo {0} chiamato {1} è disponibile nella definizione {2}.' + noSmtpHandlersDefinedExceptionMessage = 'Non sono stati definiti gestori SMTP.' + sessionMiddlewareAlreadyInitializedExceptionMessage = 'Il Middleware della sessione è già stato inizializzato.' + reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = "La funzione del componente riutilizzabile 'pathItems' non è disponibile in OpenAPI v3.0." + wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = "Il carattere jolly * per le Intestazioni è incompatibile con l'opzione AutoHeaders." + noDataForFileUploadedExceptionMessage = "Nessun dato per il file '{0}' è stato caricato nella richiesta." + sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = 'SSE può essere configurato solo su richieste con un valore di intestazione Accept di text/event-stream.' + noSessionAvailableToSaveExceptionMessage = 'Nessuna sessione disponibile per il salvataggio.' + pathParameterRequiresRequiredSwitchExceptionMessage = "Se la posizione del parametro è 'Path', il parametro switch 'Required' è obbligatorio." + noOpenApiUrlSuppliedExceptionMessage = 'Nessun URL OpenAPI fornito per {0}.' + maximumConcurrentSchedulesInvalidExceptionMessage = 'I programmi concorrenti massimi devono essere >=1 ma ottenuto: {0}' + snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = 'Gli Snapin sono supportati solo su Windows PowerShell.' + eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = 'La registrazione nel Visualizzatore eventi è supportata solo su Windows.' + parametersMutuallyExclusiveExceptionMessage = "I parametri '{0}' e '{1}' sono mutuamente esclusivi." + pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 'La funzionalità PathItems non è supportata in OpenAPI v3.0.x' + openApiParameterRequiresNameExceptionMessage = 'Il parametro OpenApi richiede un nome specificato.' + maximumConcurrentTasksLessThanMinimumExceptionMessage = 'Il numero massimo di attività simultanee non può essere inferiore al minimo di {0}, ma è stato ottenuto: {1}' + noSemaphoreFoundExceptionMessage = "Nessun semaforo trovato chiamato '{0}'" + singleValueForIntervalExceptionMessage = 'Puoi fornire solo un singolo valore {0} quando si utilizzano gli intervalli.' + jwtNotYetValidExceptionMessage = "JWT non è ancora valido per l'uso." + verbAlreadyDefinedForUrlExceptionMessage = '[Verbo] {0}: Già definito per {1}' + noSecretNamedMountedExceptionMessage = "Nessun Segreto con il nome '{0}' è stato montato." + moduleOrVersionNotFoundExceptionMessage = 'Modulo o versione non trovati su {0}: {1}@{2}' + noScriptBlockSuppliedExceptionMessage = 'Nessun ScriptBlock fornito.' + noSecretVaultRegisteredExceptionMessage = "Nessun Vault dei Segreti con il nome '{0}' è stato registrato." + nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = "È richiesto un nome per l'endpoint se viene fornito il parametro RedirectTo." + openApiLicenseObjectRequiresNameExceptionMessage = "L'oggetto OpenAPI 'license' richiede la proprietà 'name'. Utilizzare il parametro -LicenseName." + sourcePathDoesNotExistForStaticRouteExceptionMessage = '[{0})] {1}: Il percorso sorgente fornito per la rotta statica non esiste: {2}' + noNameForWebSocketDisconnectExceptionMessage = 'Nessun nome fornito per disconnettere il WebSocket.' + certificateExpiredExceptionMessage = "Il certificato '{0}' è scaduto: {1}" + secretVaultUnlockExpiryDateInPastExceptionMessage = 'La data di scadenza per sbloccare il Vault dei Segreti è nel passato (UTC): {0}' + invalidExceptionTypeExceptionMessage = "L'eccezione è di un tipo non valido, dovrebbe essere WebException o HttpRequestException, ma è stato ottenuto: {0}" + invalidSecretValueTypeExceptionMessage = 'Il valore segreto è di un tipo non valido. Tipi previsti: String, SecureString, HashTable, Byte[] o PSCredential. Ma ottenuto: {0}' + explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 'La modalità TLS esplicita è supportata solo sugli endpoint SMTPS e TCPS.' + discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = "Il parametro 'DiscriminatorMapping' può essere utilizzato solo quando è presente 'DiscriminatorProperty'." + scriptErrorExceptionMessage = "Errore '{0}' nello script {1} {2} (riga {3}) carattere {4} eseguendo {5} su {6} oggetto '{7}' Classe: {8} Classe di base: {9}" + cannotSupplyIntervalForQuarterExceptionMessage = 'Impossibile fornire un valore di intervallo per ogni trimestre.' + scheduleEndTimeMustBeInFutureExceptionMessage = '[Pianificazione] {0}: Il valore di EndTime deve essere nel futuro.' + invalidJwtSignatureSuppliedExceptionMessage = 'Firma JWT fornita non valida.' + noSetScriptBlockForVaultExceptionMessage = "Nessun ScriptBlock fornito per aggiornare/creare segreti nella cassaforte '{0}'" + accessMethodNotExistForMergingExceptionMessage = "Il metodo di accesso non esiste per l'unione: {0}" + defaultAuthNotInListExceptionMessage = "L'autenticazione predefinita '{0}' non è nella lista di autenticazione fornita." + parameterHasNoNameExceptionMessage = "Il parametro non ha un nome. Assegna un nome a questo componente usando il parametro 'Name'." + methodPathAlreadyDefinedForUrlExceptionMessage = '[{0}] {1}: Già definito per {2}' + fileWatcherAlreadyDefinedExceptionMessage = "Un File Watcher con il nome '{0}' è già stato definito." + noServiceHandlersDefinedExceptionMessage = 'Non sono stati definiti gestori di servizio.' + secretRequiredForCustomSessionStorageExceptionMessage = "È necessario un segreto quando si utilizza l'archiviazione delle sessioni personalizzata." + secretManagementModuleNotInstalledExceptionMessage = 'Il modulo Microsoft.PowerShell.SecretManagement non è installato.' + noPathSuppliedForRouteExceptionMessage = 'Nessun percorso fornito per la rotta.' + validationOfAnyOfSchemaNotSupportedExceptionMessage = "La validazione di uno schema che include 'anyof' non è supportata." + iisAuthSupportIsForWindowsOnlyExceptionMessage = "Il supporto per l'autenticazione IIS è solo per Windows." + oauth2InnerSchemeInvalidExceptionMessage = 'OAuth2 InnerScheme può essere solo uno tra Basic o Form, ma è stato ottenuto: {0}' + noRoutePathSuppliedForPageExceptionMessage = 'Nessun percorso di rotta fornito per la pagina {0}.' + cacheStorageNotFoundForExistsExceptionMessage = "Memoria cache con nome '{0}' non trovata durante il tentativo di verificare se l'elemento memorizzato nella cache '{1}' esiste." + handlerAlreadyDefinedExceptionMessage = '[{0}] {1}: Handler già definito.' + sessionsNotConfiguredExceptionMessage = 'Le sessioni non sono state configurate.' + propertiesTypeObjectAssociationExceptionMessage = 'Solo le proprietà di tipo Oggetto possono essere associate a {0}.' + sessionsRequiredForSessionPersistentAuthExceptionMessage = "Sono necessarie sessioni per utilizzare l'autenticazione persistente della sessione." + invalidPathWildcardOrDirectoryExceptionMessage = 'Il percorso fornito non può essere un carattere jolly o una directory: {0}' + accessMethodAlreadyDefinedExceptionMessage = 'Metodo di accesso già definito: {0}' + parametersValueOrExternalValueMandatoryExceptionMessage = "I parametri 'Value' o 'ExternalValue' sono obbligatori." + maximumConcurrentTasksInvalidExceptionMessage = 'Il numero massimo di attività simultanee deve essere >=1, ma è stato ottenuto: {0}' + cannotCreatePropertyWithoutTypeExceptionMessage = 'Impossibile creare la proprietà perché non è definito alcun tipo.' + authMethodNotExistForMergingExceptionMessage = 'Il metodo di autenticazione non esiste per la fusione: {0}' + maxValueInvalidExceptionMessage = "Il valore massimo '{0}' per {1} non è valido, dovrebbe essere minore o uguale a {2}" + endpointAlreadyDefinedExceptionMessage = "Un endpoint denominato '{0}' è già stato definito." + eventAlreadyRegisteredExceptionMessage = 'Evento {0} già registrato: {1}' + parameterNotSuppliedInRequestExceptionMessage = "Un parametro chiamato '{0}' non è stato fornito nella richiesta o non ci sono dati disponibili." + cacheStorageNotFoundForSetExceptionMessage = "Memoria cache con nome '{0}' non trovata durante il tentativo di impostare l'elemento memorizzato nella cache '{1}'." + methodPathAlreadyDefinedExceptionMessage = '[{0}] {1}: Già definito.' + errorLoggingAlreadyEnabledExceptionMessage = 'La registrazione degli errori è già abilitata.' + valueForUsingVariableNotFoundExceptionMessage = "Impossibile trovare il valore per '`$using:{0}'." + rapidPdfDoesNotSupportOpenApi31ExceptionMessage = 'Lo strumento di documentazione RapidPdf non supporta OpenAPI 3.1' + oauth2ClientSecretRequiredExceptionMessage = 'OAuth2 richiede un Client Secret quando non si utilizza PKCE.' + invalidBase64JwtExceptionMessage = 'Valore codificato Base64 non valido trovato in JWT' + noSessionToCalculateDataHashExceptionMessage = "Nessuna sessione disponibile per calcolare l'hash dei dati." + cacheStorageNotFoundForRemoveExceptionMessage = "Memoria cache con nome '{0}' non trovata durante il tentativo di rimuovere l'elemento memorizzato nella cache '{1}'." + csrfMiddlewareNotInitializedExceptionMessage = 'Il Middleware CSRF non è stato inizializzato.' + infoTitleMandatoryMessage = 'info.title è obbligatorio.' + typeCanOnlyBeAssociatedWithObjectExceptionMessage = 'Il tipo {0} può essere associato solo a un oggetto.' + userFileDoesNotExistExceptionMessage = 'Il file utente non esiste: {0}' + routeParameterNeedsValidScriptblockExceptionMessage = 'Il parametro della rotta richiede uno ScriptBlock valido e non vuoto.' + nextTriggerCalculationErrorExceptionMessage = 'Sembra che ci sia stato un errore nel tentativo di calcolare la prossima data e ora del trigger: {0}' + cannotLockValueTypeExceptionMessage = 'Non è possibile bloccare un [ValueTypes].' + failedToCreateOpenSslCertExceptionMessage = 'Impossibile creare il certificato openssl: {0}' + jwtExpiredExceptionMessage = 'JWT è scaduto.' + openingGuiMessage = 'Apertura della GUI.' + multiTypePropertiesRequireOpenApi31ExceptionMessage = 'Le proprietà multi-tipo richiedono OpenApi versione 3.1 o superiore.' + noNameForWebSocketRemoveExceptionMessage = 'Nessun nome fornito per rimuovere il WebSocket.' + maxSizeInvalidExceptionMessage = 'MaxSize deve essere 0 o superiore, ma è stato ottenuto: {0}' + iisShutdownMessage = '(Chiusura IIS)' + cannotUnlockValueTypeExceptionMessage = 'Non è possibile sbloccare un [ValueTypes].' + noJwtSignatureForAlgorithmExceptionMessage = 'Nessuna firma JWT fornita per {0}.' + maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 'Il numero massimo di thread WebSocket simultanei deve essere >=1, ma è stato ottenuto: {0}' + acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 'Il messaggio di conferma è supportato solo sugli endpoint SMTP e TCP.' + failedToConnectToUrlExceptionMessage = "Impossibile connettersi all'URL: {0}" + failedToAcquireMutexOwnershipExceptionMessage = 'Impossibile acquisire la proprietà del mutex. Nome del mutex: {0}' + sessionsRequiredForOAuth2WithPKCEExceptionMessage = 'Sono necessarie sessioni per utilizzare OAuth2 con PKCE' + failedToConnectToWebSocketExceptionMessage = 'Connessione al WebSocket non riuscita: {0}' + unsupportedObjectExceptionMessage = 'Oggetto non supportato' + failedToParseAddressExceptionMessage = "Impossibile analizzare '{0}' come indirizzo IP/Host:Port valido" + mustBeRunningWithAdminPrivilegesExceptionMessage = 'Deve essere eseguito con privilegi di amministratore per ascoltare gli indirizzi non locali.' + specificationMessage = 'Specifica' + cacheStorageNotFoundForClearExceptionMessage = "Memoria cache con nome '{0}' non trovata durante il tentativo di cancellare la cache." + restartingServerMessage = 'Riavvio del server...' + cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = "Impossibile fornire un intervallo quando il parametro 'Every' è impostato su None." + unsupportedJwtAlgorithmExceptionMessage = "L'algoritmo JWT non è attualmente supportato: {0}" + websocketsNotConfiguredForSignalMessagesExceptionMessage = 'I WebSockets non sono configurati per inviare messaggi di segnale.' + invalidLogicTypeInHashtableMiddlewareExceptionMessage = 'Un Middleware di tipo Hashtable fornito ha un tipo di logica non valido. Previsto ScriptBlock, ma ottenuto: {0}' + maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 'I programmi concorrenti massimi non possono essere inferiori al minimo di {0} ma ottenuto: {1}' + failedToAcquireSemaphoreOwnershipExceptionMessage = 'Impossibile acquisire la proprietà del semaforo. Nome del semaforo: {0}' + propertiesParameterWithoutNameExceptionMessage = 'I parametri Properties non possono essere utilizzati se la proprietà non ha un nome.' + customSessionStorageMethodNotImplementedExceptionMessage = "L'archiviazione delle sessioni personalizzata non implementa il metodo richiesto '{0}()'." + authenticationMethodDoesNotExistExceptionMessage = 'Il metodo di autenticazione non esiste: {0}' + webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = 'La funzionalità Webhooks non è supportata in OpenAPI v3.0.x' + invalidContentTypeForSchemaExceptionMessage = "'content-type' non valido trovato per lo schema: {0}" + noUnlockScriptBlockForVaultExceptionMessage = "Nessun ScriptBlock di sblocco fornito per sbloccare la cassaforte '{0}'" + definitionTagMessage = 'Definizione {0}:' + failedToOpenRunspacePoolExceptionMessage = 'Impossibile aprire RunspacePool: {0}' + verbNoLogicPassedExceptionMessage = '[Verbo] {0}: Nessuna logica passata' + noMutexFoundExceptionMessage = "Nessun mutex trovato chiamato '{0}'" + documentationMessage = 'Documentazione' + timerAlreadyDefinedExceptionMessage = '[Timer] {0}: Timer già definito.' + invalidPortExceptionMessage = 'La porta non può essere negativa: {0}' + viewsFolderNameAlreadyExistsExceptionMessage = 'Il nome della cartella Views esiste già: {0}' + noNameForWebSocketResetExceptionMessage = 'Nessun nome fornito per reimpostare il WebSocket.' + mergeDefaultAuthNotInListExceptionMessage = "L'autenticazione MergeDefault '{0}' non è nella lista di autenticazione fornita." + descriptionRequiredExceptionMessage = 'È necessaria una descrizione.' + pageNameShouldBeAlphaNumericExceptionMessage = 'Il nome della pagina dovrebbe essere un valore alfanumerico valido: {0}' + defaultValueNotBooleanOrEnumExceptionMessage = "Il valore predefinito non è un booleano e non fa parte dell'enum." + openApiComponentSchemaDoesNotExistExceptionMessage = 'Lo schema del componente OpenApi {0} non esiste.' + timerParameterMustBeGreaterThanZeroExceptionMessage = '[Timer] {0}: {1} deve essere maggiore di 0.' + taskTimedOutExceptionMessage = 'Il compito è scaduto dopo {0}ms.' + scheduleStartTimeAfterEndTimeExceptionMessage = "[Pianificazione] {0}: Non può avere un 'StartTime' dopo 'EndTime'" + infoVersionMandatoryMessage = 'info.version è obbligatorio.' + cannotUnlockNullObjectExceptionMessage = 'Non è possibile sbloccare un oggetto nullo.' + nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 'È richiesto uno ScriptBlock non vuoto per lo schema di autenticazione personalizzato.' + validationOfOneOfSchemaNotSupportedExceptionMessage = "La validazione di uno schema che include 'oneof' non è supportata." + routeParameterCannotBeNullExceptionMessage = "Il parametro 'Route' non può essere null." + cacheStorageAlreadyExistsExceptionMessage = "Memoria cache con nome '{0}' esiste già." + loggingMethodRequiresValidScriptBlockExceptionMessage = "Il metodo di output fornito per il metodo di registrazione '{0}' richiede un ScriptBlock valido." + scopedVariableAlreadyDefinedExceptionMessage = 'Variabile con ambito già definita: {0}' + oauth2RequiresAuthorizeUrlExceptionMessage = "OAuth2 richiede che venga fornita un'URL di autorizzazione" + pathNotExistExceptionMessage = 'Il percorso non esiste: {0}' + noDomainServerNameForWindowsAdAuthExceptionMessage = "Non è stato fornito alcun nome di server di dominio per l'autenticazione AD di Windows" + suppliedDateAfterScheduleEndTimeExceptionMessage = "La data fornita è successiva all'ora di fine del programma a {0}" + wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = "Il carattere jolly * per i Metodi è incompatibile con l'opzione AutoMethods." + cannotSupplyIntervalForYearExceptionMessage = 'Impossibile fornire un valore di intervallo per ogni anno.' + missingComponentsMessage = 'Componenti mancanti' + invalidStrictTransportSecurityDurationExceptionMessage = 'Durata Strict-Transport-Security non valida fornita: {0}. Deve essere maggiore di 0.' + noSecretForHmac512ExceptionMessage = "Nessun segreto fornito per l'hash HMAC512." + daysInMonthExceededExceptionMessage = '{0} ha solo {1} giorni, ma è stato fornito {2}.' + nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 'È richiesto uno ScriptBlock non vuoto per il metodo di registrazione personalizzato.' + encodingAttributeOnlyAppliesToMultipartExceptionMessage = "L'attributo di codifica si applica solo ai corpi delle richieste multipart e application/x-www-form-urlencoded." + suppliedDateBeforeScheduleStartTimeExceptionMessage = "La data fornita è precedente all'ora di inizio del programma a {0}" + unlockSecretRequiredExceptionMessage = "È necessaria una proprietà 'UnlockSecret' quando si utilizza Microsoft.PowerShell.SecretStore" + noLogicPassedForMethodRouteExceptionMessage = '[{0}] {1}: Nessuna logica passata.' + bodyParserAlreadyDefinedForContentTypeExceptionMessage = 'Un body-parser è già definito per il tipo di contenuto {0}.' + invalidJwtSuppliedExceptionMessage = 'JWT fornito non valido.' + sessionsRequiredForFlashMessagesExceptionMessage = 'Le sessioni sono necessarie per utilizzare i messaggi Flash.' + outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = 'Il metodo di output fornito per la registrazione delle richieste richiede uno ScriptBlock valido.' + semaphoreAlreadyExistsExceptionMessage = 'Un semaforo con il seguente nome esiste già: {0}' + invalidJwtHeaderAlgorithmSuppliedExceptionMessage = "Algoritmo dell'header JWT fornito non valido." + oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = "Il provider OAuth2 non supporta il tipo di concessione 'password' richiesto dall'utilizzo di un InnerScheme." + invalidAliasFoundExceptionMessage = 'Alias {0} non valido trovato: {1}' + scheduleDoesNotExistExceptionMessage = "Il programma '{0}' non esiste." + accessMethodNotExistExceptionMessage = 'Il metodo di accesso non esiste: {0}' + oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = "Il provider OAuth2 non supporta il tipo di risposta 'code'." + untestedPowerShellVersionWarningMessage = '[AVVERTENZA] Pode {0} non è stato testato su PowerShell {1}, poiché non era disponibile quando Pode è stato rilasciato.' + secretVaultAlreadyRegisteredAutoImportExceptionMessage = "Una cassaforte segreta con il nome '{0}' è già stata registrata durante l'importazione automatica delle cassaforti segrete." + schemeRequiresValidScriptBlockExceptionMessage = "Lo schema fornito per il validatore di autenticazione '{0}' richiede uno ScriptBlock valido." + serverLoopingMessage = 'Ciclo del server ogni {0} secondi' + certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 'Impronte digitali/nome del certificato supportati solo su Windows.' + sseConnectionNameRequiredExceptionMessage = "È richiesto un nome di connessione SSE, sia da -Name che da $`$WebEvent.Sse.Name" + invalidMiddlewareTypeExceptionMessage = 'Uno dei Middleware forniti è di un tipo non valido. Previsto ScriptBlock o Hashtable, ma ottenuto: {0}' + noSecretForJwtSignatureExceptionMessage = 'Nessun segreto fornito per la firma JWT.' + modulePathDoesNotExistExceptionMessage = 'Il percorso del modulo non esiste: {0}' + taskAlreadyDefinedExceptionMessage = '[Attività] {0}: Attività già definita.' + verbAlreadyDefinedExceptionMessage = '[Verbo] {0}: Già definito' + clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 'I certificati client sono supportati solo sugli endpoint HTTPS.' + endpointNameNotExistExceptionMessage = "Endpoint con nome '{0}' non esiste." + middlewareNoLogicSuppliedExceptionMessage = '[Middleware]: Nessuna logica fornita nello ScriptBlock.' + scriptBlockRequiredForMergingUsersExceptionMessage = 'È richiesto uno ScriptBlock per unire più utenti autenticati in un unico oggetto quando Valid è All.' + secretVaultAlreadyRegisteredExceptionMessage = "Un Vault dei Segreti con il nome '{0}' è già stato registrato{1}." + deprecatedTitleVersionDescriptionWarningMessage = "AVVERTENZA: Titolo, Versione e Descrizione su 'Enable-PodeOpenApi' sono deprecati. Si prega di utilizzare 'Add-PodeOAInfo' invece." + undefinedOpenApiReferencesMessage = 'Riferimenti OpenAPI non definiti:' + doneMessage = 'Fatto' + swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = 'Questa versione di Swagger-Editor non supporta OpenAPI 3.1' + durationMustBeZeroOrGreaterExceptionMessage = 'La durata deve essere 0 o superiore, ma è stato ottenuto: {0}s' + viewsPathDoesNotExistExceptionMessage = 'Il percorso delle Views non esiste: {0}' + discriminatorIncompatibleWithAllOfExceptionMessage = "Il parametro 'Discriminator' è incompatibile con 'allOf'." + noNameForWebSocketSendMessageExceptionMessage = 'Nessun nome fornito per inviare un messaggio al WebSocket.' + hashtableMiddlewareNoLogicExceptionMessage = 'Un Middleware di tipo Hashtable fornito non ha una logica definita.' + openApiInfoMessage = 'Informazioni OpenAPI:' + invalidSchemeForAuthValidatorExceptionMessage = "Lo schema '{0}' fornito per il validatore di autenticazione '{1}' richiede uno ScriptBlock valido." + sseFailedToBroadcastExceptionMessage = 'SSE non è riuscito a trasmettere a causa del livello di trasmissione SSE definito per {0}: {1}.' + adModuleWindowsOnlyExceptionMessage = 'Il modulo Active Directory è disponibile solo su Windows.' + requestLoggingAlreadyEnabledExceptionMessage = 'La registrazione delle richieste è già abilitata.' + invalidAccessControlMaxAgeDurationExceptionMessage = 'Durata non valida fornita per Access-Control-Max-Age: {0}. Deve essere maggiore di 0.' +} + diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index f84068e7a..bae2cdb4e 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -1,284 +1,285 @@ -ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyExceptionMessage = Active DirectoryモジュールはWindowsでのみ利用可能です。 -adModuleNotInstalledExceptionMessage = Active Directoryモジュールがインストールされていません。 -secretManagementModuleNotInstalledExceptionMessage = Microsoft.PowerShell.SecretManagementモジュールがインストールされていません。 -secretVaultAlreadyRegisteredAutoImportExceptionMessage = シークレットボールト'{0}'は既に登録されています(シークレットボールトの自動インポート中)。 -failedToOpenRunspacePoolExceptionMessage = RunspacePoolのオープンに失敗しました: {0} -cronExpressionInvalidExceptionMessage = Cron式は5つの部分で構成される必要があります: {0} -invalidAliasFoundExceptionMessage = 無効な{0}エイリアスが見つかりました: {1} -invalidAtomCharacterExceptionMessage = 無効なアトム文字: {0} -minValueGreaterThanMaxExceptionMessage = {0}の最小値は最大値を超えることはできません。 -minValueInvalidExceptionMessage = {1}の最小値'{0}'は無効です。{2}以上でなければなりません。 -maxValueInvalidExceptionMessage = {1}の最大値'{0}'は無効です。{2}以下でなければなりません。 -valueOutOfRangeExceptionMessage = {1}の値'{0}'は無効です。{2}から{3}の間でなければなりません。 -daysInMonthExceededExceptionMessage = {0}は{1}日しかありませんが、{2}が指定されました。 -nextTriggerCalculationErrorExceptionMessage = 次のトリガー日時の計算中に問題が発生したようです: {0} -incompatiblePodeDllExceptionMessage = 既存の互換性のないPode.DLLバージョン{0}がロードされています。バージョン{1}が必要です。新しいPowerShell/pwshセッションを開いて再試行してください。 -endpointNotExistExceptionMessage = プロトコル'{0}'、アドレス'{1}'またはローカルアドレス'{2}'のエンドポイントが存在しません。 -endpointNameNotExistExceptionMessage = 名前'{0}'のエンドポイントが存在しません。 -failedToConnectToUrlExceptionMessage = URLへの接続に失敗しました: {0} -failedToParseAddressExceptionMessage = '{0}'を有効なIP/ホスト:ポートアドレスとして解析できませんでした。 -invalidIpAddressExceptionMessage = 提供されたIPアドレスは無効です: {0} -invalidPortExceptionMessage = ポートは負であってはなりません: {0} -pathNotExistExceptionMessage = パスが存在しません: {0} -noSecretForHmac256ExceptionMessage = HMAC256ハッシュに対する秘密が提供されていません。 -noSecretForHmac384ExceptionMessage = HMAC384ハッシュに対する秘密が提供されていません。 -noSecretForHmac512ExceptionMessage = HMAC512ハッシュに対する秘密が提供されていません。 -noSecretForJwtSignatureExceptionMessage = JWT署名に対する秘密が提供されていません。 -noSecretExpectedForNoSignatureExceptionMessage = 署名なしのための秘密が提供されることを期待していませんでした。 -unsupportedJwtAlgorithmExceptionMessage = 現在サポートされていないJWTアルゴリズムです: {0} -invalidBase64JwtExceptionMessage = JWTに無効なBase64エンコード値が見つかりました。 -invalidJsonJwtExceptionMessage = JWTに無効なJSON値が見つかりました。 -unsupportedFunctionInServerlessContextExceptionMessage = サーバーレスコンテキストではサポートされていない関数です: {0} -invalidPathWildcardOrDirectoryExceptionMessage = 指定されたパスはワイルドカードまたはディレクトリにすることはできません: {0} -invalidExceptionTypeExceptionMessage = 例外が無効な型です。WebExceptionまたはHttpRequestExceptionのいずれかである必要がありますが、次の型を取得しました: {0} -pathToLoadNotFoundExceptionMessage = 読み込むパス{0}が見つかりません: {1} -singleValueForIntervalExceptionMessage = インターバルを使用する場合、単一の{0}値しか指定できません。 -scriptErrorExceptionMessage = スクリプト{1} {2}(行{3})のエラー'{0}'(文字{4})が{6}オブジェクト'{7}'の{5}を実行中に発生しました クラス: {8} 基底クラス: {9} -noScriptBlockSuppliedExceptionMessage = ScriptBlockが提供されていません。 -iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKENがありません。 -propertiesParameterWithoutNameExceptionMessage = プロパティに名前がない場合、プロパティパラメータは使用できません。 -multiTypePropertiesRequireOpenApi31ExceptionMessage = 複数タイプのプロパティはOpenApiバージョン3.1以上が必要です。 -openApiVersionPropertyMandatoryExceptionMessage = OpenApiバージョンプロパティは必須です。 -webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = Webhooks機能はOpenAPI v3.0.xではサポートされていません。 -authenticationMethodDoesNotExistExceptionMessage = 認証方法が存在しません: {0} -unsupportedObjectExceptionMessage = サポートされていないオブジェクトです。 -validationOfAnyOfSchemaNotSupportedExceptionMessage = 'anyof'を含むスキーマの検証はサポートされていません。 -validationOfOneOfSchemaNotSupportedExceptionMessage = 'oneof'を含むスキーマの検証はサポートされていません。 -cannotCreatePropertyWithoutTypeExceptionMessage = 型が定義されていないため、プロパティを作成できません。 -headerMustHaveNameInEncodingContextExceptionMessage = エンコーディングコンテキストで使用される場合、ヘッダーには名前が必要です。 -descriptionRequiredExceptionMessage = 説明が必要です。 -openApiDocumentNotCompliantExceptionMessage = OpenAPIドキュメントが準拠していません。 -noComponentInDefinitionExceptionMessage = {2}定義に{0}タイプの名前{1}コンポーネントが利用できません。 -methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: 既に定義されています。 -methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: {2}用に既に定義されています。 -invalidMiddlewareTypeExceptionMessage = 提供されたMiddlewaresの1つが無効な型です。ScriptBlockまたはHashtableのいずれかを期待しましたが、次を取得しました: {0} -hashtableMiddlewareNoLogicExceptionMessage = 提供されたHashtableミドルウェアにロジックが定義されていません。 -invalidLogicTypeInHashtableMiddlewareExceptionMessage = 提供されたHashtableミドルウェアに無効なロジック型があります。ScriptBlockを期待しましたが、次を取得しました: {0} -scopedVariableAlreadyDefinedExceptionMessage = スコープ付き変数が既に定義されています: {0} -valueForUsingVariableNotFoundExceptionMessage = '`$using:{0}'の値が見つかりませんでした。 -unlockSecretRequiredExceptionMessage = Microsoft.PowerShell.SecretStoreを使用する場合、'UnlockSecret'プロパティが必要です。 -unlockSecretButNoScriptBlockExceptionMessage = カスタムシークレットボールトタイプに対してアンロックシークレットが提供されましたが、アンロックスクリプトブロックが提供されていません。 -noUnlockScriptBlockForVaultExceptionMessage = ボールト'{0}'のロック解除に必要なスクリプトブロックが提供されていません。 -noSetScriptBlockForVaultExceptionMessage = ボールト'{0}'のシークレットを更新/作成するためのスクリプトブロックが提供されていません。 -noRemoveScriptBlockForVaultExceptionMessage = ボールト'{0}'のシークレットを削除するためのスクリプトブロックが提供されていません。 -invalidSecretValueTypeExceptionMessage = シークレットの値が無効な型です。期待される型: String、SecureString、HashTable、Byte[]、またはPSCredential。しかし、次を取得しました: {0} -limitValueCannotBeZeroOrLessExceptionMessage = {0}の制限値は0またはそれ以下にすることはできません。 -secondsValueCannotBeZeroOrLessExceptionMessage = {0}の秒数値は0またはそれ以下にすることはできません。 -failedToCreateOpenSslCertExceptionMessage = OpenSSL証明書の作成に失敗しました: {0} -certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Certificate Thumbprints/NameはWindowsでのみサポートされています。 -noCertificateFoundExceptionMessage = '{2}'用の{0}\{1}に証明書が見つかりませんでした。 -runspacePoolFailedToLoadExceptionMessage = {0} RunspacePoolの読み込みに失敗しました。 -noServiceHandlersDefinedExceptionMessage = サービスハンドラが定義されていません。 -noSessionToSetOnResponseExceptionMessage = レスポンスに設定するセッションがありません。 -noSessionToCalculateDataHashExceptionMessage = データハッシュを計算するセッションがありません。 -moduleOrVersionNotFoundExceptionMessage = {0}でモジュールまたはバージョンが見つかりません: {1}@{2} -noSmtpHandlersDefinedExceptionMessage = SMTPハンドラが定義されていません。 -taskTimedOutExceptionMessage = タスクが{0}ミリ秒後にタイムアウトしました。 -verbAlreadyDefinedExceptionMessage = [動詞] {0}: すでに定義されています -verbAlreadyDefinedForUrlExceptionMessage = [動詞] {0}: {1}にすでに定義されています -pathOrScriptBlockRequiredExceptionMessage = カスタムアクセス値のソース化には、パスまたはスクリプトブロックが必要です。 -accessMethodAlreadyDefinedExceptionMessage = アクセス方法はすでに定義されています: {0} -accessMethodNotExistForMergingExceptionMessage = マージするアクセス方法が存在しません: {0} -routeAlreadyContainsCustomAccessExceptionMessage = ルート '[{0}] {1}' はすでに名前 '{2}' のカスタムアクセスを含んでいます -accessMethodNotExistExceptionMessage = アクセス方法が存在しません: {0} -pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = PathItems機能はOpenAPI v3.0.xではサポートされていません。 -nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = カスタム認証スキームには空でないScriptBlockが必要です。 -oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerSchemeはBasicまたはFormのいずれかでなければなりませんが、取得したのは: {0} -sessionsRequiredForOAuth2WithPKCEExceptionMessage = PKCEを使用するOAuth2にはセッションが必要です。 -oauth2ClientSecretRequiredExceptionMessage = PKCEを使用しない場合、OAuth2にはクライアントシークレットが必要です。 -authMethodAlreadyDefinedExceptionMessage = 認証方法はすでに定義されています:{0} -invalidSchemeForAuthValidatorExceptionMessage = '{1}'認証バリデーターのために提供された'{0}'スキームには有効なScriptBlockが必要です。 -sessionsRequiredForSessionPersistentAuthExceptionMessage = セッション持続認証を使用するにはセッションが必要です。 -oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2には認可URLの提供が必要です。 -authMethodNotExistForMergingExceptionMessage = マージするための認証方法は存在しません:{0} -mergeDefaultAuthNotInListExceptionMessage = MergeDefault認証'{0}'は提供された認証リストにありません。 -defaultAuthNotInListExceptionMessage = デフォルト認証'{0}'は提供された認証リストにありません。 -scriptBlockRequiredForMergingUsersExceptionMessage = ValidがAllの場合、複数の認証済みユーザーを1つのオブジェクトにマージするためのScriptBlockが必要です。 -noDomainServerNameForWindowsAdAuthExceptionMessage = Windows AD認証用のドメインサーバー名が提供されていません。 -sessionsNotConfiguredExceptionMessage = セッションが構成されていません。 -windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Windowsローカル認証のサポートはWindowsのみです。 -iisAuthSupportIsForWindowsOnlyExceptionMessage = IIS認証のサポートはWindowsのみです。 -noAlgorithmInJwtHeaderExceptionMessage = JWTヘッダーにアルゴリズムが提供されていません。 -invalidJwtSuppliedExceptionMessage = 無効なJWTが提供されました。 -invalidJwtHeaderAlgorithmSuppliedExceptionMessage = 無効なJWTヘッダーアルゴリズムが提供されました。 -noJwtSignatureForAlgorithmExceptionMessage = {0}のためのJWT署名が提供されていません。 -expectedNoJwtSignatureSuppliedExceptionMessage = 提供されるべきではないJWT署名が予期されました。 -invalidJwtSignatureSuppliedExceptionMessage = 無効なJWT署名が提供されました。 -jwtExpiredExceptionMessage = JWTの有効期限が切れています。 -jwtNotYetValidExceptionMessage = JWTはまだ有効ではありません。 -snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = SnapinsはWindows PowerShellのみでサポートされています。 -userFileDoesNotExistExceptionMessage = ユーザーファイルが存在しません:{0} -schemeRequiresValidScriptBlockExceptionMessage = '{0}'認証バリデーターのために提供されたスキームには有効なScriptBlockが必要です。 -oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = OAuth2プロバイダーは'code' response_typeをサポートしていません。 -oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = OAuth2プロバイダーはInnerSchemeを使用するために必要な'password' grant_typeをサポートしていません。 -eventAlreadyRegisteredExceptionMessage = {0}イベントはすでに登録されています:{1} -noEventRegisteredExceptionMessage = 登録された{0}イベントはありません:{1} -sessionsRequiredForFlashMessagesExceptionMessage = フラッシュメッセージを使用するにはセッションが必要です。 -eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = イベントビューアーロギングはWindowsでのみサポートされています。 -nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = カスタムロギング出力メソッドには空でないScriptBlockが必要です。 -requestLoggingAlreadyEnabledExceptionMessage = リクエストロギングは既に有効になっています。 -outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = リクエストロギングのために提供された出力メソッドには有効なScriptBlockが必要です。 -errorLoggingAlreadyEnabledExceptionMessage = エラーロギングは既に有効になっています。 -nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = ロギングメソッドには空でないScriptBlockが必要です。 -csrfMiddlewareNotInitializedExceptionMessage = CSRFミドルウェアが初期化されていません。 -sessionsRequiredForCsrfExceptionMessage = クッキーを使用しない場合は、CSRFを使用するためにセッションが必要です。 -middlewareNoLogicSuppliedExceptionMessage = [ミドルウェア]: ScriptBlockにロジックが提供されていません。 -parameterHasNoNameExceptionMessage = パラメーターに名前がありません。このコンポーネントに'Name'パラメーターを使用して名前を付けてください。 -reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = OpenAPI v3.0では再利用可能なコンポーネント機能'pathItems'は使用できません。 -noPropertiesMutuallyExclusiveExceptionMessage = パラメーター'NoProperties'は'Properties'、'MinProperties'、および'MaxProperties'と相互排他的です。 -discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = パラメーター'DiscriminatorMapping'は'DiscriminatorProperty'が存在する場合にのみ使用できます。 -discriminatorIncompatibleWithAllOfExceptionMessage = パラメーター'Discriminator'は'allOf'と互換性がありません。 -typeCanOnlyBeAssociatedWithObjectExceptionMessage = タイプ{0}はオブジェクトにのみ関連付けることができます。 -showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGuiは現在、Windows PowerShellおよびWindows上のPowerShell 7+でのみ利用可能です。 -nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = RedirectToパラメーターが提供されている場合、エンドポイントには名前が必要です。 -clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = クライアント証明書はHTTPSエンドポイントでのみサポートされています。 -explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 明示的なTLSモードはSMTPSおよびTCPSエンドポイントでのみサポートされています。 -acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 確認メッセージはSMTPおよびTCPエンドポイントでのみサポートされています。 -crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = CRLFメッセージ終了チェックはTCPエンドポイントでのみサポートされています。 -mustBeRunningWithAdminPrivilegesExceptionMessage = ローカルホスト以外のアドレスでリッスンするには管理者権限で実行する必要があります。 -certificateSuppliedForNonHttpsWssEndpointExceptionMessage = HTTPS/WSS以外のエンドポイントに提供された証明書。 -websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSocketsはシグナルメッセージを送信するように構成されていません。 -noPathSuppliedForRouteExceptionMessage = ルートのパスが提供されていません。 -accessRequiresAuthenticationOnRoutesExceptionMessage = アクセスにはルート上の認証が必要です。 -accessMethodDoesNotExistExceptionMessage = アクセスメソッドが存在しません:{0}。 -routeParameterNeedsValidScriptblockExceptionMessage = ルートパラメーターには有効で空でないScriptBlockが必要です。 -noCommandsSuppliedToConvertToRoutesExceptionMessage = ルートに変換するためのコマンドが提供されていません。 -nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = ページルートを作成するには空でないScriptBlockが必要です。 -sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSEはAcceptヘッダー値がtext/event-streamのリクエストでのみ構成できます。 -sseConnectionNameRequiredExceptionMessage = -Nameまたは`$WebEvent.Sse.NameからSSE接続名が必要です。 -sseFailedToBroadcastExceptionMessage = {0}のSSEブロードキャストレベルが定義されているため、SSEのブロードキャストに失敗しました: {1} -podeNotInitializedExceptionMessage = Podeが初期化されていません。 -invalidTaskTypeExceptionMessage = タスクタイプが無効です。予期されるタイプ:[System.Threading.Tasks.Task]または[hashtable] -cannotLockValueTypeExceptionMessage = [ValueTypes]をロックできません。 -cannotLockNullObjectExceptionMessage = nullオブジェクトをロックできません。 -failedToAcquireLockExceptionMessage = オブジェクトのロックを取得できませんでした。 -cannotUnlockValueTypeExceptionMessage = [ValueTypes]のロックを解除できません。 -cannotUnlockNullObjectExceptionMessage = nullオブジェクトのロックを解除できません。 -sessionMiddlewareAlreadyInitializedExceptionMessage = セッションミドルウェアは既に初期化されています。 -customSessionStorageMethodNotImplementedExceptionMessage = カスタムセッションストレージは必要なメソッド'{0}()'を実装していません。 -secretRequiredForCustomSessionStorageExceptionMessage = カスタムセッションストレージを使用する場合、シークレットが必要です。 -noSessionAvailableToSaveExceptionMessage = 保存するためのセッションが利用できません。 -cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = パラメーター'Every'がNoneに設定されている場合、間隔を提供できません。 -cannotSupplyIntervalForQuarterExceptionMessage = 四半期ごとの間隔値を提供できません。 -cannotSupplyIntervalForYearExceptionMessage = 毎年の間隔値を提供できません。 -secretVaultAlreadyRegisteredExceptionMessage = 名前 '{0}' のシークレットボールトは既に登録されています{1}。 -secretVaultUnlockExpiryDateInPastExceptionMessage = シークレットボールトのアンロック有効期限が過去に設定されています (UTC) :{0} -secretAlreadyMountedExceptionMessage = 名前 '{0}' のシークレットは既にマウントされています。 -credentialsPassedWildcardForHeadersLiteralExceptionMessage = 資格情報が渡されると、ヘッダーのワイルドカード * はワイルドカードとしてではなく、リテラル文字列として解釈されます。 -wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = ヘッダーのワイルドカード * は AutoHeaders スイッチと互換性がありません。 -wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = メソッドのワイルドカード * は AutoMethods スイッチと互換性がありません。 -invalidAccessControlMaxAgeDurationExceptionMessage = 無効な Access-Control-Max-Age 期間が提供されました:{0}。0 より大きくする必要があります。 -noNameForWebSocketDisconnectExceptionMessage = 切断する WebSocket の名前が指定されていません。 -noNameForWebSocketRemoveExceptionMessage = 削除する WebSocket の名前が指定されていません。 -noNameForWebSocketSendMessageExceptionMessage = メッセージを送信する WebSocket の名前が指定されていません。 -noSecretNamedMountedExceptionMessage = 名前 '{0}' のシークレットはマウントされていません。 -noNameForWebSocketResetExceptionMessage = リセットする WebSocket の名前が指定されていません。 -schemaValidationRequiresPowerShell610ExceptionMessage = スキーマ検証には PowerShell バージョン 6.1.0 以上が必要です。 -routeParameterCannotBeNullExceptionMessage = パラメータ 'Route' は null ではいけません。 -encodingAttributeOnlyAppliesToMultipartExceptionMessage = エンコーディング属性は、multipart および application/x-www-form-urlencoded リクエストボディにのみ適用されます。 -testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema' は 'Enable-PodeOpenApi -EnableSchemaValidation' を使用して有効にする必要があります。 -openApiComponentSchemaDoesNotExistExceptionMessage = OpenApi コンポーネントスキーマ {0} は存在しません。 -openApiParameterRequiresNameExceptionMessage = OpenApi パラメータには名前が必要です。 -openApiLicenseObjectRequiresNameExceptionMessage = OpenAPI オブジェクト 'license' には 'name' プロパティが必要です。-LicenseName パラメータを使用してください。 -parametersValueOrExternalValueMandatoryExceptionMessage = パラメータ 'Value' または 'ExternalValue' は必須です。 -parametersMutuallyExclusiveExceptionMessage = パラメータ '{0}' と '{1}' は互いに排他的です。 -maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 最大同時 WebSocket スレッド数は >=1 でなければなりませんが、取得した値は: {0} -maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 最大同時 WebSocket スレッド数は最小値 {0} より小さくてはいけませんが、取得した値は: {1} -alreadyConnectedToWebSocketExceptionMessage = 名前 '{0}' の WebSocket に既に接続されています -failedToConnectToWebSocketExceptionMessage = WebSocket への接続に失敗しました: {0} -verbNoLogicPassedExceptionMessage = [動詞] {0}: ロジックが渡されていません -scriptPathDoesNotExistExceptionMessage = スクリプトパスが存在しません: {0} -failedToImportModuleExceptionMessage = モジュールのインポートに失敗しました: {0} -modulePathDoesNotExistExceptionMessage = モジュールパスが存在しません: {0} -defaultValueNotBooleanOrEnumExceptionMessage = デフォルト値は boolean ではなく、enum に含まれていません。 -propertiesTypeObjectAssociationExceptionMessage = Object 型のプロパティのみが {0} と関連付けられます。 -invalidContentTypeForSchemaExceptionMessage = スキーマの 'content-type' が無効です: {0} -openApiRequestStyleInvalidForParameterExceptionMessage = OpenApi リクエストのスタイルは {1} パラメータに対して {0} であってはなりません。 -pathParameterRequiresRequiredSwitchExceptionMessage = パラメータの場所が 'Path' の場合、スイッチパラメータ 'Required' は必須です。 -operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0} は一意でなければならず、配列に適用できません。 -operationIdMustBeUniqueExceptionMessage = OperationID: {0} は一意でなければなりません。 -noOpenApiUrlSuppliedExceptionMessage = {0} 用の OpenAPI URL が提供されていません。 -noTitleSuppliedForPageExceptionMessage = {0} ページのタイトルが提供されていません。 -noRoutePathSuppliedForPageExceptionMessage = {0} ページのルートパスが提供されていません。 -swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = このバージョンの Swagger-Editor は OpenAPI 3.1 をサポートしていません -rapidPdfDoesNotSupportOpenApi31ExceptionMessage = ドキュメントツール RapidPdf は OpenAPI 3.1 をサポートしていません -definitionTagNotDefinedExceptionMessage = 定義タグ {0} が定義されていません。 -scopedVariableNotFoundExceptionMessage = スコープ変数が見つかりません: {0} -noSecretVaultRegisteredExceptionMessage = 名前 '{0}' のシークレットボールトは登録されていません。 -invalidStrictTransportSecurityDurationExceptionMessage = 無効な Strict-Transport-Security 期間が指定されました: {0}。0 より大きい必要があります。 -durationMustBeZeroOrGreaterExceptionMessage = 期間は 0 以上でなければなりませんが、取得した値は: {0}s -taskAlreadyDefinedExceptionMessage = [タスク] {0}: タスクは既に定義されています。 -maximumConcurrentTasksInvalidExceptionMessage = 最大同時タスク数は >=1 でなければなりませんが、取得した値は: {0} -maximumConcurrentTasksLessThanMinimumExceptionMessage = 最大同時タスク数は最小値 {0} より少なくてはいけませんが、取得した値は: {1} -taskDoesNotExistExceptionMessage = タスク '{0}' は存在しません。 -cacheStorageNotFoundForRetrieveExceptionMessage = キャッシュされたアイテム '{1}' を取得しようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。 -cacheStorageNotFoundForSetExceptionMessage = キャッシュされたアイテム '{1}' を設定しようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。 -cacheStorageNotFoundForExistsExceptionMessage = キャッシュされたアイテム '{1}' が存在するかどうかを確認しようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。 -cacheStorageNotFoundForRemoveExceptionMessage = キャッシュされたアイテム '{1}' を削除しようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。 -cacheStorageNotFoundForClearExceptionMessage = キャッシュをクリアしようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。 -cacheStorageAlreadyExistsExceptionMessage = 名前 '{0}' のキャッシュストレージは既に存在します。 -pathToIconForGuiDoesNotExistExceptionMessage = GUI用アイコンのパスが存在しません: {0} -invalidHostnameSuppliedExceptionMessage = 無効なホスト名が指定されました: {0} -endpointAlreadyDefinedExceptionMessage = 名前 '{0}' のエンドポイントは既に定義されています。 -certificateExpiredExceptionMessage = 証明書 '{0}' の有効期限が切れています: {1} -endpointNotDefinedForRedirectingExceptionMessage = リダイレクトのために名前 '{0}' のエンドポイントが定義されていません。 -fileWatcherAlreadyDefinedExceptionMessage = 名前 '{0}' のファイルウォッチャーは既に定義されています。 -handlerAlreadyDefinedExceptionMessage = [{0}] {1}: ハンドラは既に定義されています。 -maxDaysInvalidExceptionMessage = MaxDaysは0以上でなければなりませんが、受け取った値は: {0} -maxSizeInvalidExceptionMessage = MaxSizeは0以上でなければなりませんが、受け取った値は: {0} -loggingMethodAlreadyDefinedExceptionMessage = ログ記録方法は既に定義されています: {0} -loggingMethodRequiresValidScriptBlockExceptionMessage = '{0}' ログ記録方法のために提供された出力方法は、有効なScriptBlockが必要です。 -csrfCookieRequiresSecretExceptionMessage = CSRFのためにクッキーを使用する場合、秘密が必要です。秘密を提供するか、クッキーのグローバル秘密を設定してください - (Set-PodeCookieSecret '' -Global) -bodyParserAlreadyDefinedForContentTypeExceptionMessage = {0} コンテンツタイプ用のボディパーサーは既に定義されています。 -middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: ミドルウェアは既に定義されています。 -parameterNotSuppliedInRequestExceptionMessage = リクエストに '{0}' という名前のパラメータが提供されていないか、データがありません。 -noDataForFileUploadedExceptionMessage = リクエストでアップロードされたファイル '{0}' のデータがありません。 -viewsFolderNameAlreadyExistsExceptionMessage = ビューのフォルダ名は既に存在します: {0} -viewsPathDoesNotExistExceptionMessage = ビューのパスが存在しません: {0} -timerAlreadyDefinedExceptionMessage = [タイマー] {0}: タイマーはすでに定義されています。 -timerParameterMustBeGreaterThanZeroExceptionMessage = [タイマー] {0}: {1} は 0 より大きくなければなりません。 -timerDoesNotExistExceptionMessage = タイマー '{0}' は存在しません。 -mutexAlreadyExistsExceptionMessage = 次の名前のミューテックスはすでに存在します: {0} -noMutexFoundExceptionMessage = 名前 '{0}' のミューテックスが見つかりません -failedToAcquireMutexOwnershipExceptionMessage = ミューテックスの所有権を取得できませんでした。ミューテックス名: {0} -semaphoreAlreadyExistsExceptionMessage = 次の名前のセマフォはすでに存在します: {0} -failedToAcquireSemaphoreOwnershipExceptionMessage = セマフォの所有権を取得できませんでした。セマフォ名: {0} -scheduleAlreadyDefinedExceptionMessage = [スケジュール] {0}: スケジュールはすでに定義されています。 -scheduleCannotHaveNegativeLimitExceptionMessage = [スケジュール] {0}: 負の制限を持つことはできません。 -scheduleEndTimeMustBeInFutureExceptionMessage = [スケジュール] {0}: EndTime 値は未来に設定する必要があります。 -scheduleStartTimeAfterEndTimeExceptionMessage = [スケジュール] {0}: 'StartTime' が 'EndTime' の後であることはできません -maximumConcurrentSchedulesInvalidExceptionMessage = 最大同時スケジュール数は 1 以上でなければなりませんが、受け取った値: {0} -maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 最大同時スケジュール数は最小 {0} 未満にすることはできませんが、受け取った値: {1} -scheduleDoesNotExistExceptionMessage = スケジュール '{0}' は存在しません。 -suppliedDateBeforeScheduleStartTimeExceptionMessage = 提供された日付はスケジュールの開始時間 {0} より前です -suppliedDateAfterScheduleEndTimeExceptionMessage = 提供された日付はスケジュールの終了時間 {0} の後です -noSemaphoreFoundExceptionMessage = 名前 '{0}' のセマフォが見つかりません -noLogicPassedForRouteExceptionMessage = ルートに対してロジックが渡されませんでした: {0} -noPathSuppliedForStaticRouteExceptionMessage = [{0}]: 静的ルートに対して提供されたパスがありません。 -sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: 静的ルートに対して提供されたソースパスが存在しません: {2} -noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: ロジックが渡されませんでした。 -moduleDoesNotContainFunctionExceptionMessage = モジュール {0} にはルートに変換する関数 {1} が含まれていません。 -pageNameShouldBeAlphaNumericExceptionMessage = ページ名は有効な英数字である必要があります: {0} -filesHaveChangedMessage = 次のファイルが変更されました: -multipleEndpointsForGuiMessage = 複数のエンドポイントが定義されていますが、GUIには最初のエンドポイントのみが使用されます。 -openingGuiMessage = GUIを開いています。 -listeningOnEndpointsMessage = 次の {0} エンドポイントでリッスンしています [{1} スレッド]: -specificationMessage = 仕様 -documentationMessage = ドキュメント -restartingServerMessage = サーバーを再起動しています... -doneMessage = 完了 -deprecatedTitleVersionDescriptionWarningMessage = 警告: 'Enable-PodeOpenApi' のタイトル、バージョン、および説明は非推奨です。代わりに 'Add-PodeOAInfo' を使用してください。 -undefinedOpenApiReferencesMessage = 未定義のOpenAPI参照: -definitionTagMessage = 定義 {0}: -openApiGenerationDocumentErrorMessage = OpenAPI生成ドキュメントエラー: -infoTitleMandatoryMessage = info.title は必須です。 -infoVersionMandatoryMessage = info.version は必須です。 -missingComponentsMessage = 欠落しているコンポーネント -openApiInfoMessage = OpenAPI情報: -serverLoopingMessage = サーバーループ間隔 {0}秒 -iisShutdownMessage = (IIS シャットダウン) -terminatingMessage = 終了中... -eolPowerShellWarningMessage = [警告] Pode {0} は、EOLであるPowerShell {1} でテストされていません。 -untestedPowerShellVersionWarningMessage = [警告] Pode {0} はリリース時に利用可能でなかったため、PowerShell {1} でテストされていません。 -'@ \ No newline at end of file +@{ + schemaValidationRequiresPowerShell610ExceptionMessage = 'スキーマ検証には PowerShell バージョン 6.1.0 以上が必要です。' + pathOrScriptBlockRequiredExceptionMessage = 'カスタムアクセス値のソース化には、パスまたはスクリプトブロックが必要です。' + operationIdMustBeUniqueForArrayExceptionMessage = 'OperationID: {0} は一意でなければならず、配列に適用できません。' + endpointNotDefinedForRedirectingExceptionMessage = "リダイレクトのために名前 '{0}' のエンドポイントが定義されていません。" + filesHaveChangedMessage = '次のファイルが変更されました:' + iisAspnetcoreTokenMissingExceptionMessage = 'IIS ASPNETCORE_TOKENがありません。' + minValueGreaterThanMaxExceptionMessage = '{0}の最小値は最大値を超えることはできません。' + noLogicPassedForRouteExceptionMessage = 'ルートに対してロジックが渡されませんでした: {0}' + scriptPathDoesNotExistExceptionMessage = 'スクリプトパスが存在しません: {0}' + mutexAlreadyExistsExceptionMessage = '次の名前のミューテックスはすでに存在します: {0}' + listeningOnEndpointsMessage = '次の {0} エンドポイントでリッスンしています [{1} スレッド]:' + unsupportedFunctionInServerlessContextExceptionMessage = 'サーバーレスコンテキストではサポートされていない関数です: {0}' + expectedNoJwtSignatureSuppliedExceptionMessage = '提供されるべきではないJWT署名が予期されました。' + secretAlreadyMountedExceptionMessage = "名前 '{0}' のシークレットは既にマウントされています。" + failedToAcquireLockExceptionMessage = 'オブジェクトのロックを取得できませんでした。' + noPathSuppliedForStaticRouteExceptionMessage = '[{0}]: 静的ルートに対して提供されたパスがありません。' + invalidHostnameSuppliedExceptionMessage = '無効なホスト名が指定されました: {0}' + authMethodAlreadyDefinedExceptionMessage = '認証方法はすでに定義されています:{0}' + csrfCookieRequiresSecretExceptionMessage = "CSRFのためにクッキーを使用する場合、秘密が必要です。秘密を提供するか、クッキーのグローバル秘密を設定してください - (Set-PodeCookieSecret '' -Global)" + nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 'ページルートを作成するには空でないScriptBlockが必要です。' + noPropertiesMutuallyExclusiveExceptionMessage = "パラメーター'NoProperties'は'Properties'、'MinProperties'、および'MaxProperties'と相互排他的です。" + incompatiblePodeDllExceptionMessage = '既存の互換性のないPode.DLLバージョン{0}がロードされています。バージョン{1}が必要です。新しいPowerShell/pwshセッションを開いて再試行してください。' + accessMethodDoesNotExistExceptionMessage = 'アクセスメソッドが存在しません:{0}。' + scheduleAlreadyDefinedExceptionMessage = '[スケジュール] {0}: スケジュールはすでに定義されています。' + secondsValueCannotBeZeroOrLessExceptionMessage = '{0}の秒数値は0またはそれ以下にすることはできません。' + pathToLoadNotFoundExceptionMessage = '読み込むパス{0}が見つかりません: {1}' + failedToImportModuleExceptionMessage = 'モジュールのインポートに失敗しました: {0}' + endpointNotExistExceptionMessage = "プロトコル'{0}'、アドレス'{1}'またはローカルアドレス'{2}'のエンドポイントが存在しません。" + terminatingMessage = '終了中...' + noCommandsSuppliedToConvertToRoutesExceptionMessage = 'ルートに変換するためのコマンドが提供されていません。' + invalidTaskTypeExceptionMessage = 'タスクタイプが無効です。予期されるタイプ:[System.Threading.Tasks.Task]または[hashtable]' + alreadyConnectedToWebSocketExceptionMessage = "名前 '{0}' の WebSocket に既に接続されています" + crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = 'CRLFメッセージ終了チェックはTCPエンドポイントでのみサポートされています。' + testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = "'Test-PodeOAComponentSchema' は 'Enable-PodeOpenApi -EnableSchemaValidation' を使用して有効にする必要があります。" + adModuleNotInstalledExceptionMessage = 'Active Directoryモジュールがインストールされていません。' + cronExpressionInvalidExceptionMessage = 'Cron式は5つの部分で構成される必要があります: {0}' + noSessionToSetOnResponseExceptionMessage = 'レスポンスに設定するセッションがありません。' + valueOutOfRangeExceptionMessage = "{1}の値'{0}'は無効です。{2}から{3}の間でなければなりません。" + loggingMethodAlreadyDefinedExceptionMessage = 'ログ記録方法は既に定義されています: {0}' + noSecretForHmac256ExceptionMessage = 'HMAC256ハッシュに対する秘密が提供されていません。' + eolPowerShellWarningMessage = '[警告] Pode {0} は、EOLであるPowerShell {1} でテストされていません。' + runspacePoolFailedToLoadExceptionMessage = '{0} RunspacePoolの読み込みに失敗しました。' + noEventRegisteredExceptionMessage = '登録された{0}イベントはありません:{1}' + scheduleCannotHaveNegativeLimitExceptionMessage = '[スケジュール] {0}: 負の制限を持つことはできません。' + openApiRequestStyleInvalidForParameterExceptionMessage = 'OpenApi リクエストのスタイルは {1} パラメータに対して {0} であってはなりません。' + openApiDocumentNotCompliantExceptionMessage = 'OpenAPIドキュメントが準拠していません。' + taskDoesNotExistExceptionMessage = "タスク '{0}' は存在しません。" + scopedVariableNotFoundExceptionMessage = 'スコープ変数が見つかりません: {0}' + sessionsRequiredForCsrfExceptionMessage = 'クッキーを使用しない場合は、CSRFを使用するためにセッションが必要です。' + nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 'ロギングメソッドには空でないScriptBlockが必要です。' + credentialsPassedWildcardForHeadersLiteralExceptionMessage = '資格情報が渡されると、ヘッダーのワイルドカード * はワイルドカードとしてではなく、リテラル文字列として解釈されます。' + podeNotInitializedExceptionMessage = 'Podeが初期化されていません。' + multipleEndpointsForGuiMessage = '複数のエンドポイントが定義されていますが、GUIには最初のエンドポイントのみが使用されます。' + operationIdMustBeUniqueExceptionMessage = 'OperationID: {0} は一意でなければなりません。' + invalidJsonJwtExceptionMessage = 'JWTに無効なJSON値が見つかりました。' + noAlgorithmInJwtHeaderExceptionMessage = 'JWTヘッダーにアルゴリズムが提供されていません。' + openApiVersionPropertyMandatoryExceptionMessage = 'OpenApiバージョンプロパティは必須です。' + limitValueCannotBeZeroOrLessExceptionMessage = '{0}の制限値は0またはそれ以下にすることはできません。' + timerDoesNotExistExceptionMessage = "タイマー '{0}' は存在しません。" + openApiGenerationDocumentErrorMessage = 'OpenAPI生成ドキュメントエラー:' + routeAlreadyContainsCustomAccessExceptionMessage = "ルート '[{0}] {1}' はすでに名前 '{2}' のカスタムアクセスを含んでいます" + maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = '最大同時 WebSocket スレッド数は最小値 {0} より小さくてはいけませんが、取得した値は: {1}' + middlewareAlreadyDefinedExceptionMessage = '[Middleware] {0}: ミドルウェアは既に定義されています。' + invalidAtomCharacterExceptionMessage = '無効なアトム文字: {0}' + cacheStorageNotFoundForRetrieveExceptionMessage = "キャッシュされたアイテム '{1}' を取得しようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。" + headerMustHaveNameInEncodingContextExceptionMessage = 'エンコーディングコンテキストで使用される場合、ヘッダーには名前が必要です。' + moduleDoesNotContainFunctionExceptionMessage = 'モジュール {0} にはルートに変換する関数 {1} が含まれていません。' + pathToIconForGuiDoesNotExistExceptionMessage = 'GUI用アイコンのパスが存在しません: {0}' + noTitleSuppliedForPageExceptionMessage = '{0} ページのタイトルが提供されていません。' + certificateSuppliedForNonHttpsWssEndpointExceptionMessage = 'HTTPS/WSS以外のエンドポイントに提供された証明書。' + cannotLockNullObjectExceptionMessage = 'nullオブジェクトをロックできません。' + showPodeGuiOnlyAvailableOnWindowsExceptionMessage = 'Show-PodeGuiは現在、Windows PowerShellおよびWindows上のPowerShell 7+でのみ利用可能です。' + unlockSecretButNoScriptBlockExceptionMessage = 'カスタムシークレットボールトタイプに対してアンロックシークレットが提供されましたが、アンロックスクリプトブロックが提供されていません。' + invalidIpAddressExceptionMessage = '提供されたIPアドレスは無効です: {0}' + maxDaysInvalidExceptionMessage = 'MaxDaysは0以上でなければなりませんが、受け取った値は: {0}' + noRemoveScriptBlockForVaultExceptionMessage = "ボールト'{0}'のシークレットを削除するためのスクリプトブロックが提供されていません。" + noSecretExpectedForNoSignatureExceptionMessage = '署名なしのための秘密が提供されることを期待していませんでした。' + noCertificateFoundExceptionMessage = "'{2}'用の{0}{1}に証明書が見つかりませんでした。" + minValueInvalidExceptionMessage = "{1}の最小値'{0}'は無効です。{2}以上でなければなりません。" + accessRequiresAuthenticationOnRoutesExceptionMessage = 'アクセスにはルート上の認証が必要です。' + noSecretForHmac384ExceptionMessage = 'HMAC384ハッシュに対する秘密が提供されていません。' + windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = 'Windowsローカル認証のサポートはWindowsのみです。' + definitionTagNotDefinedExceptionMessage = '定義タグ {0} が定義されていません。' + noComponentInDefinitionExceptionMessage = '{2}定義に{0}タイプの名前{1}コンポーネントが利用できません。' + noSmtpHandlersDefinedExceptionMessage = 'SMTPハンドラが定義されていません。' + sessionMiddlewareAlreadyInitializedExceptionMessage = 'セッションミドルウェアは既に初期化されています。' + reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = "OpenAPI v3.0では再利用可能なコンポーネント機能'pathItems'は使用できません。" + wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 'ヘッダーのワイルドカード * は AutoHeaders スイッチと互換性がありません。' + noDataForFileUploadedExceptionMessage = "リクエストでアップロードされたファイル '{0}' のデータがありません。" + sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = 'SSEはAcceptヘッダー値がtext/event-streamのリクエストでのみ構成できます。' + noSessionAvailableToSaveExceptionMessage = '保存するためのセッションが利用できません。' + pathParameterRequiresRequiredSwitchExceptionMessage = "パラメータの場所が 'Path' の場合、スイッチパラメータ 'Required' は必須です。" + noOpenApiUrlSuppliedExceptionMessage = '{0} 用の OpenAPI URL が提供されていません。' + maximumConcurrentSchedulesInvalidExceptionMessage = '最大同時スケジュール数は 1 以上でなければなりませんが、受け取った値: {0}' + snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = 'SnapinsはWindows PowerShellのみでサポートされています。' + eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = 'イベントビューアーロギングはWindowsでのみサポートされています。' + parametersMutuallyExclusiveExceptionMessage = "パラメータ '{0}' と '{1}' は互いに排他的です。" + pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 'PathItems機能はOpenAPI v3.0.xではサポートされていません。' + openApiParameterRequiresNameExceptionMessage = 'OpenApi パラメータには名前が必要です。' + maximumConcurrentTasksLessThanMinimumExceptionMessage = '最大同時タスク数は最小値 {0} より少なくてはいけませんが、取得した値は: {1}' + noSemaphoreFoundExceptionMessage = "名前 '{0}' のセマフォが見つかりません" + singleValueForIntervalExceptionMessage = 'インターバルを使用する場合、単一の{0}値しか指定できません。' + jwtNotYetValidExceptionMessage = 'JWTはまだ有効ではありません。' + verbAlreadyDefinedForUrlExceptionMessage = '[動詞] {0}: {1}にすでに定義されています' + noSecretNamedMountedExceptionMessage = "名前 '{0}' のシークレットはマウントされていません。" + moduleOrVersionNotFoundExceptionMessage = '{0}でモジュールまたはバージョンが見つかりません: {1}@{2}' + noScriptBlockSuppliedExceptionMessage = 'ScriptBlockが提供されていません。' + noSecretVaultRegisteredExceptionMessage = "名前 '{0}' のシークレットボールトは登録されていません。" + nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = 'RedirectToパラメーターが提供されている場合、エンドポイントには名前が必要です。' + openApiLicenseObjectRequiresNameExceptionMessage = "OpenAPI オブジェクト 'license' には 'name' プロパティが必要です。-LicenseName パラメータを使用してください。" + sourcePathDoesNotExistForStaticRouteExceptionMessage = '[{0})] {1}: 静的ルートに対して提供されたソースパスが存在しません: {2}' + noNameForWebSocketDisconnectExceptionMessage = '切断する WebSocket の名前が指定されていません。' + certificateExpiredExceptionMessage = "証明書 '{0}' の有効期限が切れています: {1}" + secretVaultUnlockExpiryDateInPastExceptionMessage = 'シークレットボールトのアンロック有効期限が過去に設定されています (UTC) :{0}' + invalidExceptionTypeExceptionMessage = '例外が無効な型です。WebExceptionまたはHttpRequestExceptionのいずれかである必要がありますが、次の型を取得しました: {0}' + invalidSecretValueTypeExceptionMessage = 'シークレットの値が無効な型です。期待される型: String、SecureString、HashTable、Byte[]、またはPSCredential。しかし、次を取得しました: {0}' + explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = '明示的なTLSモードはSMTPSおよびTCPSエンドポイントでのみサポートされています。' + discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = "パラメーター'DiscriminatorMapping'は'DiscriminatorProperty'が存在する場合にのみ使用できます。" + scriptErrorExceptionMessage = "スクリプト{1} {2}(行{3})のエラー'{0}'(文字{4})が{6}オブジェクト'{7}'の{5}を実行中に発生しました クラス: {8} 基底クラス: {9}" + cannotSupplyIntervalForQuarterExceptionMessage = '四半期ごとの間隔値を提供できません。' + scheduleEndTimeMustBeInFutureExceptionMessage = '[スケジュール] {0}: EndTime 値は未来に設定する必要があります。' + invalidJwtSignatureSuppliedExceptionMessage = '無効なJWT署名が提供されました。' + noSetScriptBlockForVaultExceptionMessage = "ボールト'{0}'のシークレットを更新/作成するためのスクリプトブロックが提供されていません。" + accessMethodNotExistForMergingExceptionMessage = 'マージするアクセス方法が存在しません: {0}' + defaultAuthNotInListExceptionMessage = "デフォルト認証'{0}'は提供された認証リストにありません。" + parameterHasNoNameExceptionMessage = "パラメーターに名前がありません。このコンポーネントに'Name'パラメーターを使用して名前を付けてください。" + methodPathAlreadyDefinedForUrlExceptionMessage = '[{0}] {1}: {2}用に既に定義されています。' + fileWatcherAlreadyDefinedExceptionMessage = "名前 '{0}' のファイルウォッチャーは既に定義されています。" + noServiceHandlersDefinedExceptionMessage = 'サービスハンドラが定義されていません。' + secretRequiredForCustomSessionStorageExceptionMessage = 'カスタムセッションストレージを使用する場合、シークレットが必要です。' + secretManagementModuleNotInstalledExceptionMessage = 'Microsoft.PowerShell.SecretManagementモジュールがインストールされていません。' + noPathSuppliedForRouteExceptionMessage = 'ルートのパスが提供されていません。' + validationOfAnyOfSchemaNotSupportedExceptionMessage = "'anyof'を含むスキーマの検証はサポートされていません。" + iisAuthSupportIsForWindowsOnlyExceptionMessage = 'IIS認証のサポートはWindowsのみです。' + oauth2InnerSchemeInvalidExceptionMessage = 'OAuth2 InnerSchemeはBasicまたはFormのいずれかでなければなりませんが、取得したのは: {0}' + noRoutePathSuppliedForPageExceptionMessage = '{0} ページのルートパスが提供されていません。' + cacheStorageNotFoundForExistsExceptionMessage = "キャッシュされたアイテム '{1}' が存在するかどうかを確認しようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。" + handlerAlreadyDefinedExceptionMessage = '[{0}] {1}: ハンドラは既に定義されています。' + sessionsNotConfiguredExceptionMessage = 'セッションが構成されていません。' + propertiesTypeObjectAssociationExceptionMessage = 'Object 型のプロパティのみが {0} と関連付けられます。' + sessionsRequiredForSessionPersistentAuthExceptionMessage = 'セッション持続認証を使用するにはセッションが必要です。' + invalidPathWildcardOrDirectoryExceptionMessage = '指定されたパスはワイルドカードまたはディレクトリにすることはできません: {0}' + accessMethodAlreadyDefinedExceptionMessage = 'アクセス方法はすでに定義されています: {0}' + parametersValueOrExternalValueMandatoryExceptionMessage = "パラメータ 'Value' または 'ExternalValue' は必須です。" + maximumConcurrentTasksInvalidExceptionMessage = '最大同時タスク数は >=1 でなければなりませんが、取得した値は: {0}' + cannotCreatePropertyWithoutTypeExceptionMessage = '型が定義されていないため、プロパティを作成できません。' + authMethodNotExistForMergingExceptionMessage = 'マージするための認証方法は存在しません:{0}' + maxValueInvalidExceptionMessage = "{1}の最大値'{0}'は無効です。{2}以下でなければなりません。" + endpointAlreadyDefinedExceptionMessage = "名前 '{0}' のエンドポイントは既に定義されています。" + eventAlreadyRegisteredExceptionMessage = '{0}イベントはすでに登録されています:{1}' + parameterNotSuppliedInRequestExceptionMessage = "リクエストに '{0}' という名前のパラメータが提供されていないか、データがありません。" + cacheStorageNotFoundForSetExceptionMessage = "キャッシュされたアイテム '{1}' を設定しようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。" + methodPathAlreadyDefinedExceptionMessage = '[{0}] {1}: 既に定義されています。' + errorLoggingAlreadyEnabledExceptionMessage = 'エラーロギングは既に有効になっています。' + valueForUsingVariableNotFoundExceptionMessage = "'`$using:{0}'の値が見つかりませんでした。" + rapidPdfDoesNotSupportOpenApi31ExceptionMessage = 'ドキュメントツール RapidPdf は OpenAPI 3.1 をサポートしていません' + oauth2ClientSecretRequiredExceptionMessage = 'PKCEを使用しない場合、OAuth2にはクライアントシークレットが必要です。' + invalidBase64JwtExceptionMessage = 'JWTに無効なBase64エンコード値が見つかりました。' + noSessionToCalculateDataHashExceptionMessage = 'データハッシュを計算するセッションがありません。' + cacheStorageNotFoundForRemoveExceptionMessage = "キャッシュされたアイテム '{1}' を削除しようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。" + csrfMiddlewareNotInitializedExceptionMessage = 'CSRFミドルウェアが初期化されていません。' + infoTitleMandatoryMessage = 'info.title は必須です。' + typeCanOnlyBeAssociatedWithObjectExceptionMessage = 'タイプ{0}はオブジェクトにのみ関連付けることができます。' + userFileDoesNotExistExceptionMessage = 'ユーザーファイルが存在しません:{0}' + routeParameterNeedsValidScriptblockExceptionMessage = 'ルートパラメーターには有効で空でないScriptBlockが必要です。' + nextTriggerCalculationErrorExceptionMessage = '次のトリガー日時の計算中に問題が発生したようです: {0}' + cannotLockValueTypeExceptionMessage = '[ValueTypes]をロックできません。' + failedToCreateOpenSslCertExceptionMessage = 'OpenSSL証明書の作成に失敗しました: {0}' + jwtExpiredExceptionMessage = 'JWTの有効期限が切れています。' + openingGuiMessage = 'GUIを開いています。' + multiTypePropertiesRequireOpenApi31ExceptionMessage = '複数タイプのプロパティはOpenApiバージョン3.1以上が必要です。' + noNameForWebSocketRemoveExceptionMessage = '削除する WebSocket の名前が指定されていません。' + maxSizeInvalidExceptionMessage = 'MaxSizeは0以上でなければなりませんが、受け取った値は: {0}' + iisShutdownMessage = '(IIS シャットダウン)' + cannotUnlockValueTypeExceptionMessage = '[ValueTypes]のロックを解除できません。' + noJwtSignatureForAlgorithmExceptionMessage = '{0}のためのJWT署名が提供されていません。' + maximumConcurrentWebSocketThreadsInvalidExceptionMessage = '最大同時 WebSocket スレッド数は >=1 でなければなりませんが、取得した値は: {0}' + acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = '確認メッセージはSMTPおよびTCPエンドポイントでのみサポートされています。' + failedToConnectToUrlExceptionMessage = 'URLへの接続に失敗しました: {0}' + failedToAcquireMutexOwnershipExceptionMessage = 'ミューテックスの所有権を取得できませんでした。ミューテックス名: {0}' + sessionsRequiredForOAuth2WithPKCEExceptionMessage = 'PKCEを使用するOAuth2にはセッションが必要です。' + failedToConnectToWebSocketExceptionMessage = 'WebSocket への接続に失敗しました: {0}' + unsupportedObjectExceptionMessage = 'サポートされていないオブジェクトです。' + failedToParseAddressExceptionMessage = "'{0}'を有効なIP/ホスト:ポートアドレスとして解析できませんでした。" + mustBeRunningWithAdminPrivilegesExceptionMessage = 'ローカルホスト以外のアドレスでリッスンするには管理者権限で実行する必要があります。' + specificationMessage = '仕様' + cacheStorageNotFoundForClearExceptionMessage = "キャッシュをクリアしようとしたときに、名前 '{0}' のキャッシュストレージが見つかりません。" + restartingServerMessage = 'サーバーを再起動しています...' + cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = "パラメーター'Every'がNoneに設定されている場合、間隔を提供できません。" + unsupportedJwtAlgorithmExceptionMessage = '現在サポートされていないJWTアルゴリズムです: {0}' + websocketsNotConfiguredForSignalMessagesExceptionMessage = 'WebSocketsはシグナルメッセージを送信するように構成されていません。' + invalidLogicTypeInHashtableMiddlewareExceptionMessage = '提供されたHashtableミドルウェアに無効なロジック型があります。ScriptBlockを期待しましたが、次を取得しました: {0}' + maximumConcurrentSchedulesLessThanMinimumExceptionMessage = '最大同時スケジュール数は最小 {0} 未満にすることはできませんが、受け取った値: {1}' + failedToAcquireSemaphoreOwnershipExceptionMessage = 'セマフォの所有権を取得できませんでした。セマフォ名: {0}' + propertiesParameterWithoutNameExceptionMessage = 'プロパティに名前がない場合、プロパティパラメータは使用できません。' + customSessionStorageMethodNotImplementedExceptionMessage = "カスタムセッションストレージは必要なメソッド'{0}()'を実装していません。" + authenticationMethodDoesNotExistExceptionMessage = '認証方法が存在しません: {0}' + webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = 'Webhooks機能はOpenAPI v3.0.xではサポートされていません。' + invalidContentTypeForSchemaExceptionMessage = "スキーマの 'content-type' が無効です: {0}" + noUnlockScriptBlockForVaultExceptionMessage = "ボールト'{0}'のロック解除に必要なスクリプトブロックが提供されていません。" + definitionTagMessage = '定義 {0}:' + failedToOpenRunspacePoolExceptionMessage = 'RunspacePoolのオープンに失敗しました: {0}' + verbNoLogicPassedExceptionMessage = '[動詞] {0}: ロジックが渡されていません' + noMutexFoundExceptionMessage = "名前 '{0}' のミューテックスが見つかりません" + documentationMessage = 'ドキュメント' + timerAlreadyDefinedExceptionMessage = '[タイマー] {0}: タイマーはすでに定義されています。' + invalidPortExceptionMessage = 'ポートは負であってはなりません: {0}' + viewsFolderNameAlreadyExistsExceptionMessage = 'ビューのフォルダ名は既に存在します: {0}' + noNameForWebSocketResetExceptionMessage = 'リセットする WebSocket の名前が指定されていません。' + mergeDefaultAuthNotInListExceptionMessage = "MergeDefault認証'{0}'は提供された認証リストにありません。" + descriptionRequiredExceptionMessage = '説明が必要です。' + pageNameShouldBeAlphaNumericExceptionMessage = 'ページ名は有効な英数字である必要があります: {0}' + defaultValueNotBooleanOrEnumExceptionMessage = 'デフォルト値は boolean ではなく、enum に含まれていません。' + openApiComponentSchemaDoesNotExistExceptionMessage = 'OpenApi コンポーネントスキーマ {0} は存在しません。' + timerParameterMustBeGreaterThanZeroExceptionMessage = '[タイマー] {0}: {1} は 0 より大きくなければなりません。' + taskTimedOutExceptionMessage = 'タスクが{0}ミリ秒後にタイムアウトしました。' + scheduleStartTimeAfterEndTimeExceptionMessage = "[スケジュール] {0}: 'StartTime' が 'EndTime' の後であることはできません" + infoVersionMandatoryMessage = 'info.version は必須です。' + cannotUnlockNullObjectExceptionMessage = 'nullオブジェクトのロックを解除できません。' + nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 'カスタム認証スキームには空でないScriptBlockが必要です。' + validationOfOneOfSchemaNotSupportedExceptionMessage = "'oneof'を含むスキーマの検証はサポートされていません。" + routeParameterCannotBeNullExceptionMessage = "パラメータ 'Route' は null ではいけません。" + cacheStorageAlreadyExistsExceptionMessage = "名前 '{0}' のキャッシュストレージは既に存在します。" + loggingMethodRequiresValidScriptBlockExceptionMessage = "'{0}' ログ記録方法のために提供された出力方法は、有効なScriptBlockが必要です。" + scopedVariableAlreadyDefinedExceptionMessage = 'スコープ付き変数が既に定義されています: {0}' + oauth2RequiresAuthorizeUrlExceptionMessage = 'OAuth2には認可URLの提供が必要です。' + pathNotExistExceptionMessage = 'パスが存在しません: {0}' + noDomainServerNameForWindowsAdAuthExceptionMessage = 'Windows AD認証用のドメインサーバー名が提供されていません。' + suppliedDateAfterScheduleEndTimeExceptionMessage = '提供された日付はスケジュールの終了時間 {0} の後です' + wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 'メソッドのワイルドカード * は AutoMethods スイッチと互換性がありません。' + cannotSupplyIntervalForYearExceptionMessage = '毎年の間隔値を提供できません。' + missingComponentsMessage = '欠落しているコンポーネント' + invalidStrictTransportSecurityDurationExceptionMessage = '無効な Strict-Transport-Security 期間が指定されました: {0}。0 より大きい必要があります。' + noSecretForHmac512ExceptionMessage = 'HMAC512ハッシュに対する秘密が提供されていません。' + daysInMonthExceededExceptionMessage = '{0}は{1}日しかありませんが、{2}が指定されました。' + nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 'カスタムロギング出力メソッドには空でないScriptBlockが必要です。' + encodingAttributeOnlyAppliesToMultipartExceptionMessage = 'エンコーディング属性は、multipart および application/x-www-form-urlencoded リクエストボディにのみ適用されます。' + suppliedDateBeforeScheduleStartTimeExceptionMessage = '提供された日付はスケジュールの開始時間 {0} より前です' + unlockSecretRequiredExceptionMessage = "Microsoft.PowerShell.SecretStoreを使用する場合、'UnlockSecret'プロパティが必要です。" + noLogicPassedForMethodRouteExceptionMessage = '[{0}] {1}: ロジックが渡されませんでした。' + bodyParserAlreadyDefinedForContentTypeExceptionMessage = '{0} コンテンツタイプ用のボディパーサーは既に定義されています。' + invalidJwtSuppliedExceptionMessage = '無効なJWTが提供されました。' + sessionsRequiredForFlashMessagesExceptionMessage = 'フラッシュメッセージを使用するにはセッションが必要です。' + outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = 'リクエストロギングのために提供された出力メソッドには有効なScriptBlockが必要です。' + semaphoreAlreadyExistsExceptionMessage = '次の名前のセマフォはすでに存在します: {0}' + invalidJwtHeaderAlgorithmSuppliedExceptionMessage = '無効なJWTヘッダーアルゴリズムが提供されました。' + oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = "OAuth2プロバイダーはInnerSchemeを使用するために必要な'password' grant_typeをサポートしていません。" + invalidAliasFoundExceptionMessage = '無効な{0}エイリアスが見つかりました: {1}' + scheduleDoesNotExistExceptionMessage = "スケジュール '{0}' は存在しません。" + accessMethodNotExistExceptionMessage = 'アクセス方法が存在しません: {0}' + oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = "OAuth2プロバイダーは'code' response_typeをサポートしていません。" + untestedPowerShellVersionWarningMessage = '[警告] Pode {0} はリリース時に利用可能でなかったため、PowerShell {1} でテストされていません。' + secretVaultAlreadyRegisteredAutoImportExceptionMessage = "シークレットボールト'{0}'は既に登録されています(シークレットボールトの自動インポート中)。" + schemeRequiresValidScriptBlockExceptionMessage = "'{0}'認証バリデーターのために提供されたスキームには有効なScriptBlockが必要です。" + serverLoopingMessage = 'サーバーループ間隔 {0}秒' + certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 'Certificate Thumbprints/NameはWindowsでのみサポートされています。' + sseConnectionNameRequiredExceptionMessage = "-Nameまたは`$WebEvent.Sse.NameからSSE接続名が必要です。" + invalidMiddlewareTypeExceptionMessage = '提供されたMiddlewaresの1つが無効な型です。ScriptBlockまたはHashtableのいずれかを期待しましたが、次を取得しました: {0}' + noSecretForJwtSignatureExceptionMessage = 'JWT署名に対する秘密が提供されていません。' + modulePathDoesNotExistExceptionMessage = 'モジュールパスが存在しません: {0}' + taskAlreadyDefinedExceptionMessage = '[タスク] {0}: タスクは既に定義されています。' + verbAlreadyDefinedExceptionMessage = '[動詞] {0}: すでに定義されています' + clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 'クライアント証明書はHTTPSエンドポイントでのみサポートされています。' + endpointNameNotExistExceptionMessage = "名前'{0}'のエンドポイントが存在しません。" + middlewareNoLogicSuppliedExceptionMessage = '[ミドルウェア]: ScriptBlockにロジックが提供されていません。' + scriptBlockRequiredForMergingUsersExceptionMessage = 'ValidがAllの場合、複数の認証済みユーザーを1つのオブジェクトにマージするためのScriptBlockが必要です。' + secretVaultAlreadyRegisteredExceptionMessage = "名前 '{0}' のシークレットボールトは既に登録されています{1}。" + deprecatedTitleVersionDescriptionWarningMessage = "警告: 'Enable-PodeOpenApi' のタイトル、バージョン、および説明は非推奨です。代わりに 'Add-PodeOAInfo' を使用してください。" + undefinedOpenApiReferencesMessage = '未定義のOpenAPI参照:' + doneMessage = '完了' + swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = 'このバージョンの Swagger-Editor は OpenAPI 3.1 をサポートしていません' + durationMustBeZeroOrGreaterExceptionMessage = '期間は 0 以上でなければなりませんが、取得した値は: {0}s' + viewsPathDoesNotExistExceptionMessage = 'ビューのパスが存在しません: {0}' + discriminatorIncompatibleWithAllOfExceptionMessage = "パラメーター'Discriminator'は'allOf'と互換性がありません。" + noNameForWebSocketSendMessageExceptionMessage = 'メッセージを送信する WebSocket の名前が指定されていません。' + hashtableMiddlewareNoLogicExceptionMessage = '提供されたHashtableミドルウェアにロジックが定義されていません。' + openApiInfoMessage = 'OpenAPI情報:' + invalidSchemeForAuthValidatorExceptionMessage = "'{1}'認証バリデーターのために提供された'{0}'スキームには有効なScriptBlockが必要です。" + sseFailedToBroadcastExceptionMessage = '{0}のSSEブロードキャストレベルが定義されているため、SSEのブロードキャストに失敗しました: {1}' + adModuleWindowsOnlyExceptionMessage = 'Active DirectoryモジュールはWindowsでのみ利用可能です。' + requestLoggingAlreadyEnabledExceptionMessage = 'リクエストロギングは既に有効になっています。' + invalidAccessControlMaxAgeDurationExceptionMessage = '無効な Access-Control-Max-Age 期間が提供されました:{0}。0 より大きくする必要があります。' +} + diff --git a/src/Locales/ko/Pode.psd1 b/src/Locales/ko/Pode.psd1 index 5e0cd3176..09f41b455 100644 --- a/src/Locales/ko/Pode.psd1 +++ b/src/Locales/ko/Pode.psd1 @@ -1,284 +1,285 @@ -ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyExceptionMessage = Active Directory 모듈은 Windows에서만 사용할 수 있습니다. -adModuleNotInstalledExceptionMessage = Active Directory 모듈이 설치되지 않았습니다. -secretManagementModuleNotInstalledExceptionMessage = Microsoft.PowerShell.SecretManagement 모듈이 설치되지 않았습니다. -secretVaultAlreadyRegisteredAutoImportExceptionMessage = 이름이 '{0}'인 비밀 금고가 이미 자동으로 가져오는 동안 등록되었습니다. -failedToOpenRunspacePoolExceptionMessage = RunspacePool을 여는 데 실패했습니다: {0} -cronExpressionInvalidExceptionMessage = Cron 표현식은 5개의 부분으로만 구성되어야 합니다: {0} -invalidAliasFoundExceptionMessage = 잘못된 {0} 별칭이 발견되었습니다: {1} -invalidAtomCharacterExceptionMessage = 잘못된 원자 문자: {0} -minValueGreaterThanMaxExceptionMessage = {0}의 최소 값은 최대 값보다 클 수 없습니다. -minValueInvalidExceptionMessage = {1}의 최소 값 '{0}'이(가) 유효하지 않습니다. {2} 이상이어야 합니다. -maxValueInvalidExceptionMessage = {1}의 최대 값 '{0}'이(가) 유효하지 않습니다. {2} 이하여야 합니다. -valueOutOfRangeExceptionMessage = {1}의 값 '{0}'이(가) 유효하지 않습니다. {2}와 {3} 사이여야 합니다. -daysInMonthExceededExceptionMessage = {0}에는 {1}일밖에 없지만 {2}일이 제공되었습니다. -nextTriggerCalculationErrorExceptionMessage = 다음 트리거 날짜 및 시간을 계산하는 중에 문제가 발생한 것 같습니다: {0} -incompatiblePodeDllExceptionMessage = 기존의 호환되지 않는 Pode.DLL 버전 {0}이 로드되었습니다. 버전 {1}이 필요합니다. 새로운 Powershell/pwsh 세션을 열고 다시 시도하세요. -endpointNotExistExceptionMessage = 프로토콜 '{0}' 및 주소 '{1}' 또는 로컬 주소 '{2}'가 있는 엔드포인트가 존재하지 않습니다. -endpointNameNotExistExceptionMessage = 이름이 '{0}'인 엔드포인트가 존재하지 않습니다. -failedToConnectToUrlExceptionMessage = URL에 연결하지 못했습니다: {0} -failedToParseAddressExceptionMessage = '{0}'을(를) 유효한 IP/호스트:포트 주소로 구문 분석하지 못했습니다. -invalidIpAddressExceptionMessage = 제공된 IP 주소가 유효하지 않습니다: {0} -invalidPortExceptionMessage = 포트는 음수일 수 없습니다: {0} -pathNotExistExceptionMessage = 경로가 존재하지 않습니다: {0} -noSecretForHmac256ExceptionMessage = HMAC256 해시를 위한 비밀이 제공되지 않았습니다. -noSecretForHmac384ExceptionMessage = HMAC384 해시를 위한 비밀이 제공되지 않았습니다. -noSecretForHmac512ExceptionMessage = HMAC512 해시를 위한 비밀이 제공되지 않았습니다. -noSecretForJwtSignatureExceptionMessage = JWT 서명을 위한 비밀이 제공되지 않았습니다. -noSecretExpectedForNoSignatureExceptionMessage = 서명이 없는 경우 비밀이 제공되지 않아야 합니다. -unsupportedJwtAlgorithmExceptionMessage = JWT 알고리즘은 현재 지원되지 않습니다: {0} -invalidBase64JwtExceptionMessage = JWT에서 잘못된 Base64 인코딩 값이 발견되었습니다. -invalidJsonJwtExceptionMessage = JWT에서 잘못된 JSON 값이 발견되었습니다. -unsupportedFunctionInServerlessContextExceptionMessage = {0} 함수는 서버리스 컨텍스트에서 지원되지 않습니다. -invalidPathWildcardOrDirectoryExceptionMessage = 제공된 경로는 와일드카드 또는 디렉터리가 될 수 없습니다: {0} -invalidExceptionTypeExceptionMessage = 예외가 잘못된 유형입니다. WebException 또는 HttpRequestException이어야 하지만, 얻은 것은: {0} -pathToLoadNotFoundExceptionMessage = 로드할 경로 {0}을(를) 찾을 수 없습니다: {1} -singleValueForIntervalExceptionMessage = 간격을 사용할 때는 단일 {0} 값을 제공할 수 있습니다. -scriptErrorExceptionMessage = 스크립트 {1} {2} (라인 {3}) 문자 {4}에서 {5}을(를) 실행하는 중에 스크립트 {0} 오류가 발생했습니다. 개체 '{7}' 클래스: {8} 기본 클래스: {9} -noScriptBlockSuppliedExceptionMessage = ScriptBlock이 제공되지 않았습니다. -iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN이 누락되었습니다. -propertiesParameterWithoutNameExceptionMessage = 속성에 이름이 없으면 Properties 매개변수를 사용할 수 없습니다. -multiTypePropertiesRequireOpenApi31ExceptionMessage = 다중 유형 속성은 OpenApi 버전 3.1 이상이 필요합니다. -openApiVersionPropertyMandatoryExceptionMessage = OpenApi 버전 속성은 필수입니다. -webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = Webhooks 기능은 OpenAPI v3.0.x에서 지원되지 않습니다. -authenticationMethodDoesNotExistExceptionMessage = 인증 방법이 존재하지 않습니다: {0} -unsupportedObjectExceptionMessage = 지원되지 않는 개체 -validationOfAnyOfSchemaNotSupportedExceptionMessage = 'anyof'을 포함하는 스키마의 유효성 검사는 지원되지 않습니다. -validationOfOneOfSchemaNotSupportedExceptionMessage = 'oneof'을 포함하는 스키마의 유효성 검사는 지원되지 않습니다. -cannotCreatePropertyWithoutTypeExceptionMessage = 유형이 정의되지 않았기 때문에 속성을 생성할 수 없습니다. -headerMustHaveNameInEncodingContextExceptionMessage = 인코딩 컨텍스트에서 사용될 때 헤더는 이름이 있어야 합니다. -descriptionRequiredExceptionMessage = 설명이 필요합니다. -openApiDocumentNotCompliantExceptionMessage = OpenAPI 문서는 준수하지 않습니다. -noComponentInDefinitionExceptionMessage = {2} 정의에서 {0} 유형의 {1} 이름의 구성 요소가 없습니다. -methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: 이미 정의되었습니다. -methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: {2}에 대해 이미 정의되었습니다. -invalidMiddlewareTypeExceptionMessage = 제공된 미들웨어 중 하나가 잘못된 유형입니다. 예상된 유형은 ScriptBlock 또는 Hashtable이지만, 얻은 것은: {0} -hashtableMiddlewareNoLogicExceptionMessage = 제공된 Hashtable 미들웨어에는 정의된 논리가 없습니다. -invalidLogicTypeInHashtableMiddlewareExceptionMessage = 제공된 Hashtable 미들웨어에 잘못된 논리 유형이 있습니다. 예상된 유형은 ScriptBlock이지만, 얻은 것은: {0} -scopedVariableAlreadyDefinedExceptionMessage = 범위 지정 변수가 이미 정의되었습니다: {0} -valueForUsingVariableNotFoundExceptionMessage = '`$using:{0}'에 대한 값을 찾을 수 없습니다. -unlockSecretRequiredExceptionMessage = Microsoft.PowerShell.SecretStore를 사용할 때 'UnlockSecret' 속성이 필요합니다. -unlockSecretButNoScriptBlockExceptionMessage = 사용자 정의 비밀 금고 유형에 대해 제공된 Unlock 비밀이지만, Unlock ScriptBlock이 제공되지 않았습니다. -noUnlockScriptBlockForVaultExceptionMessage = 금고 '{0}'을(를) 해제하는 Unlock ScriptBlock이 제공되지 않았습니다. -noSetScriptBlockForVaultExceptionMessage = 금고 '{0}'에서 비밀을 업데이트/생성하기 위한 Set ScriptBlock이 제공되지 않았습니다. -noRemoveScriptBlockForVaultExceptionMessage = 금고 '{0}'에서 비밀을 제거하기 위한 Remove ScriptBlock이 제공되지 않았습니다. -invalidSecretValueTypeExceptionMessage = 비밀 값이 잘못된 유형입니다. 예상되는 유형: String, SecureString, HashTable, Byte[] 또는 PSCredential. 그러나 얻은 것은: {0} -limitValueCannotBeZeroOrLessExceptionMessage = {0}에 대한 제한 값은 0 이하일 수 없습니다. -secondsValueCannotBeZeroOrLessExceptionMessage = {0}에 대한 초 값은 0 이하일 수 없습니다. -failedToCreateOpenSslCertExceptionMessage = openssl 인증서 생성 실패: {0} -certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 인증서 지문/이름은 Windows에서만 지원됩니다. -noCertificateFoundExceptionMessage = '{2}'에 대한 {0}\{1}에서 인증서를 찾을 수 없습니다. -runspacePoolFailedToLoadExceptionMessage = {0} RunspacePool 로드 실패. -noServiceHandlersDefinedExceptionMessage = 정의된 서비스 핸들러가 없습니다. -noSessionToSetOnResponseExceptionMessage = 응답에 설정할 세션이 없습니다. -noSessionToCalculateDataHashExceptionMessage = 데이터 해시를 계산할 세션이 없습니다. -moduleOrVersionNotFoundExceptionMessage = {0}에서 모듈 또는 버전을 찾을 수 없습니다: {1}@{2} -noSmtpHandlersDefinedExceptionMessage = 정의된 SMTP 핸들러가 없습니다. -taskTimedOutExceptionMessage = 작업이 {0}ms 후에 시간 초과되었습니다. -verbAlreadyDefinedExceptionMessage = [동사] {0}: 이미 정의되었습니다. -verbAlreadyDefinedForUrlExceptionMessage = [동사] {0}: {1}에 대해 이미 정의되었습니다. -pathOrScriptBlockRequiredExceptionMessage = 사용자 지정 액세스 값을 소싱하기 위해 경로 또는 ScriptBlock이 필요합니다. -accessMethodAlreadyDefinedExceptionMessage = 액세스 방법이 이미 정의되었습니다: {0} -accessMethodNotExistForMergingExceptionMessage = 병합을 위한 액세스 방법이 존재하지 않습니다: {0} -routeAlreadyContainsCustomAccessExceptionMessage = 경로 '[{0}] {1}'에 '{2}' 이름의 사용자 지정 액세스가 이미 포함되어 있습니다. -accessMethodNotExistExceptionMessage = 액세스 방법이 존재하지 않습니다: {0} -pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = PathItems 기능은 OpenAPI v3.0.x에서 지원되지 않습니다. -nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 사용자 정의 인증 스킴에는 비어 있지 않은 ScriptBlock이 필요합니다. -oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme은 Basic 또는 Form 인증 중 하나여야 합니다, 그러나 받은 값: {0} -sessionsRequiredForOAuth2WithPKCEExceptionMessage = PKCE를 사용하는 OAuth2에는 세션이 필요합니다. -oauth2ClientSecretRequiredExceptionMessage = PKCE를 사용하지 않을 때 OAuth2에는 클라이언트 비밀이 필요합니다. -authMethodAlreadyDefinedExceptionMessage = 인증 방법이 이미 정의되었습니다: {0} -invalidSchemeForAuthValidatorExceptionMessage = '{1}' 인증 검증기에 제공된 '{0}' 스킴에는 유효한 ScriptBlock이 필요합니다. -sessionsRequiredForSessionPersistentAuthExceptionMessage = 세션 지속 인증을 사용하려면 세션이 필요합니다. -oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2에는 권한 부여 URL이 필요합니다. -authMethodNotExistForMergingExceptionMessage = 병합을 위한 인증 방법이 존재하지 않습니다: {0} -mergeDefaultAuthNotInListExceptionMessage = 병합 기본 인증 '{0}'이(가) 제공된 인증 목록에 없습니다. -defaultAuthNotInListExceptionMessage = 기본 인증 '{0}'이(가) 제공된 인증 목록에 없습니다. -scriptBlockRequiredForMergingUsersExceptionMessage = Valid가 All일 때 여러 인증된 사용자를 하나의 객체로 병합하려면 ScriptBlock이 필요합니다. -noDomainServerNameForWindowsAdAuthExceptionMessage = Windows AD 인증을 위한 도메인 서버 이름이 제공되지 않았습니다. -sessionsNotConfiguredExceptionMessage = 세션이 구성되지 않았습니다. -windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Windows 로컬 인증 지원은 Windows 전용입니다. -iisAuthSupportIsForWindowsOnlyExceptionMessage = IIS 인증 지원은 Windows 전용입니다. -noAlgorithmInJwtHeaderExceptionMessage = JWT 헤더에 제공된 알고리즘이 없습니다. -invalidJwtSuppliedExceptionMessage = 제공된 JWT가 유효하지 않습니다. -invalidJwtHeaderAlgorithmSuppliedExceptionMessage = 제공된 JWT 헤더 알고리즘이 유효하지 않습니다. -noJwtSignatureForAlgorithmExceptionMessage = {0}에 대한 JWT 서명이 제공되지 않았습니다. -expectedNoJwtSignatureSuppliedExceptionMessage = JWT 서명이 제공되지 않을 것으로 예상되었습니다. -invalidJwtSignatureSuppliedExceptionMessage = 제공된 JWT 서명이 유효하지 않습니다. -jwtExpiredExceptionMessage = JWT가 만료되었습니다. -jwtNotYetValidExceptionMessage = JWT가 아직 유효하지 않습니다. -snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Snapins는 Windows PowerShell에서만 지원됩니다. -userFileDoesNotExistExceptionMessage = 사용자 파일이 존재하지 않습니다: {0} -schemeRequiresValidScriptBlockExceptionMessage = '{0}' 인증 검증기에 제공된 스킴에는 유효한 ScriptBlock이 필요합니다. -oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = OAuth2 공급자는 'code' 응답 유형을 지원하지 않습니다. -oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = OAuth2 공급자는 InnerScheme을 사용하는 데 필요한 'password' 부여 유형을 지원하지 않습니다. -eventAlreadyRegisteredExceptionMessage = {0} 이벤트가 이미 등록되었습니다: {1} -noEventRegisteredExceptionMessage = 등록된 {0} 이벤트가 없습니다: {1} -sessionsRequiredForFlashMessagesExceptionMessage = 플래시 메시지를 사용하려면 세션이 필요합니다. -eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = 이벤트 뷰어 로깅은 Windows에서만 지원됩니다. -nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 사용자 정의 로깅 출력 방법에는 비어 있지 않은 ScriptBlock이 필요합니다. -requestLoggingAlreadyEnabledExceptionMessage = 요청 로깅이 이미 활성화되었습니다. -outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = 요청 로깅에 제공된 출력 방법에는 유효한 ScriptBlock이 필요합니다. -errorLoggingAlreadyEnabledExceptionMessage = 오류 로깅이 이미 활성화되었습니다. -nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 로깅 방법에는 비어 있지 않은 ScriptBlock이 필요합니다. -csrfMiddlewareNotInitializedExceptionMessage = CSRF 미들웨어가 초기화되지 않았습니다. -sessionsRequiredForCsrfExceptionMessage = 쿠키를 사용하지 않으려면 CSRF 사용을 위해 세션이 필요합니다. -middlewareNoLogicSuppliedExceptionMessage = [미들웨어]: ScriptBlock에 로직이 제공되지 않았습니다. -parameterHasNoNameExceptionMessage = 매개변수에 이름이 없습니다. 'Name' 매개변수를 사용하여 이 구성 요소에 이름을 지정하십시오. -reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = OpenAPI v3.0에서는 재사용 가능한 구성 요소 기능 'pathItems'를 사용할 수 없습니다. -noPropertiesMutuallyExclusiveExceptionMessage = 매개변수 'NoProperties'는 'Properties', 'MinProperties' 및 'MaxProperties'와 상호 배타적입니다. -discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = 매개변수 'DiscriminatorMapping'은 'DiscriminatorProperty'가 있을 때만 사용할 수 있습니다. -discriminatorIncompatibleWithAllOfExceptionMessage = 매개변수 'Discriminator'는 'allOf'와 호환되지 않습니다. -typeCanOnlyBeAssociatedWithObjectExceptionMessage = 유형 {0}는 객체와만 연관될 수 있습니다. -showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui는 현재 Windows PowerShell 및 Windows의 PowerShell 7+에서만 사용할 수 있습니다. -nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = RedirectTo 매개변수가 제공된 경우 엔드포인트에 이름이 필요합니다. -clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 클라이언트 인증서는 HTTPS 엔드포인트에서만 지원됩니다. -explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 명시적 TLS 모드는 SMTPS 및 TCPS 엔드포인트에서만 지원됩니다. -acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 확인 메시지는 SMTP 및 TCP 엔드포인트에서만 지원됩니다. -crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = CRLF 메시지 끝 검사는 TCP 엔드포인트에서만 지원됩니다. -mustBeRunningWithAdminPrivilegesExceptionMessage = 관리자 권한으로 실행되어야 비로소 로컬호스트 주소가 아닌 주소를 청취할 수 있습니다. -certificateSuppliedForNonHttpsWssEndpointExceptionMessage = HTTPS/WSS가 아닌 엔드포인트에 제공된 인증서입니다. -websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSockets가 신호 메시지를 보내도록 구성되지 않았습니다. -noPathSuppliedForRouteExceptionMessage = 경로에 대해 제공된 경로가 없습니다. -accessRequiresAuthenticationOnRoutesExceptionMessage = 경로에 대한 접근은 인증이 필요합니다. -accessMethodDoesNotExistExceptionMessage = 접근 방법이 존재하지 않습니다: {0}. -routeParameterNeedsValidScriptblockExceptionMessage = 경로 매개변수에는 유효하고 비어 있지 않은 ScriptBlock이 필요합니다. -noCommandsSuppliedToConvertToRoutesExceptionMessage = 경로로 변환할 명령이 제공되지 않았습니다. -nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 페이지 경로를 생성하려면 비어 있지 않은 ScriptBlock이 필요합니다. -sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE는 Accept 헤더 값이 text/event-stream인 요청에서만 구성할 수 있습니다. -sseConnectionNameRequiredExceptionMessage = -Name 또는 `$WebEvent.Sse.Name에서 SSE 연결 이름이 필요합니다. -sseFailedToBroadcastExceptionMessage = {0}에 대해 정의된 SSE 브로드캐스트 수준으로 인해 SSE 브로드캐스트에 실패했습니다: {1} -podeNotInitializedExceptionMessage = Pode가 초기화되지 않았습니다. -invalidTaskTypeExceptionMessage = 작업 유형이 유효하지 않습니다. 예상된 유형: [System.Threading.Tasks.Task] 또는 [hashtable] -cannotLockValueTypeExceptionMessage = [ValueTypes]를 잠글 수 없습니다. -cannotLockNullObjectExceptionMessage = null 개체를 잠글 수 없습니다. -failedToAcquireLockExceptionMessage = 개체에 대한 잠금을 획득하지 못했습니다. -cannotUnlockValueTypeExceptionMessage = [ValueTypes]를 잠금 해제할 수 없습니다. -cannotUnlockNullObjectExceptionMessage = null 개체를 잠금 해제할 수 없습니다. -sessionMiddlewareAlreadyInitializedExceptionMessage = 세션 미들웨어가 이미 초기화되었습니다. -customSessionStorageMethodNotImplementedExceptionMessage = 사용자 정의 세션 저장소가 필요한 메서드 '{0}()'를 구현하지 않았습니다. -secretRequiredForCustomSessionStorageExceptionMessage = 사용자 정의 세션 저장소를 사용할 때는 비밀이 필요합니다. -noSessionAvailableToSaveExceptionMessage = 저장할 수 있는 세션이 없습니다. -cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = 매개변수 'Every'가 None으로 설정된 경우 간격을 제공할 수 없습니다. -cannotSupplyIntervalForQuarterExceptionMessage = 분기별 간격 값을 제공할 수 없습니다. -cannotSupplyIntervalForYearExceptionMessage = 매년 간격 값을 제공할 수 없습니다. -secretVaultAlreadyRegisteredExceptionMessage = 이름이 '{0}'인 시크릿 금고가 이미 등록되었습니다{1}. -secretVaultUnlockExpiryDateInPastExceptionMessage = 시크릿 금고의 잠금 해제 만료 날짜가 과거입니다 (UTC): {0} -secretAlreadyMountedExceptionMessage = 이름이 '{0}'인 시크릿이 이미 마운트되었습니다. -credentialsPassedWildcardForHeadersLiteralExceptionMessage = 자격 증명이 전달되면, 헤더에 대한 * 와일드카드는 와일드카드가 아닌 리터럴 문자열로 취급됩니다. -wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 헤더에 대한 * 와일드카드는 AutoHeaders 스위치와 호환되지 않습니다. -wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 메서드에 대한 * 와일드카드는 AutoMethods 스위치와 호환되지 않습니다. -invalidAccessControlMaxAgeDurationExceptionMessage = 잘못된 Access-Control-Max-Age 기간이 제공되었습니다: {0}. 0보다 커야 합니다. -noNameForWebSocketDisconnectExceptionMessage = 연결을 끊을 WebSocket의 이름이 제공되지 않았습니다. -noNameForWebSocketRemoveExceptionMessage = 제거할 WebSocket의 이름이 제공되지 않았습니다. -noNameForWebSocketSendMessageExceptionMessage = 메시지를 보낼 WebSocket의 이름이 제공되지 않았습니다. -noSecretNamedMountedExceptionMessage = 이름이 '{0}'인 시크릿이 마운트되지 않았습니다. -noNameForWebSocketResetExceptionMessage = 재설정할 WebSocket의 이름이 제공되지 않았습니다. -schemaValidationRequiresPowerShell610ExceptionMessage = 스키마 유효성 검사는 PowerShell 버전 6.1.0 이상이 필요합니다. -routeParameterCannotBeNullExceptionMessage = 'Route' 매개변수는 null일 수 없습니다. -encodingAttributeOnlyAppliesToMultipartExceptionMessage = 인코딩 속성은 multipart 및 application/x-www-form-urlencoded 요청 본문에만 적용됩니다. -testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema'는 'Enable-PodeOpenApi -EnableSchemaValidation'을 사용하여 활성화해야 합니다. -openApiComponentSchemaDoesNotExistExceptionMessage = OpenApi 구성 요소 스키마 {0}이(가) 존재하지 않습니다. -openApiParameterRequiresNameExceptionMessage = OpenApi 매개변수에는 이름이 필요합니다. -openApiLicenseObjectRequiresNameExceptionMessage = OpenAPI 객체 'license'는 'name' 속성이 필요합니다. -LicenseName 매개변수를 사용하십시오. -parametersValueOrExternalValueMandatoryExceptionMessage = 매개변수 'Value' 또는 'ExternalValue'는 필수입니다. -parametersMutuallyExclusiveExceptionMessage = 매개변수 '{0}'와(과) '{1}'는 상호 배타적입니다. -maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 최대 동시 WebSocket 스레드는 >=1이어야 하지만 받은 값: {0} -maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 최대 동시 WebSocket 스레드는 최소값 {0}보다 작을 수 없지만 받은 값: {1} -alreadyConnectedToWebSocketExceptionMessage = 이름이 '{0}'인 WebSocket에 이미 연결되어 있습니다. -failedToConnectToWebSocketExceptionMessage = WebSocket에 연결하지 못했습니다: {0} -verbNoLogicPassedExceptionMessage = [동사] {0}: 전달된 로직 없음 -scriptPathDoesNotExistExceptionMessage = 스크립트 경로가 존재하지 않습니다: {0} -failedToImportModuleExceptionMessage = 모듈을 가져오지 못했습니다: {0} -modulePathDoesNotExistExceptionMessage = 모듈 경로가 존재하지 않습니다: {0} -defaultValueNotBooleanOrEnumExceptionMessage = 기본값이 boolean이 아니며 enum에 속하지 않습니다. -propertiesTypeObjectAssociationExceptionMessage = Object 유형의 속성만 {0}와(과) 연결될 수 있습니다. -invalidContentTypeForSchemaExceptionMessage = 스키마에 대해 잘못된 'content-type'이 발견되었습니다: {0} -openApiRequestStyleInvalidForParameterExceptionMessage = OpenApi 요청 스타일은 {1} 매개변수에 대해 {0}일 수 없습니다. -pathParameterRequiresRequiredSwitchExceptionMessage = 매개변수 위치가 'Path'인 경우 'Required' 스위치 매개변수가 필수입니다. -operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0}은(는) 고유해야 하며 배열에 적용될 수 없습니다. -operationIdMustBeUniqueExceptionMessage = OperationID: {0}은(는) 고유해야 합니다. -noOpenApiUrlSuppliedExceptionMessage = {0}에 대한 OpenAPI URL이 제공되지 않았습니다. -noTitleSuppliedForPageExceptionMessage = {0} 페이지에 대한 제목이 제공되지 않았습니다. -noRoutePathSuppliedForPageExceptionMessage = {0} 페이지에 대한 경로가 제공되지 않았습니다. -swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = 이 버전의 Swagger-Editor는 OpenAPI 3.1을 지원하지 않습니다. -rapidPdfDoesNotSupportOpenApi31ExceptionMessage = 문서 도구 RapidPdf는 OpenAPI 3.1을 지원하지 않습니다. -definitionTagNotDefinedExceptionMessage = 정의 태그 {0}이(가) 정의되지 않았습니다. -scopedVariableNotFoundExceptionMessage = 범위 변수 {0}을(를) 찾을 수 없습니다. -noSecretVaultRegisteredExceptionMessage = 이름이 '{0}'인 비밀 금고가 등록되지 않았습니다. -invalidStrictTransportSecurityDurationExceptionMessage = 잘못된 Strict-Transport-Security 기간이 제공되었습니다: {0}. 0보다 커야 합니다. -durationMustBeZeroOrGreaterExceptionMessage = 기간은 0 이상이어야 하지만 받은 값: {0}s -taskAlreadyDefinedExceptionMessage = [작업] {0}: 작업이 이미 정의되었습니다. -maximumConcurrentTasksInvalidExceptionMessage = 최대 동시 작업 수는 >=1이어야 하지만 받은 값: {0} -maximumConcurrentTasksLessThanMinimumExceptionMessage = 최대 동시 작업 수는 최소값 {0}보다 작을 수 없지만 받은 값: {1} -taskDoesNotExistExceptionMessage = 작업 '{0}'이(가) 존재하지 않습니다. -cacheStorageNotFoundForRetrieveExceptionMessage = 캐시된 항목 '{1}'을(를) 검색하려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다. -cacheStorageNotFoundForSetExceptionMessage = 캐시된 항목 '{1}'을(를) 설정하려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다. -cacheStorageNotFoundForExistsExceptionMessage = 캐시된 항목 '{1}'이(가) 존재하는지 확인하려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다. -cacheStorageNotFoundForRemoveExceptionMessage = 캐시된 항목 '{1}'을(를) 제거하려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다. -cacheStorageNotFoundForClearExceptionMessage = 캐시를 지우려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다. -cacheStorageAlreadyExistsExceptionMessage = 이름이 '{0}'인 캐시 스토리지가 이미 존재합니다. -pathToIconForGuiDoesNotExistExceptionMessage = GUI용 아이콘의 경로가 존재하지 않습니다: {0} -invalidHostnameSuppliedExceptionMessage = 제공된 호스트 이름이 잘못되었습니다: {0} -endpointAlreadyDefinedExceptionMessage = 이름이 '{0}'인 엔드포인트가 이미 정의되어 있습니다. -certificateExpiredExceptionMessage = 인증서 '{0}'이(가) 만료되었습니다: {1} -endpointNotDefinedForRedirectingExceptionMessage = 리디렉션을 위해 이름이 '{0}'인 엔드포인트가 정의되지 않았습니다. -fileWatcherAlreadyDefinedExceptionMessage = '{0}'라는 이름의 파일 감시자가 이미 정의되었습니다. -handlerAlreadyDefinedExceptionMessage = [{0}] {1}: 핸들러가 이미 정의되었습니다. -maxDaysInvalidExceptionMessage = MaxDays는 0 이상이어야 하지만, 받은 값: {0} -maxSizeInvalidExceptionMessage = MaxSize는 0 이상이어야 하지만, 받은 값: {0} -loggingMethodAlreadyDefinedExceptionMessage = 로깅 방법이 이미 정의되었습니다: {0} -loggingMethodRequiresValidScriptBlockExceptionMessage = '{0}' 로깅 방법에 대한 제공된 출력 방법은 유효한 ScriptBlock이 필요합니다. -csrfCookieRequiresSecretExceptionMessage = CSRF에 대해 쿠키를 사용할 때, 비밀이 필요합니다. 비밀을 제공하거나 전역 비밀 쿠키를 설정하십시오 - (Set-PodeCookieSecret '' -Global) -bodyParserAlreadyDefinedForContentTypeExceptionMessage = {0} 콘텐츠 유형에 대한 바디 파서가 이미 정의되어 있습니다. -middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: 미들웨어가 이미 정의되었습니다. -parameterNotSuppliedInRequestExceptionMessage = 요청에 '{0}'라는 이름의 매개변수가 제공되지 않았거나 데이터가 없습니다. -noDataForFileUploadedExceptionMessage = 요청에서 업로드된 파일 '{0}'에 대한 데이터가 없습니다. -viewsFolderNameAlreadyExistsExceptionMessage = 뷰 폴더 이름이 이미 존재합니다: {0} -viewsPathDoesNotExistExceptionMessage = 뷰 경로가 존재하지 않습니다: {0} -timerAlreadyDefinedExceptionMessage = [타이머] {0}: 타이머가 이미 정의되어 있습니다. -timerParameterMustBeGreaterThanZeroExceptionMessage = [타이머] {0}: {1}은(는) 0보다 커야 합니다. -timerDoesNotExistExceptionMessage = 타이머 '{0}'이(가) 존재하지 않습니다. -mutexAlreadyExistsExceptionMessage = 이름이 '{0}'인 뮤텍스가 이미 존재합니다. -noMutexFoundExceptionMessage = 이름이 '{0}'인 뮤텍스를 찾을 수 없습니다. -failedToAcquireMutexOwnershipExceptionMessage = 뮤텍스 소유권을 획득하지 못했습니다. 뮤텍스 이름: {0} -semaphoreAlreadyExistsExceptionMessage = 이름이 '{0}'인 세마포어가 이미 존재합니다. -failedToAcquireSemaphoreOwnershipExceptionMessage = 세마포어 소유권을 획득하지 못했습니다. 세마포어 이름: {0} -scheduleAlreadyDefinedExceptionMessage = [스케줄] {0}: 스케줄이 이미 정의되어 있습니다. -scheduleCannotHaveNegativeLimitExceptionMessage = [스케줄] {0}: 음수 한도를 가질 수 없습니다. -scheduleEndTimeMustBeInFutureExceptionMessage = [스케줄] {0}: 종료 시간 값은 미래에 있어야 합니다. -scheduleStartTimeAfterEndTimeExceptionMessage = [스케줄] {0}: 'StartTime'이 'EndTime' 이후일 수 없습니다. -maximumConcurrentSchedulesInvalidExceptionMessage = 최대 동시 스케줄 수는 1 이상이어야 하지만 받은 값: {0} -maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 최대 동시 스케줄 수는 최소 {0}보다 작을 수 없지만 받은 값: {1} -scheduleDoesNotExistExceptionMessage = 스케줄 '{0}'이(가) 존재하지 않습니다. -suppliedDateBeforeScheduleStartTimeExceptionMessage = 제공된 날짜가 스케줄 시작 시간 {0} 이전입니다. -suppliedDateAfterScheduleEndTimeExceptionMessage = 제공된 날짜가 스케줄 종료 시간 {0} 이후입니다. -noSemaphoreFoundExceptionMessage = 이름이 '{0}'인 세마포어를 찾을 수 없습니다. -noLogicPassedForRouteExceptionMessage = 경로에 대한 논리가 전달되지 않았습니다: {0} -noPathSuppliedForStaticRouteExceptionMessage = [{0}]: 정적 경로에 대한 경로가 제공되지 않았습니다. -sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: 정적 경로에 대한 제공된 소스 경로가 존재하지 않습니다: {2} -noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: 논리가 전달되지 않았습니다. -moduleDoesNotContainFunctionExceptionMessage = 모듈 {0}에 경로로 변환할 함수 {1}이(가) 포함되어 있지 않습니다. -pageNameShouldBeAlphaNumericExceptionMessage = 페이지 이름은 유효한 알파벳 숫자 값이어야 합니다: {0} -filesHaveChangedMessage = 다음 파일이 변경되었습니다: -multipleEndpointsForGuiMessage = 여러 엔드포인트가 정의되었으며, GUI에는 첫 번째만 사용됩니다. -openingGuiMessage = GUI 열기. -listeningOnEndpointsMessage = 다음 {0} 엔드포인트에서 수신 중 [{1} 스레드]: -specificationMessage = 사양 -documentationMessage = 문서 -restartingServerMessage = 서버를 재시작 중... -doneMessage = 완료 -deprecatedTitleVersionDescriptionWarningMessage = 경고: 'Enable-PodeOpenApi'의 제목, 버전 및 설명이 더 이상 사용되지 않습니다. 대신 'Add-PodeOAInfo'를 사용하십시오. -undefinedOpenApiReferencesMessage = 정의되지 않은 OpenAPI 참조: -definitionTagMessage = 정의 {0}: -openApiGenerationDocumentErrorMessage = OpenAPI 생성 문서 오류: -infoTitleMandatoryMessage = info.title은 필수 항목입니다. -infoVersionMandatoryMessage = info.version은 필수 항목입니다. -missingComponentsMessage = 누락된 구성 요소 -openApiInfoMessage = OpenAPI 정보: -serverLoopingMessage = 서버 루핑 간격 {0}초 -iisShutdownMessage = (IIS 종료) -terminatingMessage = 종료 중... -eolPowerShellWarningMessage = [경고] Pode {0}은 EOL 상태인 PowerShell {1}에서 테스트되지 않았습니다. -untestedPowerShellVersionWarningMessage = [경고] Pode {0}은 출시 당시 사용 가능하지 않았기 때문에 PowerShell {1}에서 테스트되지 않았습니다. -'@ \ No newline at end of file +@{ + schemaValidationRequiresPowerShell610ExceptionMessage = '스키마 유효성 검사는 PowerShell 버전 6.1.0 이상이 필요합니다.' + pathOrScriptBlockRequiredExceptionMessage = '사용자 지정 액세스 값을 소싱하기 위해 경로 또는 ScriptBlock이 필요합니다.' + operationIdMustBeUniqueForArrayExceptionMessage = 'OperationID: {0}은(는) 고유해야 하며 배열에 적용될 수 없습니다.' + endpointNotDefinedForRedirectingExceptionMessage = "리디렉션을 위해 이름이 '{0}'인 엔드포인트가 정의되지 않았습니다." + filesHaveChangedMessage = '다음 파일이 변경되었습니다:' + iisAspnetcoreTokenMissingExceptionMessage = 'IIS ASPNETCORE_TOKEN이 누락되었습니다.' + minValueGreaterThanMaxExceptionMessage = '{0}의 최소 값은 최대 값보다 클 수 없습니다.' + noLogicPassedForRouteExceptionMessage = '경로에 대한 논리가 전달되지 않았습니다: {0}' + scriptPathDoesNotExistExceptionMessage = '스크립트 경로가 존재하지 않습니다: {0}' + mutexAlreadyExistsExceptionMessage = "이름이 '{0}'인 뮤텍스가 이미 존재합니다." + listeningOnEndpointsMessage = '다음 {0} 엔드포인트에서 수신 중 [{1} 스레드]:' + unsupportedFunctionInServerlessContextExceptionMessage = '{0} 함수는 서버리스 컨텍스트에서 지원되지 않습니다.' + expectedNoJwtSignatureSuppliedExceptionMessage = 'JWT 서명이 제공되지 않을 것으로 예상되었습니다.' + secretAlreadyMountedExceptionMessage = "이름이 '{0}'인 시크릿이 이미 마운트되었습니다." + failedToAcquireLockExceptionMessage = '개체에 대한 잠금을 획득하지 못했습니다.' + noPathSuppliedForStaticRouteExceptionMessage = '[{0}]: 정적 경로에 대한 경로가 제공되지 않았습니다.' + invalidHostnameSuppliedExceptionMessage = '제공된 호스트 이름이 잘못되었습니다: {0}' + authMethodAlreadyDefinedExceptionMessage = '인증 방법이 이미 정의되었습니다: {0}' + csrfCookieRequiresSecretExceptionMessage = "CSRF에 대해 쿠키를 사용할 때, 비밀이 필요합니다. 비밀을 제공하거나 전역 비밀 쿠키를 설정하십시오 - (Set-PodeCookieSecret '' -Global)" + nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = '페이지 경로를 생성하려면 비어 있지 않은 ScriptBlock이 필요합니다.' + noPropertiesMutuallyExclusiveExceptionMessage = "매개변수 'NoProperties'는 'Properties', 'MinProperties' 및 'MaxProperties'와 상호 배타적입니다." + incompatiblePodeDllExceptionMessage = '기존의 호환되지 않는 Pode.DLL 버전 {0}이 로드되었습니다. 버전 {1}이 필요합니다. 새로운 Powershell/pwsh 세션을 열고 다시 시도하세요.' + accessMethodDoesNotExistExceptionMessage = '접근 방법이 존재하지 않습니다: {0}.' + scheduleAlreadyDefinedExceptionMessage = '[스케줄] {0}: 스케줄이 이미 정의되어 있습니다.' + secondsValueCannotBeZeroOrLessExceptionMessage = '{0}에 대한 초 값은 0 이하일 수 없습니다.' + pathToLoadNotFoundExceptionMessage = '로드할 경로 {0}을(를) 찾을 수 없습니다: {1}' + failedToImportModuleExceptionMessage = '모듈을 가져오지 못했습니다: {0}' + endpointNotExistExceptionMessage = "프로토콜 '{0}' 및 주소 '{1}' 또는 로컬 주소 '{2}'가 있는 엔드포인트가 존재하지 않습니다." + terminatingMessage = '종료 중...' + noCommandsSuppliedToConvertToRoutesExceptionMessage = '경로로 변환할 명령이 제공되지 않았습니다.' + invalidTaskTypeExceptionMessage = '작업 유형이 유효하지 않습니다. 예상된 유형: [System.Threading.Tasks.Task] 또는 [hashtable]' + alreadyConnectedToWebSocketExceptionMessage = "이름이 '{0}'인 WebSocket에 이미 연결되어 있습니다." + crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = 'CRLF 메시지 끝 검사는 TCP 엔드포인트에서만 지원됩니다.' + testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = "'Test-PodeOAComponentSchema'는 'Enable-PodeOpenApi -EnableSchemaValidation'을 사용하여 활성화해야 합니다." + adModuleNotInstalledExceptionMessage = 'Active Directory 모듈이 설치되지 않았습니다.' + cronExpressionInvalidExceptionMessage = 'Cron 표현식은 5개의 부분으로만 구성되어야 합니다: {0}' + noSessionToSetOnResponseExceptionMessage = '응답에 설정할 세션이 없습니다.' + valueOutOfRangeExceptionMessage = "{1}의 값 '{0}'이(가) 유효하지 않습니다. {2}와 {3} 사이여야 합니다." + loggingMethodAlreadyDefinedExceptionMessage = '로깅 방법이 이미 정의되었습니다: {0}' + noSecretForHmac256ExceptionMessage = 'HMAC256 해시를 위한 비밀이 제공되지 않았습니다.' + eolPowerShellWarningMessage = '[경고] Pode {0}은 EOL 상태인 PowerShell {1}에서 테스트되지 않았습니다.' + runspacePoolFailedToLoadExceptionMessage = '{0} RunspacePool 로드 실패.' + noEventRegisteredExceptionMessage = '등록된 {0} 이벤트가 없습니다: {1}' + scheduleCannotHaveNegativeLimitExceptionMessage = '[스케줄] {0}: 음수 한도를 가질 수 없습니다.' + openApiRequestStyleInvalidForParameterExceptionMessage = 'OpenApi 요청 스타일은 {1} 매개변수에 대해 {0}일 수 없습니다.' + openApiDocumentNotCompliantExceptionMessage = 'OpenAPI 문서는 준수하지 않습니다.' + taskDoesNotExistExceptionMessage = "작업 '{0}'이(가) 존재하지 않습니다." + scopedVariableNotFoundExceptionMessage = '범위 변수 {0}을(를) 찾을 수 없습니다.' + sessionsRequiredForCsrfExceptionMessage = '쿠키를 사용하지 않으려면 CSRF 사용을 위해 세션이 필요합니다.' + nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = '로깅 방법에는 비어 있지 않은 ScriptBlock이 필요합니다.' + credentialsPassedWildcardForHeadersLiteralExceptionMessage = '자격 증명이 전달되면, 헤더에 대한 * 와일드카드는 와일드카드가 아닌 리터럴 문자열로 취급됩니다.' + podeNotInitializedExceptionMessage = 'Pode가 초기화되지 않았습니다.' + multipleEndpointsForGuiMessage = '여러 엔드포인트가 정의되었으며, GUI에는 첫 번째만 사용됩니다.' + operationIdMustBeUniqueExceptionMessage = 'OperationID: {0}은(는) 고유해야 합니다.' + invalidJsonJwtExceptionMessage = 'JWT에서 잘못된 JSON 값이 발견되었습니다.' + noAlgorithmInJwtHeaderExceptionMessage = 'JWT 헤더에 제공된 알고리즘이 없습니다.' + openApiVersionPropertyMandatoryExceptionMessage = 'OpenApi 버전 속성은 필수입니다.' + limitValueCannotBeZeroOrLessExceptionMessage = '{0}에 대한 제한 값은 0 이하일 수 없습니다.' + timerDoesNotExistExceptionMessage = "타이머 '{0}'이(가) 존재하지 않습니다." + openApiGenerationDocumentErrorMessage = 'OpenAPI 생성 문서 오류:' + routeAlreadyContainsCustomAccessExceptionMessage = "경로 '[{0}] {1}'에 '{2}' 이름의 사용자 지정 액세스가 이미 포함되어 있습니다." + maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = '최대 동시 WebSocket 스레드는 최소값 {0}보다 작을 수 없지만 받은 값: {1}' + middlewareAlreadyDefinedExceptionMessage = '[Middleware] {0}: 미들웨어가 이미 정의되었습니다.' + invalidAtomCharacterExceptionMessage = '잘못된 원자 문자: {0}' + cacheStorageNotFoundForRetrieveExceptionMessage = "캐시된 항목 '{1}'을(를) 검색하려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다." + headerMustHaveNameInEncodingContextExceptionMessage = '인코딩 컨텍스트에서 사용될 때 헤더는 이름이 있어야 합니다.' + moduleDoesNotContainFunctionExceptionMessage = '모듈 {0}에 경로로 변환할 함수 {1}이(가) 포함되어 있지 않습니다.' + pathToIconForGuiDoesNotExistExceptionMessage = 'GUI용 아이콘의 경로가 존재하지 않습니다: {0}' + noTitleSuppliedForPageExceptionMessage = '{0} 페이지에 대한 제목이 제공되지 않았습니다.' + certificateSuppliedForNonHttpsWssEndpointExceptionMessage = 'HTTPS/WSS가 아닌 엔드포인트에 제공된 인증서입니다.' + cannotLockNullObjectExceptionMessage = 'null 개체를 잠글 수 없습니다.' + showPodeGuiOnlyAvailableOnWindowsExceptionMessage = 'Show-PodeGui는 현재 Windows PowerShell 및 Windows의 PowerShell 7+에서만 사용할 수 있습니다.' + unlockSecretButNoScriptBlockExceptionMessage = '사용자 정의 비밀 금고 유형에 대해 제공된 Unlock 비밀이지만, Unlock ScriptBlock이 제공되지 않았습니다.' + invalidIpAddressExceptionMessage = '제공된 IP 주소가 유효하지 않습니다: {0}' + maxDaysInvalidExceptionMessage = 'MaxDays는 0 이상이어야 하지만, 받은 값: {0}' + noRemoveScriptBlockForVaultExceptionMessage = "금고 '{0}'에서 비밀을 제거하기 위한 Remove ScriptBlock이 제공되지 않았습니다." + noSecretExpectedForNoSignatureExceptionMessage = '서명이 없는 경우 비밀이 제공되지 않아야 합니다.' + noCertificateFoundExceptionMessage = "'{2}'에 대한 {0}{1}에서 인증서를 찾을 수 없습니다." + minValueInvalidExceptionMessage = "{1}의 최소 값 '{0}'이(가) 유효하지 않습니다. {2} 이상이어야 합니다." + accessRequiresAuthenticationOnRoutesExceptionMessage = '경로에 대한 접근은 인증이 필요합니다.' + noSecretForHmac384ExceptionMessage = 'HMAC384 해시를 위한 비밀이 제공되지 않았습니다.' + windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = 'Windows 로컬 인증 지원은 Windows 전용입니다.' + definitionTagNotDefinedExceptionMessage = '정의 태그 {0}이(가) 정의되지 않았습니다.' + noComponentInDefinitionExceptionMessage = '{2} 정의에서 {0} 유형의 {1} 이름의 구성 요소가 없습니다.' + noSmtpHandlersDefinedExceptionMessage = '정의된 SMTP 핸들러가 없습니다.' + sessionMiddlewareAlreadyInitializedExceptionMessage = '세션 미들웨어가 이미 초기화되었습니다.' + reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = "OpenAPI v3.0에서는 재사용 가능한 구성 요소 기능 'pathItems'를 사용할 수 없습니다." + wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = '헤더에 대한 * 와일드카드는 AutoHeaders 스위치와 호환되지 않습니다.' + noDataForFileUploadedExceptionMessage = "요청에서 업로드된 파일 '{0}'에 대한 데이터가 없습니다." + sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = 'SSE는 Accept 헤더 값이 text/event-stream인 요청에서만 구성할 수 있습니다.' + noSessionAvailableToSaveExceptionMessage = '저장할 수 있는 세션이 없습니다.' + pathParameterRequiresRequiredSwitchExceptionMessage = "매개변수 위치가 'Path'인 경우 'Required' 스위치 매개변수가 필수입니다." + noOpenApiUrlSuppliedExceptionMessage = '{0}에 대한 OpenAPI URL이 제공되지 않았습니다.' + maximumConcurrentSchedulesInvalidExceptionMessage = '최대 동시 스케줄 수는 1 이상이어야 하지만 받은 값: {0}' + snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = 'Snapins는 Windows PowerShell에서만 지원됩니다.' + eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = '이벤트 뷰어 로깅은 Windows에서만 지원됩니다.' + parametersMutuallyExclusiveExceptionMessage = "매개변수 '{0}'와(과) '{1}'는 상호 배타적입니다." + pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 'PathItems 기능은 OpenAPI v3.0.x에서 지원되지 않습니다.' + openApiParameterRequiresNameExceptionMessage = 'OpenApi 매개변수에는 이름이 필요합니다.' + maximumConcurrentTasksLessThanMinimumExceptionMessage = '최대 동시 작업 수는 최소값 {0}보다 작을 수 없지만 받은 값: {1}' + noSemaphoreFoundExceptionMessage = "이름이 '{0}'인 세마포어를 찾을 수 없습니다." + singleValueForIntervalExceptionMessage = '간격을 사용할 때는 단일 {0} 값을 제공할 수 있습니다.' + jwtNotYetValidExceptionMessage = 'JWT가 아직 유효하지 않습니다.' + verbAlreadyDefinedForUrlExceptionMessage = '[동사] {0}: {1}에 대해 이미 정의되었습니다.' + noSecretNamedMountedExceptionMessage = "이름이 '{0}'인 시크릿이 마운트되지 않았습니다." + moduleOrVersionNotFoundExceptionMessage = '{0}에서 모듈 또는 버전을 찾을 수 없습니다: {1}@{2}' + noScriptBlockSuppliedExceptionMessage = 'ScriptBlock이 제공되지 않았습니다.' + noSecretVaultRegisteredExceptionMessage = "이름이 '{0}'인 비밀 금고가 등록되지 않았습니다." + nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = 'RedirectTo 매개변수가 제공된 경우 엔드포인트에 이름이 필요합니다.' + openApiLicenseObjectRequiresNameExceptionMessage = "OpenAPI 객체 'license'는 'name' 속성이 필요합니다. -LicenseName 매개변수를 사용하십시오." + sourcePathDoesNotExistForStaticRouteExceptionMessage = '[{0})] {1}: 정적 경로에 대한 제공된 소스 경로가 존재하지 않습니다: {2}' + noNameForWebSocketDisconnectExceptionMessage = '연결을 끊을 WebSocket의 이름이 제공되지 않았습니다.' + certificateExpiredExceptionMessage = "인증서 '{0}'이(가) 만료되었습니다: {1}" + secretVaultUnlockExpiryDateInPastExceptionMessage = '시크릿 금고의 잠금 해제 만료 날짜가 과거입니다 (UTC): {0}' + invalidExceptionTypeExceptionMessage = '예외가 잘못된 유형입니다. WebException 또는 HttpRequestException이어야 하지만, 얻은 것은: {0}' + invalidSecretValueTypeExceptionMessage = '비밀 값이 잘못된 유형입니다. 예상되는 유형: String, SecureString, HashTable, Byte[] 또는 PSCredential. 그러나 얻은 것은: {0}' + explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = '명시적 TLS 모드는 SMTPS 및 TCPS 엔드포인트에서만 지원됩니다.' + discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = "매개변수 'DiscriminatorMapping'은 'DiscriminatorProperty'가 있을 때만 사용할 수 있습니다." + scriptErrorExceptionMessage = "스크립트 {1} {2} (라인 {3}) 문자 {4}에서 {5}을(를) 실행하는 중에 스크립트 {0} 오류가 발생했습니다. 개체 '{7}' 클래스: {8} 기본 클래스: {9}" + cannotSupplyIntervalForQuarterExceptionMessage = '분기별 간격 값을 제공할 수 없습니다.' + scheduleEndTimeMustBeInFutureExceptionMessage = '[스케줄] {0}: 종료 시간 값은 미래에 있어야 합니다.' + invalidJwtSignatureSuppliedExceptionMessage = '제공된 JWT 서명이 유효하지 않습니다.' + noSetScriptBlockForVaultExceptionMessage = "금고 '{0}'에서 비밀을 업데이트/생성하기 위한 Set ScriptBlock이 제공되지 않았습니다." + accessMethodNotExistForMergingExceptionMessage = '병합을 위한 액세스 방법이 존재하지 않습니다: {0}' + defaultAuthNotInListExceptionMessage = "기본 인증 '{0}'이(가) 제공된 인증 목록에 없습니다." + parameterHasNoNameExceptionMessage = "매개변수에 이름이 없습니다. 'Name' 매개변수를 사용하여 이 구성 요소에 이름을 지정하십시오." + methodPathAlreadyDefinedForUrlExceptionMessage = '[{0}] {1}: {2}에 대해 이미 정의되었습니다.' + fileWatcherAlreadyDefinedExceptionMessage = "'{0}'라는 이름의 파일 감시자가 이미 정의되었습니다." + noServiceHandlersDefinedExceptionMessage = '정의된 서비스 핸들러가 없습니다.' + secretRequiredForCustomSessionStorageExceptionMessage = '사용자 정의 세션 저장소를 사용할 때는 비밀이 필요합니다.' + secretManagementModuleNotInstalledExceptionMessage = 'Microsoft.PowerShell.SecretManagement 모듈이 설치되지 않았습니다.' + noPathSuppliedForRouteExceptionMessage = '경로에 대해 제공된 경로가 없습니다.' + validationOfAnyOfSchemaNotSupportedExceptionMessage = "'anyof'을 포함하는 스키마의 유효성 검사는 지원되지 않습니다." + iisAuthSupportIsForWindowsOnlyExceptionMessage = 'IIS 인증 지원은 Windows 전용입니다.' + oauth2InnerSchemeInvalidExceptionMessage = 'OAuth2 InnerScheme은 Basic 또는 Form 인증 중 하나여야 합니다, 그러나 받은 값: {0}' + noRoutePathSuppliedForPageExceptionMessage = '{0} 페이지에 대한 경로가 제공되지 않았습니다.' + cacheStorageNotFoundForExistsExceptionMessage = "캐시된 항목 '{1}'이(가) 존재하는지 확인하려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다." + handlerAlreadyDefinedExceptionMessage = '[{0}] {1}: 핸들러가 이미 정의되었습니다.' + sessionsNotConfiguredExceptionMessage = '세션이 구성되지 않았습니다.' + propertiesTypeObjectAssociationExceptionMessage = 'Object 유형의 속성만 {0}와(과) 연결될 수 있습니다.' + sessionsRequiredForSessionPersistentAuthExceptionMessage = '세션 지속 인증을 사용하려면 세션이 필요합니다.' + invalidPathWildcardOrDirectoryExceptionMessage = '제공된 경로는 와일드카드 또는 디렉터리가 될 수 없습니다: {0}' + accessMethodAlreadyDefinedExceptionMessage = '액세스 방법이 이미 정의되었습니다: {0}' + parametersValueOrExternalValueMandatoryExceptionMessage = "매개변수 'Value' 또는 'ExternalValue'는 필수입니다." + maximumConcurrentTasksInvalidExceptionMessage = '최대 동시 작업 수는 >=1이어야 하지만 받은 값: {0}' + cannotCreatePropertyWithoutTypeExceptionMessage = '유형이 정의되지 않았기 때문에 속성을 생성할 수 없습니다.' + authMethodNotExistForMergingExceptionMessage = '병합을 위한 인증 방법이 존재하지 않습니다: {0}' + maxValueInvalidExceptionMessage = "{1}의 최대 값 '{0}'이(가) 유효하지 않습니다. {2} 이하여야 합니다." + endpointAlreadyDefinedExceptionMessage = "이름이 '{0}'인 엔드포인트가 이미 정의되어 있습니다." + eventAlreadyRegisteredExceptionMessage = '{0} 이벤트가 이미 등록되었습니다: {1}' + parameterNotSuppliedInRequestExceptionMessage = "요청에 '{0}'라는 이름의 매개변수가 제공되지 않았거나 데이터가 없습니다." + cacheStorageNotFoundForSetExceptionMessage = "캐시된 항목 '{1}'을(를) 설정하려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다." + methodPathAlreadyDefinedExceptionMessage = '[{0}] {1}: 이미 정의되었습니다.' + errorLoggingAlreadyEnabledExceptionMessage = '오류 로깅이 이미 활성화되었습니다.' + valueForUsingVariableNotFoundExceptionMessage = "'`$using:{0}'에 대한 값을 찾을 수 없습니다." + rapidPdfDoesNotSupportOpenApi31ExceptionMessage = '문서 도구 RapidPdf는 OpenAPI 3.1을 지원하지 않습니다.' + oauth2ClientSecretRequiredExceptionMessage = 'PKCE를 사용하지 않을 때 OAuth2에는 클라이언트 비밀이 필요합니다.' + invalidBase64JwtExceptionMessage = 'JWT에서 잘못된 Base64 인코딩 값이 발견되었습니다.' + noSessionToCalculateDataHashExceptionMessage = '데이터 해시를 계산할 세션이 없습니다.' + cacheStorageNotFoundForRemoveExceptionMessage = "캐시된 항목 '{1}'을(를) 제거하려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다." + csrfMiddlewareNotInitializedExceptionMessage = 'CSRF 미들웨어가 초기화되지 않았습니다.' + infoTitleMandatoryMessage = 'info.title은 필수 항목입니다.' + typeCanOnlyBeAssociatedWithObjectExceptionMessage = '유형 {0}는 객체와만 연관될 수 있습니다.' + userFileDoesNotExistExceptionMessage = '사용자 파일이 존재하지 않습니다: {0}' + routeParameterNeedsValidScriptblockExceptionMessage = '경로 매개변수에는 유효하고 비어 있지 않은 ScriptBlock이 필요합니다.' + nextTriggerCalculationErrorExceptionMessage = '다음 트리거 날짜 및 시간을 계산하는 중에 문제가 발생한 것 같습니다: {0}' + cannotLockValueTypeExceptionMessage = '[ValueTypes]를 잠글 수 없습니다.' + failedToCreateOpenSslCertExceptionMessage = 'openssl 인증서 생성 실패: {0}' + jwtExpiredExceptionMessage = 'JWT가 만료되었습니다.' + openingGuiMessage = 'GUI 열기.' + multiTypePropertiesRequireOpenApi31ExceptionMessage = '다중 유형 속성은 OpenApi 버전 3.1 이상이 필요합니다.' + noNameForWebSocketRemoveExceptionMessage = '제거할 WebSocket의 이름이 제공되지 않았습니다.' + maxSizeInvalidExceptionMessage = 'MaxSize는 0 이상이어야 하지만, 받은 값: {0}' + iisShutdownMessage = '(IIS 종료)' + cannotUnlockValueTypeExceptionMessage = '[ValueTypes]를 잠금 해제할 수 없습니다.' + noJwtSignatureForAlgorithmExceptionMessage = '{0}에 대한 JWT 서명이 제공되지 않았습니다.' + maximumConcurrentWebSocketThreadsInvalidExceptionMessage = '최대 동시 WebSocket 스레드는 >=1이어야 하지만 받은 값: {0}' + acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = '확인 메시지는 SMTP 및 TCP 엔드포인트에서만 지원됩니다.' + failedToConnectToUrlExceptionMessage = 'URL에 연결하지 못했습니다: {0}' + failedToAcquireMutexOwnershipExceptionMessage = '뮤텍스 소유권을 획득하지 못했습니다. 뮤텍스 이름: {0}' + sessionsRequiredForOAuth2WithPKCEExceptionMessage = 'PKCE를 사용하는 OAuth2에는 세션이 필요합니다.' + failedToConnectToWebSocketExceptionMessage = 'WebSocket에 연결하지 못했습니다: {0}' + unsupportedObjectExceptionMessage = '지원되지 않는 개체' + failedToParseAddressExceptionMessage = "'{0}'을(를) 유효한 IP/호스트:포트 주소로 구문 분석하지 못했습니다." + mustBeRunningWithAdminPrivilegesExceptionMessage = '관리자 권한으로 실행되어야 비로소 로컬호스트 주소가 아닌 주소를 청취할 수 있습니다.' + specificationMessage = '사양' + cacheStorageNotFoundForClearExceptionMessage = "캐시를 지우려고 할 때 이름이 '{0}'인 캐시 스토리지를 찾을 수 없습니다." + restartingServerMessage = '서버를 재시작 중...' + cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = "매개변수 'Every'가 None으로 설정된 경우 간격을 제공할 수 없습니다." + unsupportedJwtAlgorithmExceptionMessage = 'JWT 알고리즘은 현재 지원되지 않습니다: {0}' + websocketsNotConfiguredForSignalMessagesExceptionMessage = 'WebSockets가 신호 메시지를 보내도록 구성되지 않았습니다.' + invalidLogicTypeInHashtableMiddlewareExceptionMessage = '제공된 Hashtable 미들웨어에 잘못된 논리 유형이 있습니다. 예상된 유형은 ScriptBlock이지만, 얻은 것은: {0}' + maximumConcurrentSchedulesLessThanMinimumExceptionMessage = '최대 동시 스케줄 수는 최소 {0}보다 작을 수 없지만 받은 값: {1}' + failedToAcquireSemaphoreOwnershipExceptionMessage = '세마포어 소유권을 획득하지 못했습니다. 세마포어 이름: {0}' + propertiesParameterWithoutNameExceptionMessage = '속성에 이름이 없으면 Properties 매개변수를 사용할 수 없습니다.' + customSessionStorageMethodNotImplementedExceptionMessage = "사용자 정의 세션 저장소가 필요한 메서드 '{0}()'를 구현하지 않았습니다." + authenticationMethodDoesNotExistExceptionMessage = '인증 방법이 존재하지 않습니다: {0}' + webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = 'Webhooks 기능은 OpenAPI v3.0.x에서 지원되지 않습니다.' + invalidContentTypeForSchemaExceptionMessage = "스키마에 대해 잘못된 'content-type'이 발견되었습니다: {0}" + noUnlockScriptBlockForVaultExceptionMessage = "금고 '{0}'을(를) 해제하는 Unlock ScriptBlock이 제공되지 않았습니다." + definitionTagMessage = '정의 {0}:' + failedToOpenRunspacePoolExceptionMessage = 'RunspacePool을 여는 데 실패했습니다: {0}' + verbNoLogicPassedExceptionMessage = '[동사] {0}: 전달된 로직 없음' + noMutexFoundExceptionMessage = "이름이 '{0}'인 뮤텍스를 찾을 수 없습니다." + documentationMessage = '문서' + timerAlreadyDefinedExceptionMessage = '[타이머] {0}: 타이머가 이미 정의되어 있습니다.' + invalidPortExceptionMessage = '포트는 음수일 수 없습니다: {0}' + viewsFolderNameAlreadyExistsExceptionMessage = '뷰 폴더 이름이 이미 존재합니다: {0}' + noNameForWebSocketResetExceptionMessage = '재설정할 WebSocket의 이름이 제공되지 않았습니다.' + mergeDefaultAuthNotInListExceptionMessage = "병합 기본 인증 '{0}'이(가) 제공된 인증 목록에 없습니다." + descriptionRequiredExceptionMessage = '설명이 필요합니다.' + pageNameShouldBeAlphaNumericExceptionMessage = '페이지 이름은 유효한 알파벳 숫자 값이어야 합니다: {0}' + defaultValueNotBooleanOrEnumExceptionMessage = '기본값이 boolean이 아니며 enum에 속하지 않습니다.' + openApiComponentSchemaDoesNotExistExceptionMessage = 'OpenApi 구성 요소 스키마 {0}이(가) 존재하지 않습니다.' + timerParameterMustBeGreaterThanZeroExceptionMessage = '[타이머] {0}: {1}은(는) 0보다 커야 합니다.' + taskTimedOutExceptionMessage = '작업이 {0}ms 후에 시간 초과되었습니다.' + scheduleStartTimeAfterEndTimeExceptionMessage = "[스케줄] {0}: 'StartTime'이 'EndTime' 이후일 수 없습니다." + infoVersionMandatoryMessage = 'info.version은 필수 항목입니다.' + cannotUnlockNullObjectExceptionMessage = 'null 개체를 잠금 해제할 수 없습니다.' + nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = '사용자 정의 인증 스킴에는 비어 있지 않은 ScriptBlock이 필요합니다.' + validationOfOneOfSchemaNotSupportedExceptionMessage = "'oneof'을 포함하는 스키마의 유효성 검사는 지원되지 않습니다." + routeParameterCannotBeNullExceptionMessage = "'Route' 매개변수는 null일 수 없습니다." + cacheStorageAlreadyExistsExceptionMessage = "이름이 '{0}'인 캐시 스토리지가 이미 존재합니다." + loggingMethodRequiresValidScriptBlockExceptionMessage = "'{0}' 로깅 방법에 대한 제공된 출력 방법은 유효한 ScriptBlock이 필요합니다." + scopedVariableAlreadyDefinedExceptionMessage = '범위 지정 변수가 이미 정의되었습니다: {0}' + oauth2RequiresAuthorizeUrlExceptionMessage = 'OAuth2에는 권한 부여 URL이 필요합니다.' + pathNotExistExceptionMessage = '경로가 존재하지 않습니다: {0}' + noDomainServerNameForWindowsAdAuthExceptionMessage = 'Windows AD 인증을 위한 도메인 서버 이름이 제공되지 않았습니다.' + suppliedDateAfterScheduleEndTimeExceptionMessage = '제공된 날짜가 스케줄 종료 시간 {0} 이후입니다.' + wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = '메서드에 대한 * 와일드카드는 AutoMethods 스위치와 호환되지 않습니다.' + cannotSupplyIntervalForYearExceptionMessage = '매년 간격 값을 제공할 수 없습니다.' + missingComponentsMessage = '누락된 구성 요소' + invalidStrictTransportSecurityDurationExceptionMessage = '잘못된 Strict-Transport-Security 기간이 제공되었습니다: {0}. 0보다 커야 합니다.' + noSecretForHmac512ExceptionMessage = 'HMAC512 해시를 위한 비밀이 제공되지 않았습니다.' + daysInMonthExceededExceptionMessage = '{0}에는 {1}일밖에 없지만 {2}일이 제공되었습니다.' + nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = '사용자 정의 로깅 출력 방법에는 비어 있지 않은 ScriptBlock이 필요합니다.' + encodingAttributeOnlyAppliesToMultipartExceptionMessage = '인코딩 속성은 multipart 및 application/x-www-form-urlencoded 요청 본문에만 적용됩니다.' + suppliedDateBeforeScheduleStartTimeExceptionMessage = '제공된 날짜가 스케줄 시작 시간 {0} 이전입니다.' + unlockSecretRequiredExceptionMessage = "Microsoft.PowerShell.SecretStore를 사용할 때 'UnlockSecret' 속성이 필요합니다." + noLogicPassedForMethodRouteExceptionMessage = '[{0}] {1}: 논리가 전달되지 않았습니다.' + bodyParserAlreadyDefinedForContentTypeExceptionMessage = '{0} 콘텐츠 유형에 대한 바디 파서가 이미 정의되어 있습니다.' + invalidJwtSuppliedExceptionMessage = '제공된 JWT가 유효하지 않습니다.' + sessionsRequiredForFlashMessagesExceptionMessage = '플래시 메시지를 사용하려면 세션이 필요합니다.' + outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = '요청 로깅에 제공된 출력 방법에는 유효한 ScriptBlock이 필요합니다.' + semaphoreAlreadyExistsExceptionMessage = "이름이 '{0}'인 세마포어가 이미 존재합니다." + invalidJwtHeaderAlgorithmSuppliedExceptionMessage = '제공된 JWT 헤더 알고리즘이 유효하지 않습니다.' + oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = "OAuth2 공급자는 InnerScheme을 사용하는 데 필요한 'password' 부여 유형을 지원하지 않습니다." + invalidAliasFoundExceptionMessage = '잘못된 {0} 별칭이 발견되었습니다: {1}' + scheduleDoesNotExistExceptionMessage = "스케줄 '{0}'이(가) 존재하지 않습니다." + accessMethodNotExistExceptionMessage = '액세스 방법이 존재하지 않습니다: {0}' + oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = "OAuth2 공급자는 'code' 응답 유형을 지원하지 않습니다." + untestedPowerShellVersionWarningMessage = '[경고] Pode {0}은 출시 당시 사용 가능하지 않았기 때문에 PowerShell {1}에서 테스트되지 않았습니다.' + secretVaultAlreadyRegisteredAutoImportExceptionMessage = "이름이 '{0}'인 비밀 금고가 이미 자동으로 가져오는 동안 등록되었습니다." + schemeRequiresValidScriptBlockExceptionMessage = "'{0}' 인증 검증기에 제공된 스킴에는 유효한 ScriptBlock이 필요합니다." + serverLoopingMessage = '서버 루핑 간격 {0}초' + certificateThumbprintsNameSupportedOnWindowsExceptionMessage = '인증서 지문/이름은 Windows에서만 지원됩니다.' + sseConnectionNameRequiredExceptionMessage = "-Name 또는 `$WebEvent.Sse.Name에서 SSE 연결 이름이 필요합니다." + invalidMiddlewareTypeExceptionMessage = '제공된 미들웨어 중 하나가 잘못된 유형입니다. 예상된 유형은 ScriptBlock 또는 Hashtable이지만, 얻은 것은: {0}' + noSecretForJwtSignatureExceptionMessage = 'JWT 서명을 위한 비밀이 제공되지 않았습니다.' + modulePathDoesNotExistExceptionMessage = '모듈 경로가 존재하지 않습니다: {0}' + taskAlreadyDefinedExceptionMessage = '[작업] {0}: 작업이 이미 정의되었습니다.' + verbAlreadyDefinedExceptionMessage = '[동사] {0}: 이미 정의되었습니다.' + clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = '클라이언트 인증서는 HTTPS 엔드포인트에서만 지원됩니다.' + endpointNameNotExistExceptionMessage = "이름이 '{0}'인 엔드포인트가 존재하지 않습니다." + middlewareNoLogicSuppliedExceptionMessage = '[미들웨어]: ScriptBlock에 로직이 제공되지 않았습니다.' + scriptBlockRequiredForMergingUsersExceptionMessage = 'Valid가 All일 때 여러 인증된 사용자를 하나의 객체로 병합하려면 ScriptBlock이 필요합니다.' + secretVaultAlreadyRegisteredExceptionMessage = "이름이 '{0}'인 시크릿 금고가 이미 등록되었습니다{1}." + deprecatedTitleVersionDescriptionWarningMessage = "경고: 'Enable-PodeOpenApi'의 제목, 버전 및 설명이 더 이상 사용되지 않습니다. 대신 'Add-PodeOAInfo'를 사용하십시오." + undefinedOpenApiReferencesMessage = '정의되지 않은 OpenAPI 참조:' + doneMessage = '완료' + swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = '이 버전의 Swagger-Editor는 OpenAPI 3.1을 지원하지 않습니다.' + durationMustBeZeroOrGreaterExceptionMessage = '기간은 0 이상이어야 하지만 받은 값: {0}s' + viewsPathDoesNotExistExceptionMessage = '뷰 경로가 존재하지 않습니다: {0}' + discriminatorIncompatibleWithAllOfExceptionMessage = "매개변수 'Discriminator'는 'allOf'와 호환되지 않습니다." + noNameForWebSocketSendMessageExceptionMessage = '메시지를 보낼 WebSocket의 이름이 제공되지 않았습니다.' + hashtableMiddlewareNoLogicExceptionMessage = '제공된 Hashtable 미들웨어에는 정의된 논리가 없습니다.' + openApiInfoMessage = 'OpenAPI 정보:' + invalidSchemeForAuthValidatorExceptionMessage = "'{1}' 인증 검증기에 제공된 '{0}' 스킴에는 유효한 ScriptBlock이 필요합니다." + sseFailedToBroadcastExceptionMessage = '{0}에 대해 정의된 SSE 브로드캐스트 수준으로 인해 SSE 브로드캐스트에 실패했습니다: {1}' + adModuleWindowsOnlyExceptionMessage = 'Active Directory 모듈은 Windows에서만 사용할 수 있습니다.' + requestLoggingAlreadyEnabledExceptionMessage = '요청 로깅이 이미 활성화되었습니다.' + invalidAccessControlMaxAgeDurationExceptionMessage = '잘못된 Access-Control-Max-Age 기간이 제공되었습니다: {0}. 0보다 커야 합니다.' +} + diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index 33279d7cd..6033b59b7 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -1,284 +1,285 @@ -ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyExceptionMessage = Moduł Active Directory jest dostępny tylko w systemie Windows. -adModuleNotInstalledExceptionMessage = Moduł Active Directory nie jest zainstalowany. -secretManagementModuleNotInstalledExceptionMessage = Moduł Microsoft.PowerShell.SecretManagement nie jest zainstalowany. -secretVaultAlreadyRegisteredAutoImportExceptionMessage = Skarbiec z nazwą '{0}' został już zarejestrowany podczas automatycznego importowania skarbców. -failedToOpenRunspacePoolExceptionMessage = Nie udało się otworzyć RunspacePool: {0} -cronExpressionInvalidExceptionMessage = Wyrażenie Cron powinno składać się tylko z 5 części: {0} -invalidAliasFoundExceptionMessage = Znaleziono nieprawidłowy alias {0}: {1} -invalidAtomCharacterExceptionMessage = Nieprawidłowy znak atomu: {0} -minValueGreaterThanMaxExceptionMessage = Minimalna wartość dla {0} nie powinna być większa od maksymalnej wartości. -minValueInvalidExceptionMessage = Minimalna wartość '{0}' dla {1} jest nieprawidłowa, powinna być większa lub równa {2} -maxValueInvalidExceptionMessage = Maksymalna wartość '{0}' dla {1} jest nieprawidłowa, powinna być mniejsza lub równa {2} -valueOutOfRangeExceptionMessage = Wartość '{0}' dla {1} jest nieprawidłowa, powinna być pomiędzy {2} a {3} -daysInMonthExceededExceptionMessage = {0} ma tylko {1} dni, ale podano {2}. -nextTriggerCalculationErrorExceptionMessage = Wygląda na to, że coś poszło nie tak przy próbie obliczenia następnej daty i godziny wyzwalacza: {0} -incompatiblePodeDllExceptionMessage = Istnieje niekompatybilna wersja Pode.DLL {0}. Wymagana wersja {1}. Otwórz nową sesję Powershell/pwsh i spróbuj ponownie. -endpointNotExistExceptionMessage = Punkt końcowy z protokołem '{0}' i adresem '{1}' lub adresem lokalnym '{2}' nie istnieje. -endpointNameNotExistExceptionMessage = Punkt końcowy o nazwie '{0}' nie istnieje. -failedToConnectToUrlExceptionMessage = Nie udało się połączyć z URL: {0} -failedToParseAddressExceptionMessage = Nie udało się przeanalizować '{0}' jako poprawnego adresu IP/Host:Port -invalidIpAddressExceptionMessage = Podany adres IP jest nieprawidłowy: {0} -invalidPortExceptionMessage = Port nie może być ujemny: {0} -pathNotExistExceptionMessage = Ścieżka nie istnieje: {0} -noSecretForHmac256ExceptionMessage = Nie podano tajemnicy dla haszowania HMAC256. -noSecretForHmac384ExceptionMessage = Nie podano tajemnicy dla haszowania HMAC384. -noSecretForHmac512ExceptionMessage = Nie podano tajemnicy dla haszowania HMAC512. -noSecretForJwtSignatureExceptionMessage = Nie podano tajemnicy dla podpisu JWT. -noSecretExpectedForNoSignatureExceptionMessage = Nie oczekiwano podania tajemnicy dla braku podpisu. -unsupportedJwtAlgorithmExceptionMessage = Algorytm JWT nie jest obecnie obsługiwany: {0} -invalidBase64JwtExceptionMessage = Nieprawidłowa wartość zakodowana w Base64 znaleziona w JWT -invalidJsonJwtExceptionMessage = Nieprawidłowa wartość JSON znaleziona w JWT -unsupportedFunctionInServerlessContextExceptionMessage = Funkcja {0} nie jest obsługiwana w kontekście bezserwerowym. -invalidPathWildcardOrDirectoryExceptionMessage = Podana ścieżka nie może być symbolem wieloznacznym ani katalogiem: {0} -invalidExceptionTypeExceptionMessage = Wyjątek jest nieprawidłowego typu, powinien być WebException lub HttpRequestException, ale otrzymano: {0} -pathToLoadNotFoundExceptionMessage = Ścieżka do załadowania {0} nie znaleziona: {1} -singleValueForIntervalExceptionMessage = Możesz podać tylko jedną wartość {0} podczas korzystania z interwałów. -scriptErrorExceptionMessage = Błąd '{0}' w skrypcie {1} {2} (linia {3}) znak {4} podczas wykonywania {5} na {6} obiekt '{7}' Klasa: {8} Klasa bazowa: {9} -noScriptBlockSuppliedExceptionMessage = Nie podano ScriptBlock. -iisAspnetcoreTokenMissingExceptionMessage = Brakujący IIS ASPNETCORE_TOKEN. -propertiesParameterWithoutNameExceptionMessage = Parametry Properties nie mogą być używane, jeśli właściwość nie ma nazwy. -multiTypePropertiesRequireOpenApi31ExceptionMessage = Właściwości wielotypowe wymagają wersji OpenApi 3.1 lub wyższej. -openApiVersionPropertyMandatoryExceptionMessage = Właściwość wersji OpenApi jest obowiązkowa. -webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = Funkcja Webhooks nie jest obsługiwana w OpenAPI v3.0.x -authenticationMethodDoesNotExistExceptionMessage = Metoda uwierzytelniania nie istnieje: {0} -unsupportedObjectExceptionMessage = Obiekt nieobsługiwany -validationOfAnyOfSchemaNotSupportedExceptionMessage = Walidacja schematu, który zawiera 'anyof', nie jest obsługiwana. -validationOfOneOfSchemaNotSupportedExceptionMessage = Walidacja schematu, który zawiera 'oneof', nie jest obsługiwana. -cannotCreatePropertyWithoutTypeExceptionMessage = Nie można utworzyć właściwości, ponieważ nie zdefiniowano typu. -headerMustHaveNameInEncodingContextExceptionMessage = Nagłówek musi mieć nazwę, gdy jest używany w kontekście kodowania. -descriptionRequiredExceptionMessage = Wymagany jest opis. -openApiDocumentNotCompliantExceptionMessage = Dokument OpenAPI nie jest zgodny. -noComponentInDefinitionExceptionMessage = Brak komponentu typu {0} o nazwie {1} dostępnego w definicji {2}. -methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: Już zdefiniowane. -methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: Już zdefiniowane dla {2} -invalidMiddlewareTypeExceptionMessage = Jeden z dostarczonych Middleware jest nieprawidłowego typu. Oczekiwano ScriptBlock lub Hashtable, ale otrzymano: {0} -hashtableMiddlewareNoLogicExceptionMessage = Dostarczone Middleware typu Hashtable nie ma zdefiniowanej logiki. -invalidLogicTypeInHashtableMiddlewareExceptionMessage = Dostarczone Middleware typu Hashtable ma nieprawidłowy typ logiki. Oczekiwano ScriptBlock, ale otrzymano: {0} -scopedVariableAlreadyDefinedExceptionMessage = Zmienna z zakresem już zdefiniowana: {0} -valueForUsingVariableNotFoundExceptionMessage = Nie można znaleźć wartości dla '`$using:{0}'. -unlockSecretRequiredExceptionMessage = Właściwość 'UnlockSecret' jest wymagana przy używaniu Microsoft.PowerShell.SecretStore -unlockSecretButNoScriptBlockExceptionMessage = Podano tajemnicę odblokowania dla niestandardowego typu skarbca, ale nie podano ScriptBlock odblokowania. -noUnlockScriptBlockForVaultExceptionMessage = Nie podano ScriptBlock odblokowania dla odblokowania skarbca '{0}' -noSetScriptBlockForVaultExceptionMessage = Nie podano ScriptBlock dla aktualizacji/tworzenia tajemnic w skarbcu '{0}' -noRemoveScriptBlockForVaultExceptionMessage = Nie podano ScriptBlock dla usuwania tajemnic ze skarbca '{0}' -invalidSecretValueTypeExceptionMessage = Wartość tajemnicy jest nieprawidłowego typu. Oczekiwane typy: String, SecureString, HashTable, Byte[] lub PSCredential. Ale otrzymano: {0} -limitValueCannotBeZeroOrLessExceptionMessage = Wartość limitu nie może być 0 lub mniejsza dla {0} -secondsValueCannotBeZeroOrLessExceptionMessage = Wartość sekund nie może być 0 lub mniejsza dla {0} -failedToCreateOpenSslCertExceptionMessage = Nie udało się utworzyć certyfikatu openssl: {0} -certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Odciski palców/nazwa certyfikatu są obsługiwane tylko w systemie Windows. -noCertificateFoundExceptionMessage = Nie znaleziono certyfikatu w {0}\{1} dla '{2}' -runspacePoolFailedToLoadExceptionMessage = {0} Nie udało się załadować RunspacePool. -noServiceHandlersDefinedExceptionMessage = Nie zdefiniowano żadnych obsługujących usług. -noSessionToSetOnResponseExceptionMessage = Brak dostępnej sesji do ustawienia odpowiedzi. -noSessionToCalculateDataHashExceptionMessage = Brak dostępnej sesji do obliczenia skrótu danych. -moduleOrVersionNotFoundExceptionMessage = Nie znaleziono modułu lub wersji na {0}: {1}@{2} -noSmtpHandlersDefinedExceptionMessage = Nie zdefiniowano żadnych obsługujących SMTP. -taskTimedOutExceptionMessage = Zadanie przekroczyło limit czasu po {0}ms. -verbAlreadyDefinedExceptionMessage = [Czasownik] {0}: Już zdefiniowane -verbAlreadyDefinedForUrlExceptionMessage = [Czasownik] {0}: Już zdefiniowane dla {1} -pathOrScriptBlockRequiredExceptionMessage = Ścieżka lub ScriptBlock są wymagane do pozyskiwania wartości dostępu niestandardowego. -accessMethodAlreadyDefinedExceptionMessage = Metoda dostępu już zdefiniowana: {0} -accessMethodNotExistForMergingExceptionMessage = Metoda dostępu nie istnieje do scalania: {0} -routeAlreadyContainsCustomAccessExceptionMessage = Trasa '[{0}] {1}' już zawiera dostęp niestandardowy z nazwą '{2}' -accessMethodNotExistExceptionMessage = Metoda dostępu nie istnieje: {0} -pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = Funkcja PathItems nie jest obsługiwana w OpenAPI v3.0.x -nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = Dla niestandardowego schematu uwierzytelniania wymagany jest niepusty ScriptBlock. -oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme może być tylko jednym z dwóch: Basic lub Form, ale otrzymano: {0} -sessionsRequiredForOAuth2WithPKCEExceptionMessage = Sesje są wymagane do używania OAuth2 z PKCE -oauth2ClientSecretRequiredExceptionMessage = OAuth2 wymaga tajemnicy klienta, gdy nie używa się PKCE. -authMethodAlreadyDefinedExceptionMessage = Metoda uwierzytelniania już zdefiniowana: {0} -invalidSchemeForAuthValidatorExceptionMessage = Dostarczony schemat '{0}' dla walidatora uwierzytelniania '{1}' wymaga ważnego ScriptBlock. -sessionsRequiredForSessionPersistentAuthExceptionMessage = Sesje są wymagane do używania trwałego uwierzytelniania sesji. -oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 wymaga podania URL autoryzacji -authMethodNotExistForMergingExceptionMessage = Metoda uwierzytelniania nie istnieje dla scalania: {0} -mergeDefaultAuthNotInListExceptionMessage = Uwierzytelnianie MergeDefault '{0}' nie znajduje się na dostarczonej liście uwierzytelniania. -defaultAuthNotInListExceptionMessage = Domyślne uwierzytelnianie '{0}' nie znajduje się na dostarczonej liście uwierzytelniania. -scriptBlockRequiredForMergingUsersExceptionMessage = Wymagany jest ScriptBlock do scalania wielu uwierzytelnionych użytkowników w jeden obiekt, gdy opcja Valid to All. -noDomainServerNameForWindowsAdAuthExceptionMessage = Nie podano nazwy serwera domeny dla uwierzytelniania Windows AD -sessionsNotConfiguredExceptionMessage = Sesje nie zostały skonfigurowane. -windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Wsparcie lokalnego uwierzytelniania Windows jest tylko dla Windows. -iisAuthSupportIsForWindowsOnlyExceptionMessage = Wsparcie uwierzytelniania IIS jest tylko dla Windows. -noAlgorithmInJwtHeaderExceptionMessage = Brak dostarczonego algorytmu w nagłówku JWT. -invalidJwtSuppliedExceptionMessage = Dostarczono nieprawidłowy JWT. -invalidJwtHeaderAlgorithmSuppliedExceptionMessage = Dostarczono nieprawidłowy algorytm nagłówka JWT. -noJwtSignatureForAlgorithmExceptionMessage = Nie dostarczono podpisu JWT dla {0}. -expectedNoJwtSignatureSuppliedExceptionMessage = Oczekiwano, że nie zostanie dostarczony żaden podpis JWT. -invalidJwtSignatureSuppliedExceptionMessage = Dostarczono nieprawidłowy podpis JWT. -jwtExpiredExceptionMessage = JWT wygasł. -jwtNotYetValidExceptionMessage = JWT jeszcze nie jest ważny. -snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Snapiny są obsługiwane tylko w Windows PowerShell. -userFileDoesNotExistExceptionMessage = Plik użytkownika nie istnieje: {0} -schemeRequiresValidScriptBlockExceptionMessage = Dostarczony schemat dla walidatora uwierzytelniania '{0}' wymaga ważnego ScriptBlock. -oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = Dostawca OAuth2 nie obsługuje typu odpowiedzi 'code'. -oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = Dostawca OAuth2 nie obsługuje typu 'password' wymaganego przez InnerScheme. -eventAlreadyRegisteredExceptionMessage = Wydarzenie {0} już zarejestrowane: {1} -noEventRegisteredExceptionMessage = Brak zarejestrowanego wydarzenia {0}: {1} -sessionsRequiredForFlashMessagesExceptionMessage = Sesje są wymagane do używania wiadomości Flash. -eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = Rejestrowanie w Podglądzie zdarzeń jest obsługiwane tylko w systemie Windows. -nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = Metoda niestandardowego rejestrowania wymaga niepustego ScriptBlock. -requestLoggingAlreadyEnabledExceptionMessage = Rejestrowanie żądań jest już włączone. -outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = Podana metoda wyjściowa do rejestrowania żądań wymaga prawidłowego ScriptBlock. -errorLoggingAlreadyEnabledExceptionMessage = Rejestrowanie błędów jest już włączone. -nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = Metoda rejestrowania wymaga niepustego ScriptBlock. -csrfMiddlewareNotInitializedExceptionMessage = Middleware CSRF nie został zainicjowany. -sessionsRequiredForCsrfExceptionMessage = Sesje są wymagane do używania CSRF, chyba że chcesz używać ciasteczek. -middlewareNoLogicSuppliedExceptionMessage = [Middleware]: Nie dostarczono logiki w ScriptBlock. -parameterHasNoNameExceptionMessage = Parametr nie ma nazwy. Proszę nadać tej części nazwę za pomocą parametru 'Name'. -reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = Funkcja wielokrotnego użytku 'pathItems' nie jest dostępna w OpenAPI v3.0. -noPropertiesMutuallyExclusiveExceptionMessage = Parametr 'NoProperties' jest wzajemnie wykluczający się z 'Properties', 'MinProperties' i 'MaxProperties'. -discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = Parametr 'DiscriminatorMapping' może być używany tylko wtedy, gdy jest obecna właściwość 'DiscriminatorProperty'. -discriminatorIncompatibleWithAllOfExceptionMessage = Parametr 'Discriminator' jest niezgodny z 'allOf'. -typeCanOnlyBeAssociatedWithObjectExceptionMessage = Typ {0} może być powiązany tylko z obiektem. -showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui jest obecnie dostępne tylko dla Windows PowerShell i PowerShell 7+ w Windows. -nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = Nazwa jest wymagana dla punktu końcowego, jeśli podano parametr RedirectTo. -clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = Certyfikaty klienta są obsługiwane tylko na punktach końcowych HTTPS. -explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = Tryb TLS Explicity jest obsługiwany tylko na punktach końcowych SMTPS i TCPS. -acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = Komunikat potwierdzenia jest obsługiwany tylko na punktach końcowych SMTP i TCP. -crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = Sprawdzanie końca wiadomości CRLF jest obsługiwane tylko na punktach końcowych TCP. -mustBeRunningWithAdminPrivilegesExceptionMessage = Musisz mieć uprawnienia administratora, aby nasłuchiwać na adresach innych niż localhost. -certificateSuppliedForNonHttpsWssEndpointExceptionMessage = Certyfikat dostarczony dla punktu końcowego innego niż HTTPS/WSS. -websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSockets nie zostały skonfigurowane do wysyłania wiadomości sygnałowych. -noPathSuppliedForRouteExceptionMessage = Nie podano ścieżki dla trasy. -accessRequiresAuthenticationOnRoutesExceptionMessage = Dostęp wymaga uwierzytelnienia na trasach. -accessMethodDoesNotExistExceptionMessage = Metoda dostępu nie istnieje: {0}. -routeParameterNeedsValidScriptblockExceptionMessage = Parametr trasy wymaga prawidłowego, niepustego ScriptBlock. -noCommandsSuppliedToConvertToRoutesExceptionMessage = Nie dostarczono żadnych poleceń do konwersji na trasy. -nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Aby utworzyć trasę strony, wymagany jest niepusty ScriptBlock. -sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE można skonfigurować tylko na żądaniach z wartością nagłówka Accept równą text/event-stream. -sseConnectionNameRequiredExceptionMessage = Wymagana jest nazwa połączenia SSE, z -Name lub $`$WebEvent.Sse.Name -sseFailedToBroadcastExceptionMessage = SSE nie udało się przesłać z powodu zdefiniowanego poziomu przesyłania SSE dla {0}: {1} -podeNotInitializedExceptionMessage = Pode nie został zainicjowany. -invalidTaskTypeExceptionMessage = Typ zadania jest nieprawidłowy, oczekiwano [System.Threading.Tasks.Task] lub [hashtable] -cannotLockValueTypeExceptionMessage = Nie można zablokować [ValueTypes]. -cannotLockNullObjectExceptionMessage = Nie można zablokować pustego obiektu. -failedToAcquireLockExceptionMessage = Nie udało się uzyskać blokady na obiekcie. -cannotUnlockValueTypeExceptionMessage = Nie można odblokować [ValueTypes]. -cannotUnlockNullObjectExceptionMessage = Nie można odblokować pustego obiektu. -sessionMiddlewareAlreadyInitializedExceptionMessage = Middleware sesji został już zainicjowany. -customSessionStorageMethodNotImplementedExceptionMessage = Niestandardowe przechowywanie sesji nie implementuje wymaganego ''{0}()'' sposobu. -secretRequiredForCustomSessionStorageExceptionMessage = Podczas korzystania z niestandardowego przechowywania sesji wymagany jest sekret. -noSessionAvailableToSaveExceptionMessage = Brak dostępnej sesji do zapisania. -cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Nie można dostarczyć interwału, gdy parametr 'Every' jest ustawiony na None. -cannotSupplyIntervalForQuarterExceptionMessage = Nie można dostarczyć wartości interwału dla każdego kwartału. -cannotSupplyIntervalForYearExceptionMessage = Nie można dostarczyć wartości interwału dla każdego roku. -secretVaultAlreadyRegisteredExceptionMessage = Skarbiec tajemnic o nazwie '{0}' został już zarejestrowany{1}. -secretVaultUnlockExpiryDateInPastExceptionMessage = Data wygaśnięcia odblokowania Skarbca tajemnic jest w przeszłości (UTC): {0} -secretAlreadyMountedExceptionMessage = Tajemnica o nazwie '{0}' została już zamontowana. -credentialsPassedWildcardForHeadersLiteralExceptionMessage = Gdy przekazywane są dane uwierzytelniające, symbol wieloznaczny * dla nagłówków będzie traktowany jako dosłowny ciąg znaków, a nie symbol wieloznaczny. -wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = Symbol wieloznaczny * dla nagłówków jest niezgodny z przełącznikiem AutoHeaders. -wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = Symbol wieloznaczny * dla metod jest niezgodny z przełącznikiem AutoMethods. -invalidAccessControlMaxAgeDurationExceptionMessage = Podano nieprawidłowy czas trwania Access-Control-Max-Age: {0}. Powinien być większy niż 0. -noNameForWebSocketDisconnectExceptionMessage = Nie podano nazwy dla rozłączenia WebSocket. -noNameForWebSocketRemoveExceptionMessage = Nie podano nazwy dla usunięcia WebSocket. -noNameForWebSocketSendMessageExceptionMessage = Nie podano nazwy dla wysłania wiadomości do WebSocket. -noSecretNamedMountedExceptionMessage = Nie zamontowano tajemnicy o nazwie '{0}'. -noNameForWebSocketResetExceptionMessage = Nie podano nazwy dla resetowania WebSocket. -schemaValidationRequiresPowerShell610ExceptionMessage = Walidacja schematu wymaga wersji PowerShell 6.1.0 lub nowszej. -routeParameterCannotBeNullExceptionMessage = Parametr 'Route' nie może być pusty. -encodingAttributeOnlyAppliesToMultipartExceptionMessage = Atrybut kodowania dotyczy tylko ciał żądania typu multipart i application/x-www-form-urlencoded. -testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema' musi być włączony przy użyciu 'Enable-PodeOpenApi -EnableSchemaValidation' -openApiComponentSchemaDoesNotExistExceptionMessage = Schemat komponentu OpenApi {0} nie istnieje. -openApiParameterRequiresNameExceptionMessage = Parametr OpenApi wymaga podania nazwy. -openApiLicenseObjectRequiresNameExceptionMessage = Obiekt OpenAPI 'license' wymaga właściwości 'name'. Użyj parametru -LicenseName. -parametersValueOrExternalValueMandatoryExceptionMessage = Parametry 'Value' lub 'ExternalValue' są obowiązkowe. -parametersMutuallyExclusiveExceptionMessage = Parametry '{0}' i '{1}' są wzajemnie wykluczające się. -maximumConcurrentWebSocketThreadsInvalidExceptionMessage = Maksymalna liczba jednoczesnych wątków WebSocket musi wynosić >=1, ale otrzymano: {0} -maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = Maksymalna liczba jednoczesnych wątków WebSocket nie może być mniejsza niż minimum {0}, ale otrzymano: {1} -alreadyConnectedToWebSocketExceptionMessage = Już połączono z WebSocket o nazwie '{0}' -failedToConnectToWebSocketExceptionMessage = Nie udało się połączyć z WebSocket: {0} -verbNoLogicPassedExceptionMessage = [Czasownik] {0}: Nie przekazano logiki -scriptPathDoesNotExistExceptionMessage = Ścieżka skryptu nie istnieje: {0} -failedToImportModuleExceptionMessage = Nie udało się zaimportować modułu: {0} -modulePathDoesNotExistExceptionMessage = Ścieżka modułu nie istnieje: {0} -defaultValueNotBooleanOrEnumExceptionMessage = Wartość domyślna nie jest typu boolean i nie należy do enum. -propertiesTypeObjectAssociationExceptionMessage = Tylko właściwości typu Object mogą być powiązane z {0}. -invalidContentTypeForSchemaExceptionMessage = Nieprawidłowy 'content-type' znaleziony w schemacie: {0} -openApiRequestStyleInvalidForParameterExceptionMessage = Styl żądania OpenApi nie może być {0} dla parametru {1}. -pathParameterRequiresRequiredSwitchExceptionMessage = Jeśli lokalizacja parametru to 'Path', przełącznik 'Required' jest obowiązkowy. -operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0} musi być unikalny i nie może być zastosowany do tablicy. -operationIdMustBeUniqueExceptionMessage = OperationID: {0} musi być unikalny. -noOpenApiUrlSuppliedExceptionMessage = Nie dostarczono adresu URL OpenAPI dla {0}. -noTitleSuppliedForPageExceptionMessage = Nie dostarczono tytułu dla strony {0}. -noRoutePathSuppliedForPageExceptionMessage = Nie dostarczono ścieżki trasy dla strony {0}. -swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = Ta wersja Swagger-Editor nie obsługuje OpenAPI 3.1 -rapidPdfDoesNotSupportOpenApi31ExceptionMessage = Narzędzie do dokumentów RapidPdf nie obsługuje OpenAPI 3.1 -definitionTagNotDefinedExceptionMessage = Etykieta definicji {0} nie jest zdefiniowana. -scopedVariableNotFoundExceptionMessage = Nie znaleziono zmiennej zakresu: {0} -noSecretVaultRegisteredExceptionMessage = Nie zarejestrowano Skarbca Tajemnic o nazwie '{0}'. -invalidStrictTransportSecurityDurationExceptionMessage = Nieprawidłowy czas trwania Strict-Transport-Security: {0}. Powinien być większy niż 0. -durationMustBeZeroOrGreaterExceptionMessage = Czas trwania musi wynosić 0 lub więcej, ale otrzymano: {0}s -taskAlreadyDefinedExceptionMessage = [Zadanie] {0}: Zadanie już zdefiniowane. -maximumConcurrentTasksInvalidExceptionMessage = Maksymalna liczba jednoczesnych zadań musi wynosić >=1, ale otrzymano: {0} -maximumConcurrentTasksLessThanMinimumExceptionMessage = Maksymalna liczba jednoczesnych zadań nie może być mniejsza niż minimum {0}, ale otrzymano: {1} -taskDoesNotExistExceptionMessage = Zadanie '{0}' nie istnieje. -cacheStorageNotFoundForRetrieveExceptionMessage = Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby pobrania elementu z pamięci podręcznej '{1}'. -cacheStorageNotFoundForSetExceptionMessage = Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby ustawienia elementu w pamięci podręcznej '{1}'. -cacheStorageNotFoundForExistsExceptionMessage = Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby sprawdzenia, czy element w pamięci podręcznej '{1}' istnieje. -cacheStorageNotFoundForRemoveExceptionMessage = Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby usunięcia elementu z pamięci podręcznej '{1}'. -cacheStorageNotFoundForClearExceptionMessage = Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby wyczyszczenia pamięci podręcznej. -cacheStorageAlreadyExistsExceptionMessage = Magazyn pamięci podręcznej o nazwie '{0}' już istnieje. -pathToIconForGuiDoesNotExistExceptionMessage = Ścieżka do ikony dla GUI nie istnieje: {0} -invalidHostnameSuppliedExceptionMessage = Podano nieprawidłową nazwę hosta: {0} -endpointAlreadyDefinedExceptionMessage = Punkt końcowy o nazwie '{0}' został już zdefiniowany. -certificateExpiredExceptionMessage = Certyfikat '{0}' wygasł: {1} -endpointNotDefinedForRedirectingExceptionMessage = Nie zdefiniowano punktu końcowego o nazwie '{0}' do przekierowania. -fileWatcherAlreadyDefinedExceptionMessage = Obserwator plików o nazwie '{0}' został już zdefiniowany. -handlerAlreadyDefinedExceptionMessage = [{0}] {1}: Handler już zdefiniowany. -maxDaysInvalidExceptionMessage = MaxDays musi wynosić 0 lub więcej, ale otrzymano: {0} -maxSizeInvalidExceptionMessage = MaxSize musi wynosić 0 lub więcej, ale otrzymano: {0} -loggingMethodAlreadyDefinedExceptionMessage = Metoda logowania już zdefiniowana: {0} -loggingMethodRequiresValidScriptBlockExceptionMessage = Dostarczona metoda wyjściowa dla metody logowania '{0}' wymaga poprawnego ScriptBlock. -csrfCookieRequiresSecretExceptionMessage = Podczas używania ciasteczek do CSRF, wymagany jest Sekret. Możesz dostarczyć Sekret lub ustawić globalny sekret dla ciasteczek - (Set-PodeCookieSecret '' -Global) -bodyParserAlreadyDefinedForContentTypeExceptionMessage = Parser treści dla typu zawartości {0} jest już zdefiniowany. -middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: Middleware już zdefiniowany. -parameterNotSuppliedInRequestExceptionMessage = Parametr o nazwie '{0}' nie został dostarczony w żądaniu lub nie ma dostępnych danych. -noDataForFileUploadedExceptionMessage = Brak danych dla pliku '{0}' przesłanego w żądaniu. -viewsFolderNameAlreadyExistsExceptionMessage = Nazwa folderu Widoków już istnieje: {0} -viewsPathDoesNotExistExceptionMessage = Ścieżka do Widoków nie istnieje: {0} -timerAlreadyDefinedExceptionMessage = [Timer] {0}: Timer już zdefiniowany. -timerParameterMustBeGreaterThanZeroExceptionMessage = [Timer] {0}: {1} musi być większy od 0. -timerDoesNotExistExceptionMessage = Timer '{0}' nie istnieje. -mutexAlreadyExistsExceptionMessage = Muteks o nazwie '{0}' już istnieje. -noMutexFoundExceptionMessage = Nie znaleziono muteksu o nazwie '{0}'. -failedToAcquireMutexOwnershipExceptionMessage = Nie udało się przejąć własności muteksu. Nazwa muteksu: {0} -semaphoreAlreadyExistsExceptionMessage = Semafor o nazwie '{0}' już istnieje. -failedToAcquireSemaphoreOwnershipExceptionMessage = Nie udało się przejąć własności semaforu. Nazwa semaforu: {0} -scheduleAlreadyDefinedExceptionMessage = [Harmonogram] {0}: Harmonogram już zdefiniowany. -scheduleCannotHaveNegativeLimitExceptionMessage = [Harmonogram] {0}: Nie może mieć ujemnego limitu. -scheduleEndTimeMustBeInFutureExceptionMessage = [Harmonogram] {0}: Wartość EndTime musi być w przyszłości. -scheduleStartTimeAfterEndTimeExceptionMessage = [Harmonogram] {0}: Nie może mieć 'StartTime' po 'EndTime'. -maximumConcurrentSchedulesInvalidExceptionMessage = Maksymalna liczba równoczesnych harmonogramów musi wynosić >=1, ale otrzymano: {0} -maximumConcurrentSchedulesLessThanMinimumExceptionMessage = Maksymalna liczba równoczesnych harmonogramów nie może być mniejsza niż minimalna liczba {0}, ale otrzymano: {1} -scheduleDoesNotExistExceptionMessage = Harmonogram '{0}' nie istnieje. -suppliedDateBeforeScheduleStartTimeExceptionMessage = Podana data jest wcześniejsza niż czas rozpoczęcia harmonogramu o {0} -suppliedDateAfterScheduleEndTimeExceptionMessage = Podana data jest późniejsza niż czas zakończenia harmonogramu o {0} -noSemaphoreFoundExceptionMessage = Nie znaleziono semaforu o nazwie '{0}' -noLogicPassedForRouteExceptionMessage = Brak logiki przekazanej dla trasy: {0} -noPathSuppliedForStaticRouteExceptionMessage = [{0}]: Brak dostarczonej ścieżki dla trasy statycznej. -sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: Dostarczona ścieżka źródłowa dla trasy statycznej nie istnieje: {2} -noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Brak logiki przekazanej. -moduleDoesNotContainFunctionExceptionMessage = Moduł {0} nie zawiera funkcji {1} do konwersji na trasę. -pageNameShouldBeAlphaNumericExceptionMessage = Nazwa strony powinna być poprawną wartością alfanumeryczną: {0} -filesHaveChangedMessage = Następujące pliki zostały zmienione: -multipleEndpointsForGuiMessage = Zdefiniowano wiele punktów końcowych, tylko pierwszy będzie używany dla GUI. -openingGuiMessage = Otwieranie GUI. -listeningOnEndpointsMessage = Nasłuchiwanie na następujących {0} punktach końcowych [{1} wątków]: -specificationMessage = Specyfikacja -documentationMessage = Dokumentacja -restartingServerMessage = Restartowanie serwera... -doneMessage = Gotowe -deprecatedTitleVersionDescriptionWarningMessage = OSTRZEŻENIE: Tytuł, Wersja i Opis w 'Enable-PodeOpenApi' są przestarzałe. Proszę użyć 'Add-PodeOAInfo' zamiast tego. -undefinedOpenApiReferencesMessage = Niezdefiniowane odwołania OpenAPI: -definitionTagMessage = Definicja {0}: -openApiGenerationDocumentErrorMessage = Błąd generowania dokumentu OpenAPI: -infoTitleMandatoryMessage = info.title jest obowiązkowe. -infoVersionMandatoryMessage = info.version jest obowiązkowe. -missingComponentsMessage = Brakujące komponenty -openApiInfoMessage = Informacje OpenAPI: -serverLoopingMessage = Pętla serwera co {0} sekund -iisShutdownMessage = (Zamykanie IIS) -terminatingMessage = Kończenie... -eolPowerShellWarningMessage = [OSTRZEŻENIE] Pode {0} nie był testowany na PowerShell {1}, ponieważ jest to wersja EOL. -untestedPowerShellVersionWarningMessage = [OSTRZEŻENIE] Pode {0} nie był testowany na PowerShell {1}, ponieważ nie był dostępny, gdy Pode został wydany. -'@ \ No newline at end of file +@{ + schemaValidationRequiresPowerShell610ExceptionMessage = 'Walidacja schematu wymaga wersji PowerShell 6.1.0 lub nowszej.' + pathOrScriptBlockRequiredExceptionMessage = 'Ścieżka lub ScriptBlock są wymagane do pozyskiwania wartości dostępu niestandardowego.' + operationIdMustBeUniqueForArrayExceptionMessage = 'OperationID: {0} musi być unikalny i nie może być zastosowany do tablicy.' + endpointNotDefinedForRedirectingExceptionMessage = "Nie zdefiniowano punktu końcowego o nazwie '{0}' do przekierowania." + filesHaveChangedMessage = 'Następujące pliki zostały zmienione:' + iisAspnetcoreTokenMissingExceptionMessage = 'Brakujący IIS ASPNETCORE_TOKEN.' + minValueGreaterThanMaxExceptionMessage = 'Minimalna wartość dla {0} nie powinna być większa od maksymalnej wartości.' + noLogicPassedForRouteExceptionMessage = 'Brak logiki przekazanej dla trasy: {0}' + scriptPathDoesNotExistExceptionMessage = 'Ścieżka skryptu nie istnieje: {0}' + mutexAlreadyExistsExceptionMessage = "Muteks o nazwie '{0}' już istnieje." + listeningOnEndpointsMessage = 'Nasłuchiwanie na następujących {0} punktach końcowych [{1} wątków]:' + unsupportedFunctionInServerlessContextExceptionMessage = 'Funkcja {0} nie jest obsługiwana w kontekście bezserwerowym.' + expectedNoJwtSignatureSuppliedExceptionMessage = 'Oczekiwano, że nie zostanie dostarczony żaden podpis JWT.' + secretAlreadyMountedExceptionMessage = "Tajemnica o nazwie '{0}' została już zamontowana." + failedToAcquireLockExceptionMessage = 'Nie udało się uzyskać blokady na obiekcie.' + noPathSuppliedForStaticRouteExceptionMessage = '[{0}]: Brak dostarczonej ścieżki dla trasy statycznej.' + invalidHostnameSuppliedExceptionMessage = 'Podano nieprawidłową nazwę hosta: {0}' + authMethodAlreadyDefinedExceptionMessage = 'Metoda uwierzytelniania już zdefiniowana: {0}' + csrfCookieRequiresSecretExceptionMessage = "Podczas używania ciasteczek do CSRF, wymagany jest Sekret. Możesz dostarczyć Sekret lub ustawić globalny sekret dla ciasteczek - (Set-PodeCookieSecret '' -Global)" + nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 'Aby utworzyć trasę strony, wymagany jest niepusty ScriptBlock.' + noPropertiesMutuallyExclusiveExceptionMessage = "Parametr 'NoProperties' jest wzajemnie wykluczający się z 'Properties', 'MinProperties' i 'MaxProperties'." + incompatiblePodeDllExceptionMessage = 'Istnieje niekompatybilna wersja Pode.DLL {0}. Wymagana wersja {1}. Otwórz nową sesję Powershell/pwsh i spróbuj ponownie.' + accessMethodDoesNotExistExceptionMessage = 'Metoda dostępu nie istnieje: {0}.' + scheduleAlreadyDefinedExceptionMessage = '[Harmonogram] {0}: Harmonogram już zdefiniowany.' + secondsValueCannotBeZeroOrLessExceptionMessage = 'Wartość sekund nie może być 0 lub mniejsza dla {0}' + pathToLoadNotFoundExceptionMessage = 'Ścieżka do załadowania {0} nie znaleziona: {1}' + failedToImportModuleExceptionMessage = 'Nie udało się zaimportować modułu: {0}' + endpointNotExistExceptionMessage = "Punkt końcowy z protokołem '{0}' i adresem '{1}' lub adresem lokalnym '{2}' nie istnieje." + terminatingMessage = 'Kończenie...' + noCommandsSuppliedToConvertToRoutesExceptionMessage = 'Nie dostarczono żadnych poleceń do konwersji na trasy.' + invalidTaskTypeExceptionMessage = 'Typ zadania jest nieprawidłowy, oczekiwano [System.Threading.Tasks.Task] lub [hashtable]' + alreadyConnectedToWebSocketExceptionMessage = "Już połączono z WebSocket o nazwie '{0}'" + crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = 'Sprawdzanie końca wiadomości CRLF jest obsługiwane tylko na punktach końcowych TCP.' + testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = "'Test-PodeOAComponentSchema' musi być włączony przy użyciu 'Enable-PodeOpenApi -EnableSchemaValidation'" + adModuleNotInstalledExceptionMessage = 'Moduł Active Directory nie jest zainstalowany.' + cronExpressionInvalidExceptionMessage = 'Wyrażenie Cron powinno składać się tylko z 5 części: {0}' + noSessionToSetOnResponseExceptionMessage = 'Brak dostępnej sesji do ustawienia odpowiedzi.' + valueOutOfRangeExceptionMessage = "Wartość '{0}' dla {1} jest nieprawidłowa, powinna być pomiędzy {2} a {3}" + loggingMethodAlreadyDefinedExceptionMessage = 'Metoda logowania już zdefiniowana: {0}' + noSecretForHmac256ExceptionMessage = 'Nie podano tajemnicy dla haszowania HMAC256.' + eolPowerShellWarningMessage = '[OSTRZEŻENIE] Pode {0} nie był testowany na PowerShell {1}, ponieważ jest to wersja EOL.' + runspacePoolFailedToLoadExceptionMessage = '{0} Nie udało się załadować RunspacePool.' + noEventRegisteredExceptionMessage = 'Brak zarejestrowanego wydarzenia {0}: {1}' + scheduleCannotHaveNegativeLimitExceptionMessage = '[Harmonogram] {0}: Nie może mieć ujemnego limitu.' + openApiRequestStyleInvalidForParameterExceptionMessage = 'Styl żądania OpenApi nie może być {0} dla parametru {1}.' + openApiDocumentNotCompliantExceptionMessage = 'Dokument OpenAPI nie jest zgodny.' + taskDoesNotExistExceptionMessage = "Zadanie '{0}' nie istnieje." + scopedVariableNotFoundExceptionMessage = 'Nie znaleziono zmiennej zakresu: {0}' + sessionsRequiredForCsrfExceptionMessage = 'Sesje są wymagane do używania CSRF, chyba że chcesz używać ciasteczek.' + nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 'Metoda rejestrowania wymaga niepustego ScriptBlock.' + credentialsPassedWildcardForHeadersLiteralExceptionMessage = 'Gdy przekazywane są dane uwierzytelniające, symbol wieloznaczny * dla nagłówków będzie traktowany jako dosłowny ciąg znaków, a nie symbol wieloznaczny.' + podeNotInitializedExceptionMessage = 'Pode nie został zainicjowany.' + multipleEndpointsForGuiMessage = 'Zdefiniowano wiele punktów końcowych, tylko pierwszy będzie używany dla GUI.' + operationIdMustBeUniqueExceptionMessage = 'OperationID: {0} musi być unikalny.' + invalidJsonJwtExceptionMessage = 'Nieprawidłowa wartość JSON znaleziona w JWT' + noAlgorithmInJwtHeaderExceptionMessage = 'Brak dostarczonego algorytmu w nagłówku JWT.' + openApiVersionPropertyMandatoryExceptionMessage = 'Właściwość wersji OpenApi jest obowiązkowa.' + limitValueCannotBeZeroOrLessExceptionMessage = 'Wartość limitu nie może być 0 lub mniejsza dla {0}' + timerDoesNotExistExceptionMessage = "Timer '{0}' nie istnieje." + openApiGenerationDocumentErrorMessage = 'Błąd generowania dokumentu OpenAPI:' + routeAlreadyContainsCustomAccessExceptionMessage = "Trasa '[{0}] {1}' już zawiera dostęp niestandardowy z nazwą '{2}'" + maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 'Maksymalna liczba jednoczesnych wątków WebSocket nie może być mniejsza niż minimum {0}, ale otrzymano: {1}' + middlewareAlreadyDefinedExceptionMessage = '[Middleware] {0}: Middleware już zdefiniowany.' + invalidAtomCharacterExceptionMessage = 'Nieprawidłowy znak atomu: {0}' + cacheStorageNotFoundForRetrieveExceptionMessage = "Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby pobrania elementu z pamięci podręcznej '{1}'." + headerMustHaveNameInEncodingContextExceptionMessage = 'Nagłówek musi mieć nazwę, gdy jest używany w kontekście kodowania.' + moduleDoesNotContainFunctionExceptionMessage = 'Moduł {0} nie zawiera funkcji {1} do konwersji na trasę.' + pathToIconForGuiDoesNotExistExceptionMessage = 'Ścieżka do ikony dla GUI nie istnieje: {0}' + noTitleSuppliedForPageExceptionMessage = 'Nie dostarczono tytułu dla strony {0}.' + certificateSuppliedForNonHttpsWssEndpointExceptionMessage = 'Certyfikat dostarczony dla punktu końcowego innego niż HTTPS/WSS.' + cannotLockNullObjectExceptionMessage = 'Nie można zablokować pustego obiektu.' + showPodeGuiOnlyAvailableOnWindowsExceptionMessage = 'Show-PodeGui jest obecnie dostępne tylko dla Windows PowerShell i PowerShell 7+ w Windows.' + unlockSecretButNoScriptBlockExceptionMessage = 'Podano tajemnicę odblokowania dla niestandardowego typu skarbca, ale nie podano ScriptBlock odblokowania.' + invalidIpAddressExceptionMessage = 'Podany adres IP jest nieprawidłowy: {0}' + maxDaysInvalidExceptionMessage = 'MaxDays musi wynosić 0 lub więcej, ale otrzymano: {0}' + noRemoveScriptBlockForVaultExceptionMessage = "Nie podano ScriptBlock dla usuwania tajemnic ze skarbca '{0}'" + noSecretExpectedForNoSignatureExceptionMessage = 'Nie oczekiwano podania tajemnicy dla braku podpisu.' + noCertificateFoundExceptionMessage = "Nie znaleziono certyfikatu w {0}{1} dla '{2}'" + minValueInvalidExceptionMessage = "Minimalna wartość '{0}' dla {1} jest nieprawidłowa, powinna być większa lub równa {2}" + accessRequiresAuthenticationOnRoutesExceptionMessage = 'Dostęp wymaga uwierzytelnienia na trasach.' + noSecretForHmac384ExceptionMessage = 'Nie podano tajemnicy dla haszowania HMAC384.' + windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = 'Wsparcie lokalnego uwierzytelniania Windows jest tylko dla Windows.' + definitionTagNotDefinedExceptionMessage = 'Etykieta definicji {0} nie jest zdefiniowana.' + noComponentInDefinitionExceptionMessage = 'Brak komponentu typu {0} o nazwie {1} dostępnego w definicji {2}.' + noSmtpHandlersDefinedExceptionMessage = 'Nie zdefiniowano żadnych obsługujących SMTP.' + sessionMiddlewareAlreadyInitializedExceptionMessage = 'Middleware sesji został już zainicjowany.' + reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = "Funkcja wielokrotnego użytku 'pathItems' nie jest dostępna w OpenAPI v3.0." + wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 'Symbol wieloznaczny * dla nagłówków jest niezgodny z przełącznikiem AutoHeaders.' + noDataForFileUploadedExceptionMessage = "Brak danych dla pliku '{0}' przesłanego w żądaniu." + sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = 'SSE można skonfigurować tylko na żądaniach z wartością nagłówka Accept równą text/event-stream.' + noSessionAvailableToSaveExceptionMessage = 'Brak dostępnej sesji do zapisania.' + pathParameterRequiresRequiredSwitchExceptionMessage = "Jeśli lokalizacja parametru to 'Path', przełącznik 'Required' jest obowiązkowy." + noOpenApiUrlSuppliedExceptionMessage = 'Nie dostarczono adresu URL OpenAPI dla {0}.' + maximumConcurrentSchedulesInvalidExceptionMessage = 'Maksymalna liczba równoczesnych harmonogramów musi wynosić >=1, ale otrzymano: {0}' + snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = 'Snapiny są obsługiwane tylko w Windows PowerShell.' + eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = 'Rejestrowanie w Podglądzie zdarzeń jest obsługiwane tylko w systemie Windows.' + parametersMutuallyExclusiveExceptionMessage = "Parametry '{0}' i '{1}' są wzajemnie wykluczające się." + pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 'Funkcja PathItems nie jest obsługiwana w OpenAPI v3.0.x' + openApiParameterRequiresNameExceptionMessage = 'Parametr OpenApi wymaga podania nazwy.' + maximumConcurrentTasksLessThanMinimumExceptionMessage = 'Maksymalna liczba jednoczesnych zadań nie może być mniejsza niż minimum {0}, ale otrzymano: {1}' + noSemaphoreFoundExceptionMessage = "Nie znaleziono semaforu o nazwie '{0}'" + singleValueForIntervalExceptionMessage = 'Możesz podać tylko jedną wartość {0} podczas korzystania z interwałów.' + jwtNotYetValidExceptionMessage = 'JWT jeszcze nie jest ważny.' + verbAlreadyDefinedForUrlExceptionMessage = '[Czasownik] {0}: Już zdefiniowane dla {1}' + noSecretNamedMountedExceptionMessage = "Nie zamontowano tajemnicy o nazwie '{0}'." + moduleOrVersionNotFoundExceptionMessage = 'Nie znaleziono modułu lub wersji na {0}: {1}@{2}' + noScriptBlockSuppliedExceptionMessage = 'Nie podano ScriptBlock.' + noSecretVaultRegisteredExceptionMessage = "Nie zarejestrowano Skarbca Tajemnic o nazwie '{0}'." + nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = 'Nazwa jest wymagana dla punktu końcowego, jeśli podano parametr RedirectTo.' + openApiLicenseObjectRequiresNameExceptionMessage = "Obiekt OpenAPI 'license' wymaga właściwości 'name'. Użyj parametru -LicenseName." + sourcePathDoesNotExistForStaticRouteExceptionMessage = '[{0})] {1}: Dostarczona ścieżka źródłowa dla trasy statycznej nie istnieje: {2}' + noNameForWebSocketDisconnectExceptionMessage = 'Nie podano nazwy dla rozłączenia WebSocket.' + certificateExpiredExceptionMessage = "Certyfikat '{0}' wygasł: {1}" + secretVaultUnlockExpiryDateInPastExceptionMessage = 'Data wygaśnięcia odblokowania Skarbca tajemnic jest w przeszłości (UTC): {0}' + invalidExceptionTypeExceptionMessage = 'Wyjątek jest nieprawidłowego typu, powinien być WebException lub HttpRequestException, ale otrzymano: {0}' + invalidSecretValueTypeExceptionMessage = 'Wartość tajemnicy jest nieprawidłowego typu. Oczekiwane typy: String, SecureString, HashTable, Byte[] lub PSCredential. Ale otrzymano: {0}' + explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 'Tryb TLS Explicity jest obsługiwany tylko na punktach końcowych SMTPS i TCPS.' + discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = "Parametr 'DiscriminatorMapping' może być używany tylko wtedy, gdy jest obecna właściwość 'DiscriminatorProperty'." + scriptErrorExceptionMessage = "Błąd '{0}' w skrypcie {1} {2} (linia {3}) znak {4} podczas wykonywania {5} na {6} obiekt '{7}' Klasa: {8} Klasa bazowa: {9}" + cannotSupplyIntervalForQuarterExceptionMessage = 'Nie można dostarczyć wartości interwału dla każdego kwartału.' + scheduleEndTimeMustBeInFutureExceptionMessage = '[Harmonogram] {0}: Wartość EndTime musi być w przyszłości.' + invalidJwtSignatureSuppliedExceptionMessage = 'Dostarczono nieprawidłowy podpis JWT.' + noSetScriptBlockForVaultExceptionMessage = "Nie podano ScriptBlock dla aktualizacji/tworzenia tajemnic w skarbcu '{0}'" + accessMethodNotExistForMergingExceptionMessage = 'Metoda dostępu nie istnieje do scalania: {0}' + defaultAuthNotInListExceptionMessage = "Domyślne uwierzytelnianie '{0}' nie znajduje się na dostarczonej liście uwierzytelniania." + parameterHasNoNameExceptionMessage = "Parametr nie ma nazwy. Proszę nadać tej części nazwę za pomocą parametru 'Name'." + methodPathAlreadyDefinedForUrlExceptionMessage = '[{0}] {1}: Już zdefiniowane dla {2}' + fileWatcherAlreadyDefinedExceptionMessage = "Obserwator plików o nazwie '{0}' został już zdefiniowany." + noServiceHandlersDefinedExceptionMessage = 'Nie zdefiniowano żadnych obsługujących usług.' + secretRequiredForCustomSessionStorageExceptionMessage = 'Podczas korzystania z niestandardowego przechowywania sesji wymagany jest sekret.' + secretManagementModuleNotInstalledExceptionMessage = 'Moduł Microsoft.PowerShell.SecretManagement nie jest zainstalowany.' + noPathSuppliedForRouteExceptionMessage = 'Nie podano ścieżki dla trasy.' + validationOfAnyOfSchemaNotSupportedExceptionMessage = "Walidacja schematu, który zawiera 'anyof', nie jest obsługiwana." + iisAuthSupportIsForWindowsOnlyExceptionMessage = 'Wsparcie uwierzytelniania IIS jest tylko dla Windows.' + oauth2InnerSchemeInvalidExceptionMessage = 'OAuth2 InnerScheme może być tylko jednym z dwóch: Basic lub Form, ale otrzymano: {0}' + noRoutePathSuppliedForPageExceptionMessage = 'Nie dostarczono ścieżki trasy dla strony {0}.' + cacheStorageNotFoundForExistsExceptionMessage = "Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby sprawdzenia, czy element w pamięci podręcznej '{1}' istnieje." + handlerAlreadyDefinedExceptionMessage = '[{0}] {1}: Handler już zdefiniowany.' + sessionsNotConfiguredExceptionMessage = 'Sesje nie zostały skonfigurowane.' + propertiesTypeObjectAssociationExceptionMessage = 'Tylko właściwości typu Object mogą być powiązane z {0}.' + sessionsRequiredForSessionPersistentAuthExceptionMessage = 'Sesje są wymagane do używania trwałego uwierzytelniania sesji.' + invalidPathWildcardOrDirectoryExceptionMessage = 'Podana ścieżka nie może być symbolem wieloznacznym ani katalogiem: {0}' + accessMethodAlreadyDefinedExceptionMessage = 'Metoda dostępu już zdefiniowana: {0}' + parametersValueOrExternalValueMandatoryExceptionMessage = "Parametry 'Value' lub 'ExternalValue' są obowiązkowe." + maximumConcurrentTasksInvalidExceptionMessage = 'Maksymalna liczba jednoczesnych zadań musi wynosić >=1, ale otrzymano: {0}' + cannotCreatePropertyWithoutTypeExceptionMessage = 'Nie można utworzyć właściwości, ponieważ nie zdefiniowano typu.' + authMethodNotExistForMergingExceptionMessage = 'Metoda uwierzytelniania nie istnieje dla scalania: {0}' + maxValueInvalidExceptionMessage = "Maksymalna wartość '{0}' dla {1} jest nieprawidłowa, powinna być mniejsza lub równa {2}" + endpointAlreadyDefinedExceptionMessage = "Punkt końcowy o nazwie '{0}' został już zdefiniowany." + eventAlreadyRegisteredExceptionMessage = 'Wydarzenie {0} już zarejestrowane: {1}' + parameterNotSuppliedInRequestExceptionMessage = "Parametr o nazwie '{0}' nie został dostarczony w żądaniu lub nie ma dostępnych danych." + cacheStorageNotFoundForSetExceptionMessage = "Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby ustawienia elementu w pamięci podręcznej '{1}'." + methodPathAlreadyDefinedExceptionMessage = '[{0}] {1}: Już zdefiniowane.' + errorLoggingAlreadyEnabledExceptionMessage = 'Rejestrowanie błędów jest już włączone.' + valueForUsingVariableNotFoundExceptionMessage = "Nie można znaleźć wartości dla '`$using:{0}'." + rapidPdfDoesNotSupportOpenApi31ExceptionMessage = 'Narzędzie do dokumentów RapidPdf nie obsługuje OpenAPI 3.1' + oauth2ClientSecretRequiredExceptionMessage = 'OAuth2 wymaga tajemnicy klienta, gdy nie używa się PKCE.' + invalidBase64JwtExceptionMessage = 'Nieprawidłowa wartość zakodowana w Base64 znaleziona w JWT' + noSessionToCalculateDataHashExceptionMessage = 'Brak dostępnej sesji do obliczenia skrótu danych.' + cacheStorageNotFoundForRemoveExceptionMessage = "Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby usunięcia elementu z pamięci podręcznej '{1}'." + csrfMiddlewareNotInitializedExceptionMessage = 'Middleware CSRF nie został zainicjowany.' + infoTitleMandatoryMessage = 'info.title jest obowiązkowe.' + typeCanOnlyBeAssociatedWithObjectExceptionMessage = 'Typ {0} może być powiązany tylko z obiektem.' + userFileDoesNotExistExceptionMessage = 'Plik użytkownika nie istnieje: {0}' + routeParameterNeedsValidScriptblockExceptionMessage = 'Parametr trasy wymaga prawidłowego, niepustego ScriptBlock.' + nextTriggerCalculationErrorExceptionMessage = 'Wygląda na to, że coś poszło nie tak przy próbie obliczenia następnej daty i godziny wyzwalacza: {0}' + cannotLockValueTypeExceptionMessage = 'Nie można zablokować [ValueTypes].' + failedToCreateOpenSslCertExceptionMessage = 'Nie udało się utworzyć certyfikatu openssl: {0}' + jwtExpiredExceptionMessage = 'JWT wygasł.' + openingGuiMessage = 'Otwieranie GUI.' + multiTypePropertiesRequireOpenApi31ExceptionMessage = 'Właściwości wielotypowe wymagają wersji OpenApi 3.1 lub wyższej.' + noNameForWebSocketRemoveExceptionMessage = 'Nie podano nazwy dla usunięcia WebSocket.' + maxSizeInvalidExceptionMessage = 'MaxSize musi wynosić 0 lub więcej, ale otrzymano: {0}' + iisShutdownMessage = '(Zamykanie IIS)' + cannotUnlockValueTypeExceptionMessage = 'Nie można odblokować [ValueTypes].' + noJwtSignatureForAlgorithmExceptionMessage = 'Nie dostarczono podpisu JWT dla {0}.' + maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 'Maksymalna liczba jednoczesnych wątków WebSocket musi wynosić >=1, ale otrzymano: {0}' + acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 'Komunikat potwierdzenia jest obsługiwany tylko na punktach końcowych SMTP i TCP.' + failedToConnectToUrlExceptionMessage = 'Nie udało się połączyć z URL: {0}' + failedToAcquireMutexOwnershipExceptionMessage = 'Nie udało się przejąć własności muteksu. Nazwa muteksu: {0}' + sessionsRequiredForOAuth2WithPKCEExceptionMessage = 'Sesje są wymagane do używania OAuth2 z PKCE' + failedToConnectToWebSocketExceptionMessage = 'Nie udało się połączyć z WebSocket: {0}' + unsupportedObjectExceptionMessage = 'Obiekt nieobsługiwany' + failedToParseAddressExceptionMessage = "Nie udało się przeanalizować '{0}' jako poprawnego adresu IP/Host:Port" + mustBeRunningWithAdminPrivilegesExceptionMessage = 'Musisz mieć uprawnienia administratora, aby nasłuchiwać na adresach innych niż localhost.' + specificationMessage = 'Specyfikacja' + cacheStorageNotFoundForClearExceptionMessage = "Nie znaleziono magazynu pamięci podręcznej o nazwie '{0}' podczas próby wyczyszczenia pamięci podręcznej." + restartingServerMessage = 'Restartowanie serwera...' + cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = "Nie można dostarczyć interwału, gdy parametr 'Every' jest ustawiony na None." + unsupportedJwtAlgorithmExceptionMessage = 'Algorytm JWT nie jest obecnie obsługiwany: {0}' + websocketsNotConfiguredForSignalMessagesExceptionMessage = 'WebSockets nie zostały skonfigurowane do wysyłania wiadomości sygnałowych.' + invalidLogicTypeInHashtableMiddlewareExceptionMessage = 'Dostarczone Middleware typu Hashtable ma nieprawidłowy typ logiki. Oczekiwano ScriptBlock, ale otrzymano: {0}' + maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 'Maksymalna liczba równoczesnych harmonogramów nie może być mniejsza niż minimalna liczba {0}, ale otrzymano: {1}' + failedToAcquireSemaphoreOwnershipExceptionMessage = 'Nie udało się przejąć własności semaforu. Nazwa semaforu: {0}' + propertiesParameterWithoutNameExceptionMessage = 'Parametry Properties nie mogą być używane, jeśli właściwość nie ma nazwy.' + customSessionStorageMethodNotImplementedExceptionMessage = "Niestandardowe przechowywanie sesji nie implementuje wymaganego ''{0}()'' sposobu." + authenticationMethodDoesNotExistExceptionMessage = 'Metoda uwierzytelniania nie istnieje: {0}' + webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = 'Funkcja Webhooks nie jest obsługiwana w OpenAPI v3.0.x' + invalidContentTypeForSchemaExceptionMessage = "Nieprawidłowy 'content-type' znaleziony w schemacie: {0}" + noUnlockScriptBlockForVaultExceptionMessage = "Nie podano ScriptBlock odblokowania dla odblokowania skarbca '{0}'" + definitionTagMessage = 'Definicja {0}:' + failedToOpenRunspacePoolExceptionMessage = 'Nie udało się otworzyć RunspacePool: {0}' + verbNoLogicPassedExceptionMessage = '[Czasownik] {0}: Nie przekazano logiki' + noMutexFoundExceptionMessage = "Nie znaleziono muteksu o nazwie '{0}'." + documentationMessage = 'Dokumentacja' + timerAlreadyDefinedExceptionMessage = '[Timer] {0}: Timer już zdefiniowany.' + invalidPortExceptionMessage = 'Port nie może być ujemny: {0}' + viewsFolderNameAlreadyExistsExceptionMessage = 'Nazwa folderu Widoków już istnieje: {0}' + noNameForWebSocketResetExceptionMessage = 'Nie podano nazwy dla resetowania WebSocket.' + mergeDefaultAuthNotInListExceptionMessage = "Uwierzytelnianie MergeDefault '{0}' nie znajduje się na dostarczonej liście uwierzytelniania." + descriptionRequiredExceptionMessage = 'Wymagany jest opis.' + pageNameShouldBeAlphaNumericExceptionMessage = 'Nazwa strony powinna być poprawną wartością alfanumeryczną: {0}' + defaultValueNotBooleanOrEnumExceptionMessage = 'Wartość domyślna nie jest typu boolean i nie należy do enum.' + openApiComponentSchemaDoesNotExistExceptionMessage = 'Schemat komponentu OpenApi {0} nie istnieje.' + timerParameterMustBeGreaterThanZeroExceptionMessage = '[Timer] {0}: {1} musi być większy od 0.' + taskTimedOutExceptionMessage = 'Zadanie przekroczyło limit czasu po {0}ms.' + scheduleStartTimeAfterEndTimeExceptionMessage = "[Harmonogram] {0}: Nie może mieć 'StartTime' po 'EndTime'." + infoVersionMandatoryMessage = 'info.version jest obowiązkowe.' + cannotUnlockNullObjectExceptionMessage = 'Nie można odblokować pustego obiektu.' + nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 'Dla niestandardowego schematu uwierzytelniania wymagany jest niepusty ScriptBlock.' + validationOfOneOfSchemaNotSupportedExceptionMessage = "Walidacja schematu, który zawiera 'oneof', nie jest obsługiwana." + routeParameterCannotBeNullExceptionMessage = "Parametr 'Route' nie może być pusty." + cacheStorageAlreadyExistsExceptionMessage = "Magazyn pamięci podręcznej o nazwie '{0}' już istnieje." + loggingMethodRequiresValidScriptBlockExceptionMessage = "Dostarczona metoda wyjściowa dla metody logowania '{0}' wymaga poprawnego ScriptBlock." + scopedVariableAlreadyDefinedExceptionMessage = 'Zmienna z zakresem już zdefiniowana: {0}' + oauth2RequiresAuthorizeUrlExceptionMessage = 'OAuth2 wymaga podania URL autoryzacji' + pathNotExistExceptionMessage = 'Ścieżka nie istnieje: {0}' + noDomainServerNameForWindowsAdAuthExceptionMessage = 'Nie podano nazwy serwera domeny dla uwierzytelniania Windows AD' + suppliedDateAfterScheduleEndTimeExceptionMessage = 'Podana data jest późniejsza niż czas zakończenia harmonogramu o {0}' + wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 'Symbol wieloznaczny * dla metod jest niezgodny z przełącznikiem AutoMethods.' + cannotSupplyIntervalForYearExceptionMessage = 'Nie można dostarczyć wartości interwału dla każdego roku.' + missingComponentsMessage = 'Brakujące komponenty' + invalidStrictTransportSecurityDurationExceptionMessage = 'Nieprawidłowy czas trwania Strict-Transport-Security: {0}. Powinien być większy niż 0.' + noSecretForHmac512ExceptionMessage = 'Nie podano tajemnicy dla haszowania HMAC512.' + daysInMonthExceededExceptionMessage = '{0} ma tylko {1} dni, ale podano {2}.' + nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 'Metoda niestandardowego rejestrowania wymaga niepustego ScriptBlock.' + encodingAttributeOnlyAppliesToMultipartExceptionMessage = 'Atrybut kodowania dotyczy tylko ciał żądania typu multipart i application/x-www-form-urlencoded.' + suppliedDateBeforeScheduleStartTimeExceptionMessage = 'Podana data jest wcześniejsza niż czas rozpoczęcia harmonogramu o {0}' + unlockSecretRequiredExceptionMessage = "Właściwość 'UnlockSecret' jest wymagana przy używaniu Microsoft.PowerShell.SecretStore" + noLogicPassedForMethodRouteExceptionMessage = '[{0}] {1}: Brak logiki przekazanej.' + bodyParserAlreadyDefinedForContentTypeExceptionMessage = 'Parser treści dla typu zawartości {0} jest już zdefiniowany.' + invalidJwtSuppliedExceptionMessage = 'Dostarczono nieprawidłowy JWT.' + sessionsRequiredForFlashMessagesExceptionMessage = 'Sesje są wymagane do używania wiadomości Flash.' + outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = 'Podana metoda wyjściowa do rejestrowania żądań wymaga prawidłowego ScriptBlock.' + semaphoreAlreadyExistsExceptionMessage = "Semafor o nazwie '{0}' już istnieje." + invalidJwtHeaderAlgorithmSuppliedExceptionMessage = 'Dostarczono nieprawidłowy algorytm nagłówka JWT.' + oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = "Dostawca OAuth2 nie obsługuje typu 'password' wymaganego przez InnerScheme." + invalidAliasFoundExceptionMessage = 'Znaleziono nieprawidłowy alias {0}: {1}' + scheduleDoesNotExistExceptionMessage = "Harmonogram '{0}' nie istnieje." + accessMethodNotExistExceptionMessage = 'Metoda dostępu nie istnieje: {0}' + oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = "Dostawca OAuth2 nie obsługuje typu odpowiedzi 'code'." + untestedPowerShellVersionWarningMessage = '[OSTRZEŻENIE] Pode {0} nie był testowany na PowerShell {1}, ponieważ nie był dostępny, gdy Pode został wydany.' + secretVaultAlreadyRegisteredAutoImportExceptionMessage = "Skarbiec z nazwą '{0}' został już zarejestrowany podczas automatycznego importowania skarbców." + schemeRequiresValidScriptBlockExceptionMessage = "Dostarczony schemat dla walidatora uwierzytelniania '{0}' wymaga ważnego ScriptBlock." + serverLoopingMessage = 'Pętla serwera co {0} sekund' + certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 'Odciski palców/nazwa certyfikatu są obsługiwane tylko w systemie Windows.' + sseConnectionNameRequiredExceptionMessage = "Wymagana jest nazwa połączenia SSE, z -Name lub $`$WebEvent.Sse.Name" + invalidMiddlewareTypeExceptionMessage = 'Jeden z dostarczonych Middleware jest nieprawidłowego typu. Oczekiwano ScriptBlock lub Hashtable, ale otrzymano: {0}' + noSecretForJwtSignatureExceptionMessage = 'Nie podano tajemnicy dla podpisu JWT.' + modulePathDoesNotExistExceptionMessage = 'Ścieżka modułu nie istnieje: {0}' + taskAlreadyDefinedExceptionMessage = '[Zadanie] {0}: Zadanie już zdefiniowane.' + verbAlreadyDefinedExceptionMessage = '[Czasownik] {0}: Już zdefiniowane' + clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 'Certyfikaty klienta są obsługiwane tylko na punktach końcowych HTTPS.' + endpointNameNotExistExceptionMessage = "Punkt końcowy o nazwie '{0}' nie istnieje." + middlewareNoLogicSuppliedExceptionMessage = '[Middleware]: Nie dostarczono logiki w ScriptBlock.' + scriptBlockRequiredForMergingUsersExceptionMessage = 'Wymagany jest ScriptBlock do scalania wielu uwierzytelnionych użytkowników w jeden obiekt, gdy opcja Valid to All.' + secretVaultAlreadyRegisteredExceptionMessage = "Skarbiec tajemnic o nazwie '{0}' został już zarejestrowany{1}." + deprecatedTitleVersionDescriptionWarningMessage = "OSTRZEŻENIE: Tytuł, Wersja i Opis w 'Enable-PodeOpenApi' są przestarzałe. Proszę użyć 'Add-PodeOAInfo' zamiast tego." + undefinedOpenApiReferencesMessage = 'Niezdefiniowane odwołania OpenAPI:' + doneMessage = 'Gotowe' + swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = 'Ta wersja Swagger-Editor nie obsługuje OpenAPI 3.1' + durationMustBeZeroOrGreaterExceptionMessage = 'Czas trwania musi wynosić 0 lub więcej, ale otrzymano: {0}s' + viewsPathDoesNotExistExceptionMessage = 'Ścieżka do Widoków nie istnieje: {0}' + discriminatorIncompatibleWithAllOfExceptionMessage = "Parametr 'Discriminator' jest niezgodny z 'allOf'." + noNameForWebSocketSendMessageExceptionMessage = 'Nie podano nazwy dla wysłania wiadomości do WebSocket.' + hashtableMiddlewareNoLogicExceptionMessage = 'Dostarczone Middleware typu Hashtable nie ma zdefiniowanej logiki.' + openApiInfoMessage = 'Informacje OpenAPI:' + invalidSchemeForAuthValidatorExceptionMessage = "Dostarczony schemat '{0}' dla walidatora uwierzytelniania '{1}' wymaga ważnego ScriptBlock." + sseFailedToBroadcastExceptionMessage = 'SSE nie udało się przesłać z powodu zdefiniowanego poziomu przesyłania SSE dla {0}: {1}' + adModuleWindowsOnlyExceptionMessage = 'Moduł Active Directory jest dostępny tylko w systemie Windows.' + requestLoggingAlreadyEnabledExceptionMessage = 'Rejestrowanie żądań jest już włączone.' + invalidAccessControlMaxAgeDurationExceptionMessage = 'Podano nieprawidłowy czas trwania Access-Control-Max-Age: {0}. Powinien być większy niż 0.' +} + diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index 1d3967d70..a2572da09 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -1,284 +1,285 @@ -ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyExceptionMessage = O módulo Active Directory está disponível apenas no Windows. -adModuleNotInstalledExceptionMessage = O módulo Active Directory não está instalado. -secretManagementModuleNotInstalledExceptionMessage = O módulo Microsoft.PowerShell.SecretManagement não está instalado. -secretVaultAlreadyRegisteredAutoImportExceptionMessage = Um Cofre de Segredos com o nome '{0}' já foi registrado durante a importação automática de Cofres de Segredos. -failedToOpenRunspacePoolExceptionMessage = Falha ao abrir o RunspacePool: {0} -cronExpressionInvalidExceptionMessage = A expressão Cron deve consistir apenas em 5 partes: {0} -invalidAliasFoundExceptionMessage = Alias {0} inválido encontrado: {1} -invalidAtomCharacterExceptionMessage = Caractere atômico inválido: {0} -minValueGreaterThanMaxExceptionMessage = O valor mínimo para {0} não deve ser maior que o valor máximo. -minValueInvalidExceptionMessage = O valor mínimo '{0}' para {1} é inválido, deve ser maior ou igual a {2} -maxValueInvalidExceptionMessage = O valor máximo '{0}' para {1} é inválido, deve ser menor ou igual a {2} -valueOutOfRangeExceptionMessage = O valor '{0}' para {1} é inválido, deve estar entre {2} e {3} -daysInMonthExceededExceptionMessage = {0} tem apenas {1} dias, mas {2} foi fornecido. -nextTriggerCalculationErrorExceptionMessage = Parece que algo deu errado ao tentar calcular a próxima data e hora do gatilho: {0} -incompatiblePodeDllExceptionMessage = Uma versão incompatível existente do Pode.DLL {0} está carregada. É necessária a versão {1}. Abra uma nova sessão do Powershell/pwsh e tente novamente. -endpointNotExistExceptionMessage = O ponto de extremidade com o protocolo '{0}' e endereço '{1}' ou endereço local '{2}' não existe. -endpointNameNotExistExceptionMessage = O ponto de extremidade com o nome '{0}' não existe. -failedToConnectToUrlExceptionMessage = Falha ao conectar ao URL: {0} -failedToParseAddressExceptionMessage = Falha ao analisar '{0}' como um endereço IP/Host:Port válido -invalidIpAddressExceptionMessage = O endereço IP fornecido é inválido: {0} -invalidPortExceptionMessage = A porta não pode ser negativa: {0} -pathNotExistExceptionMessage = O caminho não existe: {0} -noSecretForHmac256ExceptionMessage = Nenhum segredo fornecido para o hash HMAC256. -noSecretForHmac384ExceptionMessage = Nenhum segredo fornecido para o hash HMAC384. -noSecretForHmac512ExceptionMessage = Nenhum segredo fornecido para o hash HMAC512. -noSecretForJwtSignatureExceptionMessage = Nenhum segredo fornecido para a assinatura JWT. -noSecretExpectedForNoSignatureExceptionMessage = Não era esperado nenhum segredo para nenhuma assinatura. -unsupportedJwtAlgorithmExceptionMessage = O algoritmo JWT não é atualmente suportado: {0} -invalidBase64JwtExceptionMessage = Valor codificado Base64 inválido encontrado no JWT -invalidJsonJwtExceptionMessage = Valor JSON inválido encontrado no JWT -unsupportedFunctionInServerlessContextExceptionMessage = A função {0} não é suportada em um contexto serverless. -invalidPathWildcardOrDirectoryExceptionMessage = O caminho fornecido não pode ser um curinga ou um diretório: {0} -invalidExceptionTypeExceptionMessage = A exceção é de um tipo inválido, deve ser WebException ou HttpRequestException, mas foi obtido: {0} -pathToLoadNotFoundExceptionMessage = Caminho para carregar {0} não encontrado: {1} -singleValueForIntervalExceptionMessage = Você pode fornecer apenas um único valor {0} ao usar intervalos. -scriptErrorExceptionMessage = Erro '{0}' no script {1} {2} (linha {3}) caractere {4} executando {5} em {6} objeto '{7}' Classe: {8} ClasseBase: {9} -noScriptBlockSuppliedExceptionMessage = Nenhum ScriptBlock fornecido. -iisAspnetcoreTokenMissingExceptionMessage = IIS ASPNETCORE_TOKEN está ausente. -propertiesParameterWithoutNameExceptionMessage = Os parâmetros Properties não podem ser usados se a propriedade não tiver um nome. -multiTypePropertiesRequireOpenApi31ExceptionMessage = Propriedades de múltiplos tipos requerem a versão 3.1 ou superior do OpenApi. -openApiVersionPropertyMandatoryExceptionMessage = A propriedade da versão do OpenApi é obrigatória. -webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = O recurso Webhooks não é suportado no OpenAPI v3.0.x -authenticationMethodDoesNotExistExceptionMessage = O método de autenticação não existe: {0} -unsupportedObjectExceptionMessage = Objeto não suportado -validationOfAnyOfSchemaNotSupportedExceptionMessage = A validação de um esquema que inclui 'anyof' não é suportada. -validationOfOneOfSchemaNotSupportedExceptionMessage = A validação de um esquema que inclui 'oneof' não é suportada. -cannotCreatePropertyWithoutTypeExceptionMessage = Não é possível criar a propriedade porque nenhum tipo é definido. -headerMustHaveNameInEncodingContextExceptionMessage = O cabeçalho deve ter um nome quando usado em um contexto de codificação. -descriptionRequiredExceptionMessage = É necessária uma descrição. -openApiDocumentNotCompliantExceptionMessage = O documento OpenAPI não está em conformidade. -noComponentInDefinitionExceptionMessage = Nenhum componente do tipo {0} chamado {1} está disponível na definição {2}. -methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: Já definido. -methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: Já definido para {2} -invalidMiddlewareTypeExceptionMessage = Um dos Middlewares fornecidos é de um tipo inválido. Esperado ScriptBlock ou Hashtable, mas obtido: {0} -hashtableMiddlewareNoLogicExceptionMessage = Um Middleware do tipo Hashtable fornecido não tem lógica definida. -invalidLogicTypeInHashtableMiddlewareExceptionMessage = Um Middleware do tipo Hashtable fornecido tem um tipo de lógica inválido. Esperado ScriptBlock, mas obtido: {0} -scopedVariableAlreadyDefinedExceptionMessage = Variável de escopo já definida: {0} -valueForUsingVariableNotFoundExceptionMessage = Valor para '`$using:{0}' não pôde ser encontrado. -unlockSecretRequiredExceptionMessage = É necessária uma propriedade 'UnlockSecret' ao usar Microsoft.PowerShell.SecretStore -unlockSecretButNoScriptBlockExceptionMessage = Segredo de desbloqueio fornecido para tipo de Cofre Secreto personalizado, mas nenhum ScriptBlock de desbloqueio fornecido. -noUnlockScriptBlockForVaultExceptionMessage = Nenhum ScriptBlock de desbloqueio fornecido para desbloquear o cofre '{0}' -noSetScriptBlockForVaultExceptionMessage = Nenhum ScriptBlock fornecido para atualizar/criar segredos no cofre '{0}' -noRemoveScriptBlockForVaultExceptionMessage = Nenhum ScriptBlock fornecido para remover segredos do cofre '{0}' -invalidSecretValueTypeExceptionMessage = O valor do segredo é de um tipo inválido. Tipos esperados: String, SecureString, HashTable, Byte[] ou PSCredential. Mas obtido: {0} -limitValueCannotBeZeroOrLessExceptionMessage = O valor limite não pode ser 0 ou inferior para {0} -secondsValueCannotBeZeroOrLessExceptionMessage = O valor dos segundos não pode ser 0 ou inferior para {0} -failedToCreateOpenSslCertExceptionMessage = Falha ao criar o certificado openssl: {0} -certificateThumbprintsNameSupportedOnWindowsExceptionMessage = Impressões digitais/nome do certificado são suportados apenas no Windows. -noCertificateFoundExceptionMessage = Nenhum certificado encontrado em {0}\{1} para '{2}' -runspacePoolFailedToLoadExceptionMessage = {0} Falha ao carregar RunspacePool. -noServiceHandlersDefinedExceptionMessage = Nenhum manipulador de serviço definido. -noSessionToSetOnResponseExceptionMessage = Não há sessão disponível para definir na resposta. -noSessionToCalculateDataHashExceptionMessage = Nenhuma sessão disponível para calcular o hash dos dados. -moduleOrVersionNotFoundExceptionMessage = Módulo ou versão não encontrada em {0}: {1}@{2} -noSmtpHandlersDefinedExceptionMessage = Nenhum manipulador SMTP definido. -taskTimedOutExceptionMessage = A tarefa expirou após {0}ms. -verbAlreadyDefinedExceptionMessage = [Verbo] {0}: Já definido -verbAlreadyDefinedForUrlExceptionMessage = [Verbo] {0}: Já definido para {1} -pathOrScriptBlockRequiredExceptionMessage = É necessário um Caminho ou ScriptBlock para obter os valores de acesso personalizados. -accessMethodAlreadyDefinedExceptionMessage = Método de acesso já definido: {0} -accessMethodNotExistForMergingExceptionMessage = O método de acesso não existe para a mesclagem: {0} -routeAlreadyContainsCustomAccessExceptionMessage = A rota '[{0}] {1}' já contém Acesso Personalizado com o nome '{2}' -accessMethodNotExistExceptionMessage = O método de acesso não existe: {0} -pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = O recurso PathItems não é suportado no OpenAPI v3.0.x -nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = É necessário um ScriptBlock não vazio para o esquema de autenticação personalizado. -oauth2InnerSchemeInvalidExceptionMessage = O OAuth2 InnerScheme só pode ser um de autenticação Basic ou Form, mas foi obtido: {0} -sessionsRequiredForOAuth2WithPKCEExceptionMessage = Sessões são necessárias para usar OAuth2 com PKCE -oauth2ClientSecretRequiredExceptionMessage = OAuth2 requer um Client Secret quando não se usa PKCE. -authMethodAlreadyDefinedExceptionMessage = Método de autenticação já definido: {0} -invalidSchemeForAuthValidatorExceptionMessage = O esquema '{0}' fornecido para o validador de autenticação '{1}' requer um ScriptBlock válido. -sessionsRequiredForSessionPersistentAuthExceptionMessage = Sessões são necessárias para usar a autenticação persistente por sessão. -oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 requer que seja fornecida uma URL de Autorização -authMethodNotExistForMergingExceptionMessage = O método de autenticação não existe para mesclagem: {0} -mergeDefaultAuthNotInListExceptionMessage = A Autenticação MergeDefault '{0}' não está na lista de Autenticação fornecida. -defaultAuthNotInListExceptionMessage = A Autenticação Default '{0}' não está na lista de Autenticação fornecida. -scriptBlockRequiredForMergingUsersExceptionMessage = É necessário um ScriptBlock para mesclar vários usuários autenticados em 1 objeto quando Valid é All. -noDomainServerNameForWindowsAdAuthExceptionMessage = Nenhum nome de servidor de domínio foi fornecido para a autenticação AD do Windows -sessionsNotConfiguredExceptionMessage = As sessões não foram configuradas. -windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = O suporte à Autenticação Local do Windows é apenas para Windows. -iisAuthSupportIsForWindowsOnlyExceptionMessage = O suporte à Autenticação IIS é apenas para Windows. -noAlgorithmInJwtHeaderExceptionMessage = Nenhum algoritmo fornecido no Cabeçalho JWT. -invalidJwtSuppliedExceptionMessage = JWT fornecido inválido. -invalidJwtHeaderAlgorithmSuppliedExceptionMessage = Algoritmo de cabeçalho JWT fornecido inválido. -noJwtSignatureForAlgorithmExceptionMessage = Nenhuma assinatura JWT fornecida para {0}. -expectedNoJwtSignatureSuppliedExceptionMessage = Esperava-se que nenhuma assinatura JWT fosse fornecida. -invalidJwtSignatureSuppliedExceptionMessage = Assinatura JWT fornecida inválida. -jwtExpiredExceptionMessage = O JWT expirou. -jwtNotYetValidExceptionMessage = O JWT ainda não é válido para uso. -snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Os Snapins são suportados apenas no Windows PowerShell. -userFileDoesNotExistExceptionMessage = O arquivo do usuário não existe: {0} -schemeRequiresValidScriptBlockExceptionMessage = O esquema fornecido para o validador de autenticação '{0}' requer um ScriptBlock válido. -oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = O provedor OAuth2 não suporta o response_type 'code'. -oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = O provedor OAuth2 não suporta o grant_type 'password' necessário ao usar um InnerScheme. -eventAlreadyRegisteredExceptionMessage = Evento {0} já registrado: {1} -noEventRegisteredExceptionMessage = Nenhum evento {0} registrado: {1} -sessionsRequiredForFlashMessagesExceptionMessage = Sessões são necessárias para usar mensagens Flash. -eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = O registro no Visualizador de Eventos é suportado apenas no Windows. -nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = Um ScriptBlock não vazio é necessário para o método de registro personalizado. -requestLoggingAlreadyEnabledExceptionMessage = O registro de solicitações já está habilitado. -outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = O método de saída fornecido para o registro de solicitações requer um ScriptBlock válido. -errorLoggingAlreadyEnabledExceptionMessage = O registro de erros já está habilitado. -nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = Um ScriptBlock não vazio é necessário para o método de registro. -csrfMiddlewareNotInitializedExceptionMessage = O Middleware CSRF não foi inicializado. -sessionsRequiredForCsrfExceptionMessage = Sessões são necessárias para usar CSRF, a menos que você queira usar cookies. -middlewareNoLogicSuppliedExceptionMessage = [Middleware]: Nenhuma lógica fornecida no ScriptBlock. -parameterHasNoNameExceptionMessage = O parâmetro não tem nome. Dê um nome a este componente usando o parâmetro 'Name'. -reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = O recurso de componente reutilizável 'pathItems' não está disponível no OpenAPI v3.0. -noPropertiesMutuallyExclusiveExceptionMessage = O parâmetro 'NoProperties' é mutuamente exclusivo com 'Properties', 'MinProperties' e 'MaxProperties'. -discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = O parâmetro 'DiscriminatorMapping' só pode ser usado quando 'DiscriminatorProperty' está presente. -discriminatorIncompatibleWithAllOfExceptionMessage = O parâmetro 'Discriminator' é incompatível com 'allOf'. -typeCanOnlyBeAssociatedWithObjectExceptionMessage = O tipo {0} só pode ser associado a um Objeto. -showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui está atualmente disponível apenas para Windows PowerShell e PowerShell 7+ no Windows. -nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = Um nome é necessário para o endpoint se o parâmetro RedirectTo for fornecido. -clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = Certificados de cliente são suportados apenas em endpoints HTTPS. -explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = O modo TLS explícito é suportado apenas em endpoints SMTPS e TCPS. -acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = A mensagem de reconhecimento é suportada apenas em endpoints SMTP e TCP. -crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = A verificação de fim de mensagem CRLF é suportada apenas em endpoints TCP. -mustBeRunningWithAdminPrivilegesExceptionMessage = Deve estar sendo executado com privilégios de administrador para escutar endereços que não sejam localhost. -certificateSuppliedForNonHttpsWssEndpointExceptionMessage = Certificado fornecido para endpoint que não é HTTPS/WSS. -websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSockets não estão configurados para enviar mensagens de sinal. -noPathSuppliedForRouteExceptionMessage = Nenhum caminho fornecido para a Rota. -accessRequiresAuthenticationOnRoutesExceptionMessage = O acesso requer autenticação nas rotas. -accessMethodDoesNotExistExceptionMessage = O método de acesso não existe: {0}. -routeParameterNeedsValidScriptblockExceptionMessage = O parâmetro da Rota precisa de um ScriptBlock válido e não vazio. -noCommandsSuppliedToConvertToRoutesExceptionMessage = Nenhum comando fornecido para converter em Rotas. -nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = Um ScriptBlock não vazio é necessário para criar uma Rota de Página. -sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE só pode ser configurado em solicitações com um valor de cabeçalho Accept de text/event-stream. -sseConnectionNameRequiredExceptionMessage = Um nome de conexão SSE é necessário, seja de -Name ou `$WebEvent.Sse.Name. -sseFailedToBroadcastExceptionMessage = SSE falhou em transmitir devido ao nível de transmissão SSE definido para {0}: {1}. -podeNotInitializedExceptionMessage = Pode não foi inicializado. -invalidTaskTypeExceptionMessage = O tipo de tarefa é inválido, esperado [System.Threading.Tasks.Task] ou [hashtable]. -cannotLockValueTypeExceptionMessage = Não é possível bloquear um [ValueTypes]. -cannotLockNullObjectExceptionMessage = Não é possível bloquear um objeto nulo. -failedToAcquireLockExceptionMessage = Falha ao adquirir um bloqueio no objeto. -cannotUnlockValueTypeExceptionMessage = Não é possível desbloquear um [ValueTypes]. -cannotUnlockNullObjectExceptionMessage = Não é possível desbloquear um objeto nulo. -sessionMiddlewareAlreadyInitializedExceptionMessage = O Middleware de Sessão já foi inicializado. -customSessionStorageMethodNotImplementedExceptionMessage = O armazenamento de sessão personalizado não implementa o método requerido '{0}()'. -secretRequiredForCustomSessionStorageExceptionMessage = Um segredo é necessário ao usar armazenamento de sessão personalizado. -noSessionAvailableToSaveExceptionMessage = Não há sessão disponível para salvar. -cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = Não é possível fornecer um intervalo quando o parâmetro 'Every' está definido como None. -cannotSupplyIntervalForQuarterExceptionMessage = Não é possível fornecer um valor de intervalo para cada trimestre. -cannotSupplyIntervalForYearExceptionMessage = Não é possível fornecer um valor de intervalo para cada ano. -secretVaultAlreadyRegisteredExceptionMessage = Um Cofre de Segredos com o nome '{0}' já foi registrado{1}. -secretVaultUnlockExpiryDateInPastExceptionMessage = A data de expiração de desbloqueio do Cofre de Segredos está no passado (UTC): {0} -secretAlreadyMountedExceptionMessage = Um Segredo com o nome '{0}' já foi montado. -credentialsPassedWildcardForHeadersLiteralExceptionMessage = Quando as Credenciais são passadas, o caractere curinga * para os Cabeçalhos será interpretado como uma string literal e não como um caractere curinga. -wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = O caractere curinga * para os Cabeçalhos é incompatível com a chave AutoHeaders. -wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = O caractere curinga * para os Métodos é incompatível com a chave AutoMethods. -invalidAccessControlMaxAgeDurationExceptionMessage = Duração inválida fornecida para Access-Control-Max-Age: {0}. Deve ser maior que 0. -noNameForWebSocketDisconnectExceptionMessage = Nenhum nome fornecido para desconectar do WebSocket. -noNameForWebSocketRemoveExceptionMessage = Nenhum nome fornecido para remover o WebSocket. -noNameForWebSocketSendMessageExceptionMessage = Nenhum nome fornecido para enviar mensagem ao WebSocket. -noSecretNamedMountedExceptionMessage = Nenhum Segredo com o nome '{0}' foi montado. -noNameForWebSocketResetExceptionMessage = Nenhum nome fornecido para redefinir o WebSocket. -schemaValidationRequiresPowerShell610ExceptionMessage = A validação do esquema requer a versão 6.1.0 ou superior do PowerShell. -routeParameterCannotBeNullExceptionMessage = O parâmetro 'Route' não pode ser nulo. -encodingAttributeOnlyAppliesToMultipartExceptionMessage = O atributo de codificação só se aplica a corpos de solicitação multipart e application/x-www-form-urlencoded. -testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 'Test-PodeOAComponentSchema' precisa ser habilitado usando 'Enable-PodeOpenApi -EnableSchemaValidation' -openApiComponentSchemaDoesNotExistExceptionMessage = O esquema do componente OpenApi {0} não existe. -openApiParameterRequiresNameExceptionMessage = O parâmetro OpenApi requer um nome especificado. -openApiLicenseObjectRequiresNameExceptionMessage = O objeto OpenAPI 'license' requer a propriedade 'name'. Use o parâmetro -LicenseName. -parametersValueOrExternalValueMandatoryExceptionMessage = Os parâmetros 'Value' ou 'ExternalValue' são obrigatórios. -parametersMutuallyExclusiveExceptionMessage = Os parâmetros '{0}' e '{1}' são mutuamente exclusivos. -maximumConcurrentWebSocketThreadsInvalidExceptionMessage = O número máximo de threads concorrentes do WebSocket deve ser >=1, mas foi obtido: {0} -maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = O número máximo de threads concorrentes do WebSocket não pode ser menor que o mínimo de {0}, mas foi obtido: {1} -alreadyConnectedToWebSocketExceptionMessage = Já conectado ao websocket com o nome '{0}' -failedToConnectToWebSocketExceptionMessage = Falha ao conectar ao websocket: {0} -verbNoLogicPassedExceptionMessage = [Verbo] {0}: Nenhuma lógica passada -scriptPathDoesNotExistExceptionMessage = O caminho do script não existe: {0} -failedToImportModuleExceptionMessage = Falha ao importar módulo: {0} -modulePathDoesNotExistExceptionMessage = O caminho do módulo não existe: {0} -defaultValueNotBooleanOrEnumExceptionMessage = O valor padrão não é booleano e não faz parte do enum. -propertiesTypeObjectAssociationExceptionMessage = Apenas propriedades do tipo Objeto podem ser associadas com {0}. -invalidContentTypeForSchemaExceptionMessage = 'content-type' inválido encontrado para o esquema: {0} -openApiRequestStyleInvalidForParameterExceptionMessage = O estilo da solicitação OpenApi não pode ser {0} para um parâmetro {1}. -pathParameterRequiresRequiredSwitchExceptionMessage = Se a localização do parâmetro for 'Path', o parâmetro de switch 'Required' é obrigatório. -operationIdMustBeUniqueForArrayExceptionMessage = OperationID: {0} deve ser único e não pode ser aplicado a uma matriz. -operationIdMustBeUniqueExceptionMessage = OperationID: {0} deve ser único. -noOpenApiUrlSuppliedExceptionMessage = Nenhuma URL do OpenAPI fornecida para {0}. -noTitleSuppliedForPageExceptionMessage = Nenhum título fornecido para a página {0}. -noRoutePathSuppliedForPageExceptionMessage = Nenhum caminho de rota fornecido para a página {0}. -swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = Esta versão do Swagger-Editor não suporta OpenAPI 3.1 -rapidPdfDoesNotSupportOpenApi31ExceptionMessage = A ferramenta de documentos RapidPdf não suporta OpenAPI 3.1 -definitionTagNotDefinedExceptionMessage = A tag de definição {0} não existe. -scopedVariableNotFoundExceptionMessage = Variável de escopo não encontrada: {0} -noSecretVaultRegisteredExceptionMessage = Nenhum Cofre de Segredos com o nome '{0}' foi registrado. -invalidStrictTransportSecurityDurationExceptionMessage = Duração inválida fornecida para Strict-Transport-Security: {0}. Deve ser maior que 0. -durationMustBeZeroOrGreaterExceptionMessage = A duração deve ser 0 ou maior, mas foi obtido: {0}s -taskAlreadyDefinedExceptionMessage = [Tarefa] {0}: Tarefa já definida. -maximumConcurrentTasksInvalidExceptionMessage = O número máximo de tarefas concorrentes deve ser >=1, mas foi obtido: {0} -maximumConcurrentTasksLessThanMinimumExceptionMessage = O número máximo de tarefas concorrentes não pode ser menor que o mínimo de {0}, mas foi obtido: {1} -taskDoesNotExistExceptionMessage = A tarefa '{0}' não existe. -cacheStorageNotFoundForRetrieveExceptionMessage = Armazenamento em cache com o nome '{0}' não encontrado ao tentar recuperar o item em cache '{1}'. -cacheStorageNotFoundForSetExceptionMessage = Armazenamento em cache com o nome '{0}' não encontrado ao tentar definir o item em cache '{1}'. -cacheStorageNotFoundForExistsExceptionMessage = Armazenamento em cache com o nome '{0}' não encontrado ao tentar verificar se o item em cache '{1}' existe. -cacheStorageNotFoundForRemoveExceptionMessage = Armazenamento em cache com o nome '{0}' não encontrado ao tentar remover o item em cache '{1}'. -cacheStorageNotFoundForClearExceptionMessage = Armazenamento em cache com o nome '{0}' não encontrado ao tentar limpar o cache. -cacheStorageAlreadyExistsExceptionMessage = Armazenamento em cache com o nome '{0}' já existe. -pathToIconForGuiDoesNotExistExceptionMessage = O caminho para o ícone da interface gráfica não existe: {0} -invalidHostnameSuppliedExceptionMessage = Nome de host fornecido inválido: {0} -endpointAlreadyDefinedExceptionMessage = Um ponto de extremidade chamado '{0}' já foi definido. -certificateExpiredExceptionMessage = O certificado '{0}' expirou: {1} -endpointNotDefinedForRedirectingExceptionMessage = Não foi definido um ponto de extremidade chamado '{0}' para redirecionamento. -fileWatcherAlreadyDefinedExceptionMessage = Um Observador de Arquivos chamado '{0}' já foi definido. -handlerAlreadyDefinedExceptionMessage = [{0}] {1}: Manipulador já definido. -maxDaysInvalidExceptionMessage = MaxDays deve ser igual ou maior que 0, mas foi obtido: {0} -maxSizeInvalidExceptionMessage = MaxSize deve ser igual ou maior que 0, mas foi obtido: {0} -loggingMethodAlreadyDefinedExceptionMessage = Método de registro já definido: {0} -loggingMethodRequiresValidScriptBlockExceptionMessage = O método de saída fornecido para o método de registro '{0}' requer um ScriptBlock válido. -csrfCookieRequiresSecretExceptionMessage = Ao usar cookies para CSRF, é necessário um Segredo. Você pode fornecer um Segredo ou definir o segredo global do Cookie - (Set-PodeCookieSecret '' -Global) -bodyParserAlreadyDefinedForContentTypeExceptionMessage = Um body-parser já está definido para o tipo de conteúdo {0}. -middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: Middleware já definido. -parameterNotSuppliedInRequestExceptionMessage = Um parâmetro chamado '{0}' não foi fornecido na solicitação ou não há dados disponíveis. -noDataForFileUploadedExceptionMessage = Nenhum dado para o arquivo '{0}' foi enviado na solicitação. -viewsFolderNameAlreadyExistsExceptionMessage = O nome da pasta Views já existe: {0} -viewsPathDoesNotExistExceptionMessage = O caminho das Views não existe: {0} -timerAlreadyDefinedExceptionMessage = [Temporizador] {0}: Temporizador já definido. -timerParameterMustBeGreaterThanZeroExceptionMessage = [Temporizador] {0}: {1} deve ser maior que 0. -timerDoesNotExistExceptionMessage = O temporizador '{0}' não existe. -mutexAlreadyExistsExceptionMessage = Já existe um mutex com o seguinte nome: {0} -noMutexFoundExceptionMessage = Nenhum mutex encontrado chamado '{0}' -failedToAcquireMutexOwnershipExceptionMessage = Falha ao adquirir a propriedade do mutex. Nome do mutex: {0} -semaphoreAlreadyExistsExceptionMessage = Já existe um semáforo com o seguinte nome: {0} -failedToAcquireSemaphoreOwnershipExceptionMessage = Falha ao adquirir a propriedade do semáforo. Nome do semáforo: {0} -scheduleAlreadyDefinedExceptionMessage = [Agenda] {0}: Agenda já definida. -scheduleCannotHaveNegativeLimitExceptionMessage = [Agenda] {0}: Não pode ter um limite negativo. -scheduleEndTimeMustBeInFutureExceptionMessage = [Agenda] {0}: O valor de EndTime deve estar no futuro. -scheduleStartTimeAfterEndTimeExceptionMessage = [Agenda] {0}: Não pode ter um 'StartTime' após o 'EndTime' -maximumConcurrentSchedulesInvalidExceptionMessage = As agendas simultâneas máximas devem ser >=1, mas obtidas: {0} -maximumConcurrentSchedulesLessThanMinimumExceptionMessage = As agendas simultâneas máximas não podem ser inferiores ao mínimo de {0}, mas obtidas: {1} -scheduleDoesNotExistExceptionMessage = A agenda '{0}' não existe. -suppliedDateBeforeScheduleStartTimeExceptionMessage = A data fornecida é anterior ao horário de início da agenda em {0} -suppliedDateAfterScheduleEndTimeExceptionMessage = A data fornecida é posterior ao horário de término da agenda em {0} -noSemaphoreFoundExceptionMessage = Nenhum semáforo encontrado chamado '{0}' -noLogicPassedForRouteExceptionMessage = Nenhuma lógica passada para a Rota: {0} -noPathSuppliedForStaticRouteExceptionMessage = [{0}]: Nenhum caminho fornecido para a Rota Estática. -sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: O caminho de origem fornecido para a Rota Estática não existe: {2} -noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: Nenhuma lógica passada. -moduleDoesNotContainFunctionExceptionMessage = O módulo {0} não contém a função {1} para converter em uma Rota. -pageNameShouldBeAlphaNumericExceptionMessage = O nome da página deve ser um valor alfanumérico válido: {0} -filesHaveChangedMessage = Os seguintes arquivos foram alterados: -multipleEndpointsForGuiMessage = Múltiplos endpoints definidos, apenas o primeiro será usado para a GUI. -openingGuiMessage = Abrindo a GUI. -listeningOnEndpointsMessage = Ouvindo nos seguintes {0} endpoint(s) [{1} thread(s)]: -specificationMessage = Especificação -documentationMessage = Documentação -restartingServerMessage = Reiniciando o servidor... -doneMessage = Concluído -deprecatedTitleVersionDescriptionWarningMessage = AVISO: Título, Versão e Descrição em 'Enable-PodeOpenApi' estão obsoletos. Utilize 'Add-PodeOAInfo' em vez disso. -undefinedOpenApiReferencesMessage = Referências OpenAPI indefinidas: -definitionTagMessage = Definição {0}: -openApiGenerationDocumentErrorMessage = Erro no documento de geração do OpenAPI: -infoTitleMandatoryMessage = info.title é obrigatório. -infoVersionMandatoryMessage = info.version é obrigatório. -missingComponentsMessage = Componente(s) ausente(s) -openApiInfoMessage = Informações OpenAPI: -serverLoopingMessage = Looping do servidor a cada {0} segundos -iisShutdownMessage = (Desligamento do IIS) -terminatingMessage = Terminando... -eolPowerShellWarningMessage = [AVISO] Pode {0} não foi testado no PowerShell {1}, pois está em EOL. -untestedPowerShellVersionWarningMessage = [AVISO] Pode {0} não foi testado no PowerShell {1}, pois não estava disponível quando o Pode foi lançado. -'@ \ No newline at end of file +@{ + schemaValidationRequiresPowerShell610ExceptionMessage = 'A validação do esquema requer a versão 6.1.0 ou superior do PowerShell.' + pathOrScriptBlockRequiredExceptionMessage = 'É necessário um Caminho ou ScriptBlock para obter os valores de acesso personalizados.' + operationIdMustBeUniqueForArrayExceptionMessage = 'OperationID: {0} deve ser único e não pode ser aplicado a uma matriz.' + endpointNotDefinedForRedirectingExceptionMessage = "Não foi definido um ponto de extremidade chamado '{0}' para redirecionamento." + filesHaveChangedMessage = 'Os seguintes arquivos foram alterados:' + iisAspnetcoreTokenMissingExceptionMessage = 'IIS ASPNETCORE_TOKEN está ausente.' + minValueGreaterThanMaxExceptionMessage = 'O valor mínimo para {0} não deve ser maior que o valor máximo.' + noLogicPassedForRouteExceptionMessage = 'Nenhuma lógica passada para a Rota: {0}' + scriptPathDoesNotExistExceptionMessage = 'O caminho do script não existe: {0}' + mutexAlreadyExistsExceptionMessage = 'Já existe um mutex com o seguinte nome: {0}' + listeningOnEndpointsMessage = 'Ouvindo nos seguintes {0} endpoint(s) [{1} thread(s)]:' + unsupportedFunctionInServerlessContextExceptionMessage = 'A função {0} não é suportada em um contexto serverless.' + expectedNoJwtSignatureSuppliedExceptionMessage = 'Esperava-se que nenhuma assinatura JWT fosse fornecida.' + secretAlreadyMountedExceptionMessage = "Um Segredo com o nome '{0}' já foi montado." + failedToAcquireLockExceptionMessage = 'Falha ao adquirir um bloqueio no objeto.' + noPathSuppliedForStaticRouteExceptionMessage = '[{0}]: Nenhum caminho fornecido para a Rota Estática.' + invalidHostnameSuppliedExceptionMessage = 'Nome de host fornecido inválido: {0}' + authMethodAlreadyDefinedExceptionMessage = 'Método de autenticação já definido: {0}' + csrfCookieRequiresSecretExceptionMessage = "Ao usar cookies para CSRF, é necessário um Segredo. Você pode fornecer um Segredo ou definir o segredo global do Cookie - (Set-PodeCookieSecret '' -Global)" + nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 'Um ScriptBlock não vazio é necessário para criar uma Rota de Página.' + noPropertiesMutuallyExclusiveExceptionMessage = "O parâmetro 'NoProperties' é mutuamente exclusivo com 'Properties', 'MinProperties' e 'MaxProperties'." + incompatiblePodeDllExceptionMessage = 'Uma versão incompatível existente do Pode.DLL {0} está carregada. É necessária a versão {1}. Abra uma nova sessão do Powershell/pwsh e tente novamente.' + accessMethodDoesNotExistExceptionMessage = 'O método de acesso não existe: {0}.' + scheduleAlreadyDefinedExceptionMessage = '[Agenda] {0}: Agenda já definida.' + secondsValueCannotBeZeroOrLessExceptionMessage = 'O valor dos segundos não pode ser 0 ou inferior para {0}' + pathToLoadNotFoundExceptionMessage = 'Caminho para carregar {0} não encontrado: {1}' + failedToImportModuleExceptionMessage = 'Falha ao importar módulo: {0}' + endpointNotExistExceptionMessage = "O ponto de extremidade com o protocolo '{0}' e endereço '{1}' ou endereço local '{2}' não existe." + terminatingMessage = 'Terminando...' + noCommandsSuppliedToConvertToRoutesExceptionMessage = 'Nenhum comando fornecido para converter em Rotas.' + invalidTaskTypeExceptionMessage = 'O tipo de tarefa é inválido, esperado [System.Threading.Tasks.Task] ou [hashtable].' + alreadyConnectedToWebSocketExceptionMessage = "Já conectado ao websocket com o nome '{0}'" + crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = 'A verificação de fim de mensagem CRLF é suportada apenas em endpoints TCP.' + testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = "'Test-PodeOAComponentSchema' precisa ser habilitado usando 'Enable-PodeOpenApi -EnableSchemaValidation'" + adModuleNotInstalledExceptionMessage = 'O módulo Active Directory não está instalado.' + cronExpressionInvalidExceptionMessage = 'A expressão Cron deve consistir apenas em 5 partes: {0}' + noSessionToSetOnResponseExceptionMessage = 'Não há sessão disponível para definir na resposta.' + valueOutOfRangeExceptionMessage = "O valor '{0}' para {1} é inválido, deve estar entre {2} e {3}" + loggingMethodAlreadyDefinedExceptionMessage = 'Método de registro já definido: {0}' + noSecretForHmac256ExceptionMessage = 'Nenhum segredo fornecido para o hash HMAC256.' + eolPowerShellWarningMessage = '[AVISO] Pode {0} não foi testado no PowerShell {1}, pois está em EOL.' + runspacePoolFailedToLoadExceptionMessage = '{0} Falha ao carregar RunspacePool.' + noEventRegisteredExceptionMessage = 'Nenhum evento {0} registrado: {1}' + scheduleCannotHaveNegativeLimitExceptionMessage = '[Agenda] {0}: Não pode ter um limite negativo.' + openApiRequestStyleInvalidForParameterExceptionMessage = 'O estilo da solicitação OpenApi não pode ser {0} para um parâmetro {1}.' + openApiDocumentNotCompliantExceptionMessage = 'O documento OpenAPI não está em conformidade.' + taskDoesNotExistExceptionMessage = "A tarefa '{0}' não existe." + scopedVariableNotFoundExceptionMessage = 'Variável de escopo não encontrada: {0}' + sessionsRequiredForCsrfExceptionMessage = 'Sessões são necessárias para usar CSRF, a menos que você queira usar cookies.' + nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 'Um ScriptBlock não vazio é necessário para o método de registro.' + credentialsPassedWildcardForHeadersLiteralExceptionMessage = 'Quando as Credenciais são passadas, o caractere curinga * para os Cabeçalhos será interpretado como uma string literal e não como um caractere curinga.' + podeNotInitializedExceptionMessage = 'Pode não foi inicializado.' + multipleEndpointsForGuiMessage = 'Múltiplos endpoints definidos, apenas o primeiro será usado para a GUI.' + operationIdMustBeUniqueExceptionMessage = 'OperationID: {0} deve ser único.' + invalidJsonJwtExceptionMessage = 'Valor JSON inválido encontrado no JWT' + noAlgorithmInJwtHeaderExceptionMessage = 'Nenhum algoritmo fornecido no Cabeçalho JWT.' + openApiVersionPropertyMandatoryExceptionMessage = 'A propriedade da versão do OpenApi é obrigatória.' + limitValueCannotBeZeroOrLessExceptionMessage = 'O valor limite não pode ser 0 ou inferior para {0}' + timerDoesNotExistExceptionMessage = "O temporizador '{0}' não existe." + openApiGenerationDocumentErrorMessage = 'Erro no documento de geração do OpenAPI:' + routeAlreadyContainsCustomAccessExceptionMessage = "A rota '[{0}] {1}' já contém Acesso Personalizado com o nome '{2}'" + maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 'O número máximo de threads concorrentes do WebSocket não pode ser menor que o mínimo de {0}, mas foi obtido: {1}' + middlewareAlreadyDefinedExceptionMessage = '[Middleware] {0}: Middleware já definido.' + invalidAtomCharacterExceptionMessage = 'Caractere atômico inválido: {0}' + cacheStorageNotFoundForRetrieveExceptionMessage = "Armazenamento em cache com o nome '{0}' não encontrado ao tentar recuperar o item em cache '{1}'." + headerMustHaveNameInEncodingContextExceptionMessage = 'O cabeçalho deve ter um nome quando usado em um contexto de codificação.' + moduleDoesNotContainFunctionExceptionMessage = 'O módulo {0} não contém a função {1} para converter em uma Rota.' + pathToIconForGuiDoesNotExistExceptionMessage = 'O caminho para o ícone da interface gráfica não existe: {0}' + noTitleSuppliedForPageExceptionMessage = 'Nenhum título fornecido para a página {0}.' + certificateSuppliedForNonHttpsWssEndpointExceptionMessage = 'Certificado fornecido para endpoint que não é HTTPS/WSS.' + cannotLockNullObjectExceptionMessage = 'Não é possível bloquear um objeto nulo.' + showPodeGuiOnlyAvailableOnWindowsExceptionMessage = 'Show-PodeGui está atualmente disponível apenas para Windows PowerShell e PowerShell 7+ no Windows.' + unlockSecretButNoScriptBlockExceptionMessage = 'Segredo de desbloqueio fornecido para tipo de Cofre Secreto personalizado, mas nenhum ScriptBlock de desbloqueio fornecido.' + invalidIpAddressExceptionMessage = 'O endereço IP fornecido é inválido: {0}' + maxDaysInvalidExceptionMessage = 'MaxDays deve ser igual ou maior que 0, mas foi obtido: {0}' + noRemoveScriptBlockForVaultExceptionMessage = "Nenhum ScriptBlock fornecido para remover segredos do cofre '{0}'" + noSecretExpectedForNoSignatureExceptionMessage = 'Não era esperado nenhum segredo para nenhuma assinatura.' + noCertificateFoundExceptionMessage = "Nenhum certificado encontrado em {0}{1} para '{2}'" + minValueInvalidExceptionMessage = "O valor mínimo '{0}' para {1} é inválido, deve ser maior ou igual a {2}" + accessRequiresAuthenticationOnRoutesExceptionMessage = 'O acesso requer autenticação nas rotas.' + noSecretForHmac384ExceptionMessage = 'Nenhum segredo fornecido para o hash HMAC384.' + windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = 'O suporte à Autenticação Local do Windows é apenas para Windows.' + definitionTagNotDefinedExceptionMessage = 'A tag de definição {0} não existe.' + noComponentInDefinitionExceptionMessage = 'Nenhum componente do tipo {0} chamado {1} está disponível na definição {2}.' + noSmtpHandlersDefinedExceptionMessage = 'Nenhum manipulador SMTP definido.' + sessionMiddlewareAlreadyInitializedExceptionMessage = 'O Middleware de Sessão já foi inicializado.' + reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = "O recurso de componente reutilizável 'pathItems' não está disponível no OpenAPI v3.0." + wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 'O caractere curinga * para os Cabeçalhos é incompatível com a chave AutoHeaders.' + noDataForFileUploadedExceptionMessage = "Nenhum dado para o arquivo '{0}' foi enviado na solicitação." + sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = 'SSE só pode ser configurado em solicitações com um valor de cabeçalho Accept de text/event-stream.' + noSessionAvailableToSaveExceptionMessage = 'Não há sessão disponível para salvar.' + pathParameterRequiresRequiredSwitchExceptionMessage = "Se a localização do parâmetro for 'Path', o parâmetro de switch 'Required' é obrigatório." + noOpenApiUrlSuppliedExceptionMessage = 'Nenhuma URL do OpenAPI fornecida para {0}.' + maximumConcurrentSchedulesInvalidExceptionMessage = 'As agendas simultâneas máximas devem ser >=1, mas obtidas: {0}' + snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = 'Os Snapins são suportados apenas no Windows PowerShell.' + eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = 'O registro no Visualizador de Eventos é suportado apenas no Windows.' + parametersMutuallyExclusiveExceptionMessage = "Os parâmetros '{0}' e '{1}' são mutuamente exclusivos." + pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 'O recurso PathItems não é suportado no OpenAPI v3.0.x' + openApiParameterRequiresNameExceptionMessage = 'O parâmetro OpenApi requer um nome especificado.' + maximumConcurrentTasksLessThanMinimumExceptionMessage = 'O número máximo de tarefas concorrentes não pode ser menor que o mínimo de {0}, mas foi obtido: {1}' + noSemaphoreFoundExceptionMessage = "Nenhum semáforo encontrado chamado '{0}'" + singleValueForIntervalExceptionMessage = 'Você pode fornecer apenas um único valor {0} ao usar intervalos.' + jwtNotYetValidExceptionMessage = 'O JWT ainda não é válido para uso.' + verbAlreadyDefinedForUrlExceptionMessage = '[Verbo] {0}: Já definido para {1}' + noSecretNamedMountedExceptionMessage = "Nenhum Segredo com o nome '{0}' foi montado." + moduleOrVersionNotFoundExceptionMessage = 'Módulo ou versão não encontrada em {0}: {1}@{2}' + noScriptBlockSuppliedExceptionMessage = 'Nenhum ScriptBlock fornecido.' + noSecretVaultRegisteredExceptionMessage = "Nenhum Cofre de Segredos com o nome '{0}' foi registrado." + nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = 'Um nome é necessário para o endpoint se o parâmetro RedirectTo for fornecido.' + openApiLicenseObjectRequiresNameExceptionMessage = "O objeto OpenAPI 'license' requer a propriedade 'name'. Use o parâmetro -LicenseName." + sourcePathDoesNotExistForStaticRouteExceptionMessage = '[{0})] {1}: O caminho de origem fornecido para a Rota Estática não existe: {2}' + noNameForWebSocketDisconnectExceptionMessage = 'Nenhum nome fornecido para desconectar do WebSocket.' + certificateExpiredExceptionMessage = "O certificado '{0}' expirou: {1}" + secretVaultUnlockExpiryDateInPastExceptionMessage = 'A data de expiração de desbloqueio do Cofre de Segredos está no passado (UTC): {0}' + invalidExceptionTypeExceptionMessage = 'A exceção é de um tipo inválido, deve ser WebException ou HttpRequestException, mas foi obtido: {0}' + invalidSecretValueTypeExceptionMessage = 'O valor do segredo é de um tipo inválido. Tipos esperados: String, SecureString, HashTable, Byte[] ou PSCredential. Mas obtido: {0}' + explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 'O modo TLS explícito é suportado apenas em endpoints SMTPS e TCPS.' + discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = "O parâmetro 'DiscriminatorMapping' só pode ser usado quando 'DiscriminatorProperty' está presente." + scriptErrorExceptionMessage = "Erro '{0}' no script {1} {2} (linha {3}) caractere {4} executando {5} em {6} objeto '{7}' Classe: {8} ClasseBase: {9}" + cannotSupplyIntervalForQuarterExceptionMessage = 'Não é possível fornecer um valor de intervalo para cada trimestre.' + scheduleEndTimeMustBeInFutureExceptionMessage = '[Agenda] {0}: O valor de EndTime deve estar no futuro.' + invalidJwtSignatureSuppliedExceptionMessage = 'Assinatura JWT fornecida inválida.' + noSetScriptBlockForVaultExceptionMessage = "Nenhum ScriptBlock fornecido para atualizar/criar segredos no cofre '{0}'" + accessMethodNotExistForMergingExceptionMessage = 'O método de acesso não existe para a mesclagem: {0}' + defaultAuthNotInListExceptionMessage = "A Autenticação Default '{0}' não está na lista de Autenticação fornecida." + parameterHasNoNameExceptionMessage = "O parâmetro não tem nome. Dê um nome a este componente usando o parâmetro 'Name'." + methodPathAlreadyDefinedForUrlExceptionMessage = '[{0}] {1}: Já definido para {2}' + fileWatcherAlreadyDefinedExceptionMessage = "Um Observador de Arquivos chamado '{0}' já foi definido." + noServiceHandlersDefinedExceptionMessage = 'Nenhum manipulador de serviço definido.' + secretRequiredForCustomSessionStorageExceptionMessage = 'Um segredo é necessário ao usar armazenamento de sessão personalizado.' + secretManagementModuleNotInstalledExceptionMessage = 'O módulo Microsoft.PowerShell.SecretManagement não está instalado.' + noPathSuppliedForRouteExceptionMessage = 'Nenhum caminho fornecido para a Rota.' + validationOfAnyOfSchemaNotSupportedExceptionMessage = "A validação de um esquema que inclui 'anyof' não é suportada." + iisAuthSupportIsForWindowsOnlyExceptionMessage = 'O suporte à Autenticação IIS é apenas para Windows.' + oauth2InnerSchemeInvalidExceptionMessage = 'O OAuth2 InnerScheme só pode ser um de autenticação Basic ou Form, mas foi obtido: {0}' + noRoutePathSuppliedForPageExceptionMessage = 'Nenhum caminho de rota fornecido para a página {0}.' + cacheStorageNotFoundForExistsExceptionMessage = "Armazenamento em cache com o nome '{0}' não encontrado ao tentar verificar se o item em cache '{1}' existe." + handlerAlreadyDefinedExceptionMessage = '[{0}] {1}: Manipulador já definido.' + sessionsNotConfiguredExceptionMessage = 'As sessões não foram configuradas.' + propertiesTypeObjectAssociationExceptionMessage = 'Apenas propriedades do tipo Objeto podem ser associadas com {0}.' + sessionsRequiredForSessionPersistentAuthExceptionMessage = 'Sessões são necessárias para usar a autenticação persistente por sessão.' + invalidPathWildcardOrDirectoryExceptionMessage = 'O caminho fornecido não pode ser um curinga ou um diretório: {0}' + accessMethodAlreadyDefinedExceptionMessage = 'Método de acesso já definido: {0}' + parametersValueOrExternalValueMandatoryExceptionMessage = "Os parâmetros 'Value' ou 'ExternalValue' são obrigatórios." + maximumConcurrentTasksInvalidExceptionMessage = 'O número máximo de tarefas concorrentes deve ser >=1, mas foi obtido: {0}' + cannotCreatePropertyWithoutTypeExceptionMessage = 'Não é possível criar a propriedade porque nenhum tipo é definido.' + authMethodNotExistForMergingExceptionMessage = 'O método de autenticação não existe para mesclagem: {0}' + maxValueInvalidExceptionMessage = "O valor máximo '{0}' para {1} é inválido, deve ser menor ou igual a {2}" + endpointAlreadyDefinedExceptionMessage = "Um ponto de extremidade chamado '{0}' já foi definido." + eventAlreadyRegisteredExceptionMessage = 'Evento {0} já registrado: {1}' + parameterNotSuppliedInRequestExceptionMessage = "Um parâmetro chamado '{0}' não foi fornecido na solicitação ou não há dados disponíveis." + cacheStorageNotFoundForSetExceptionMessage = "Armazenamento em cache com o nome '{0}' não encontrado ao tentar definir o item em cache '{1}'." + methodPathAlreadyDefinedExceptionMessage = '[{0}] {1}: Já definido.' + errorLoggingAlreadyEnabledExceptionMessage = 'O registro de erros já está habilitado.' + valueForUsingVariableNotFoundExceptionMessage = "Valor para '`$using:{0}' não pôde ser encontrado." + rapidPdfDoesNotSupportOpenApi31ExceptionMessage = 'A ferramenta de documentos RapidPdf não suporta OpenAPI 3.1' + oauth2ClientSecretRequiredExceptionMessage = 'OAuth2 requer um Client Secret quando não se usa PKCE.' + invalidBase64JwtExceptionMessage = 'Valor codificado Base64 inválido encontrado no JWT' + noSessionToCalculateDataHashExceptionMessage = 'Nenhuma sessão disponível para calcular o hash dos dados.' + cacheStorageNotFoundForRemoveExceptionMessage = "Armazenamento em cache com o nome '{0}' não encontrado ao tentar remover o item em cache '{1}'." + csrfMiddlewareNotInitializedExceptionMessage = 'O Middleware CSRF não foi inicializado.' + infoTitleMandatoryMessage = 'info.title é obrigatório.' + typeCanOnlyBeAssociatedWithObjectExceptionMessage = 'O tipo {0} só pode ser associado a um Objeto.' + userFileDoesNotExistExceptionMessage = 'O arquivo do usuário não existe: {0}' + routeParameterNeedsValidScriptblockExceptionMessage = 'O parâmetro da Rota precisa de um ScriptBlock válido e não vazio.' + nextTriggerCalculationErrorExceptionMessage = 'Parece que algo deu errado ao tentar calcular a próxima data e hora do gatilho: {0}' + cannotLockValueTypeExceptionMessage = 'Não é possível bloquear um [ValueTypes].' + failedToCreateOpenSslCertExceptionMessage = 'Falha ao criar o certificado openssl: {0}' + jwtExpiredExceptionMessage = 'O JWT expirou.' + openingGuiMessage = 'Abrindo a GUI.' + multiTypePropertiesRequireOpenApi31ExceptionMessage = 'Propriedades de múltiplos tipos requerem a versão 3.1 ou superior do OpenApi.' + noNameForWebSocketRemoveExceptionMessage = 'Nenhum nome fornecido para remover o WebSocket.' + maxSizeInvalidExceptionMessage = 'MaxSize deve ser igual ou maior que 0, mas foi obtido: {0}' + iisShutdownMessage = '(Desligamento do IIS)' + cannotUnlockValueTypeExceptionMessage = 'Não é possível desbloquear um [ValueTypes].' + noJwtSignatureForAlgorithmExceptionMessage = 'Nenhuma assinatura JWT fornecida para {0}.' + maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 'O número máximo de threads concorrentes do WebSocket deve ser >=1, mas foi obtido: {0}' + acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 'A mensagem de reconhecimento é suportada apenas em endpoints SMTP e TCP.' + failedToConnectToUrlExceptionMessage = 'Falha ao conectar ao URL: {0}' + failedToAcquireMutexOwnershipExceptionMessage = 'Falha ao adquirir a propriedade do mutex. Nome do mutex: {0}' + sessionsRequiredForOAuth2WithPKCEExceptionMessage = 'Sessões são necessárias para usar OAuth2 com PKCE' + failedToConnectToWebSocketExceptionMessage = 'Falha ao conectar ao websocket: {0}' + unsupportedObjectExceptionMessage = 'Objeto não suportado' + failedToParseAddressExceptionMessage = "Falha ao analisar '{0}' como um endereço IP/Host:Port válido" + mustBeRunningWithAdminPrivilegesExceptionMessage = 'Deve estar sendo executado com privilégios de administrador para escutar endereços que não sejam localhost.' + specificationMessage = 'Especificação' + cacheStorageNotFoundForClearExceptionMessage = "Armazenamento em cache com o nome '{0}' não encontrado ao tentar limpar o cache." + restartingServerMessage = 'Reiniciando o servidor...' + cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = "Não é possível fornecer um intervalo quando o parâmetro 'Every' está definido como None." + unsupportedJwtAlgorithmExceptionMessage = 'O algoritmo JWT não é atualmente suportado: {0}' + websocketsNotConfiguredForSignalMessagesExceptionMessage = 'WebSockets não estão configurados para enviar mensagens de sinal.' + invalidLogicTypeInHashtableMiddlewareExceptionMessage = 'Um Middleware do tipo Hashtable fornecido tem um tipo de lógica inválido. Esperado ScriptBlock, mas obtido: {0}' + maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 'As agendas simultâneas máximas não podem ser inferiores ao mínimo de {0}, mas obtidas: {1}' + failedToAcquireSemaphoreOwnershipExceptionMessage = 'Falha ao adquirir a propriedade do semáforo. Nome do semáforo: {0}' + propertiesParameterWithoutNameExceptionMessage = 'Os parâmetros Properties não podem ser usados se a propriedade não tiver um nome.' + customSessionStorageMethodNotImplementedExceptionMessage = "O armazenamento de sessão personalizado não implementa o método requerido '{0}()'." + authenticationMethodDoesNotExistExceptionMessage = 'O método de autenticação não existe: {0}' + webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = 'O recurso Webhooks não é suportado no OpenAPI v3.0.x' + invalidContentTypeForSchemaExceptionMessage = "'content-type' inválido encontrado para o esquema: {0}" + noUnlockScriptBlockForVaultExceptionMessage = "Nenhum ScriptBlock de desbloqueio fornecido para desbloquear o cofre '{0}'" + definitionTagMessage = 'Definição {0}:' + failedToOpenRunspacePoolExceptionMessage = 'Falha ao abrir o RunspacePool: {0}' + verbNoLogicPassedExceptionMessage = '[Verbo] {0}: Nenhuma lógica passada' + noMutexFoundExceptionMessage = "Nenhum mutex encontrado chamado '{0}'" + documentationMessage = 'Documentação' + timerAlreadyDefinedExceptionMessage = '[Temporizador] {0}: Temporizador já definido.' + invalidPortExceptionMessage = 'A porta não pode ser negativa: {0}' + viewsFolderNameAlreadyExistsExceptionMessage = 'O nome da pasta Views já existe: {0}' + noNameForWebSocketResetExceptionMessage = 'Nenhum nome fornecido para redefinir o WebSocket.' + mergeDefaultAuthNotInListExceptionMessage = "A Autenticação MergeDefault '{0}' não está na lista de Autenticação fornecida." + descriptionRequiredExceptionMessage = 'É necessária uma descrição.' + pageNameShouldBeAlphaNumericExceptionMessage = 'O nome da página deve ser um valor alfanumérico válido: {0}' + defaultValueNotBooleanOrEnumExceptionMessage = 'O valor padrão não é booleano e não faz parte do enum.' + openApiComponentSchemaDoesNotExistExceptionMessage = 'O esquema do componente OpenApi {0} não existe.' + timerParameterMustBeGreaterThanZeroExceptionMessage = '[Temporizador] {0}: {1} deve ser maior que 0.' + taskTimedOutExceptionMessage = 'A tarefa expirou após {0}ms.' + scheduleStartTimeAfterEndTimeExceptionMessage = "[Agenda] {0}: Não pode ter um 'StartTime' após o 'EndTime'" + infoVersionMandatoryMessage = 'info.version é obrigatório.' + cannotUnlockNullObjectExceptionMessage = 'Não é possível desbloquear um objeto nulo.' + nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 'É necessário um ScriptBlock não vazio para o esquema de autenticação personalizado.' + validationOfOneOfSchemaNotSupportedExceptionMessage = "A validação de um esquema que inclui 'oneof' não é suportada." + routeParameterCannotBeNullExceptionMessage = "O parâmetro 'Route' não pode ser nulo." + cacheStorageAlreadyExistsExceptionMessage = "Armazenamento em cache com o nome '{0}' já existe." + loggingMethodRequiresValidScriptBlockExceptionMessage = "O método de saída fornecido para o método de registro '{0}' requer um ScriptBlock válido." + scopedVariableAlreadyDefinedExceptionMessage = 'Variável de escopo já definida: {0}' + oauth2RequiresAuthorizeUrlExceptionMessage = 'OAuth2 requer que seja fornecida uma URL de Autorização' + pathNotExistExceptionMessage = 'O caminho não existe: {0}' + noDomainServerNameForWindowsAdAuthExceptionMessage = 'Nenhum nome de servidor de domínio foi fornecido para a autenticação AD do Windows' + suppliedDateAfterScheduleEndTimeExceptionMessage = 'A data fornecida é posterior ao horário de término da agenda em {0}' + wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 'O caractere curinga * para os Métodos é incompatível com a chave AutoMethods.' + cannotSupplyIntervalForYearExceptionMessage = 'Não é possível fornecer um valor de intervalo para cada ano.' + missingComponentsMessage = 'Componente(s) ausente(s)' + invalidStrictTransportSecurityDurationExceptionMessage = 'Duração inválida fornecida para Strict-Transport-Security: {0}. Deve ser maior que 0.' + noSecretForHmac512ExceptionMessage = 'Nenhum segredo fornecido para o hash HMAC512.' + daysInMonthExceededExceptionMessage = '{0} tem apenas {1} dias, mas {2} foi fornecido.' + nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 'Um ScriptBlock não vazio é necessário para o método de registro personalizado.' + encodingAttributeOnlyAppliesToMultipartExceptionMessage = 'O atributo de codificação só se aplica a corpos de solicitação multipart e application/x-www-form-urlencoded.' + suppliedDateBeforeScheduleStartTimeExceptionMessage = 'A data fornecida é anterior ao horário de início da agenda em {0}' + unlockSecretRequiredExceptionMessage = "É necessária uma propriedade 'UnlockSecret' ao usar Microsoft.PowerShell.SecretStore" + noLogicPassedForMethodRouteExceptionMessage = '[{0}] {1}: Nenhuma lógica passada.' + bodyParserAlreadyDefinedForContentTypeExceptionMessage = 'Um body-parser já está definido para o tipo de conteúdo {0}.' + invalidJwtSuppliedExceptionMessage = 'JWT fornecido inválido.' + sessionsRequiredForFlashMessagesExceptionMessage = 'Sessões são necessárias para usar mensagens Flash.' + outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = 'O método de saída fornecido para o registro de solicitações requer um ScriptBlock válido.' + semaphoreAlreadyExistsExceptionMessage = 'Já existe um semáforo com o seguinte nome: {0}' + invalidJwtHeaderAlgorithmSuppliedExceptionMessage = 'Algoritmo de cabeçalho JWT fornecido inválido.' + oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = "O provedor OAuth2 não suporta o grant_type 'password' necessário ao usar um InnerScheme." + invalidAliasFoundExceptionMessage = 'Alias {0} inválido encontrado: {1}' + scheduleDoesNotExistExceptionMessage = "A agenda '{0}' não existe." + accessMethodNotExistExceptionMessage = 'O método de acesso não existe: {0}' + oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = "O provedor OAuth2 não suporta o response_type 'code'." + untestedPowerShellVersionWarningMessage = '[AVISO] Pode {0} não foi testado no PowerShell {1}, pois não estava disponível quando o Pode foi lançado.' + secretVaultAlreadyRegisteredAutoImportExceptionMessage = "Um Cofre de Segredos com o nome '{0}' já foi registrado durante a importação automática de Cofres de Segredos." + schemeRequiresValidScriptBlockExceptionMessage = "O esquema fornecido para o validador de autenticação '{0}' requer um ScriptBlock válido." + serverLoopingMessage = 'Looping do servidor a cada {0} segundos' + certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 'Impressões digitais/nome do certificado são suportados apenas no Windows.' + sseConnectionNameRequiredExceptionMessage = "Um nome de conexão SSE é necessário, seja de -Name ou `$WebEvent.Sse.Name." + invalidMiddlewareTypeExceptionMessage = 'Um dos Middlewares fornecidos é de um tipo inválido. Esperado ScriptBlock ou Hashtable, mas obtido: {0}' + noSecretForJwtSignatureExceptionMessage = 'Nenhum segredo fornecido para a assinatura JWT.' + modulePathDoesNotExistExceptionMessage = 'O caminho do módulo não existe: {0}' + taskAlreadyDefinedExceptionMessage = '[Tarefa] {0}: Tarefa já definida.' + verbAlreadyDefinedExceptionMessage = '[Verbo] {0}: Já definido' + clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 'Certificados de cliente são suportados apenas em endpoints HTTPS.' + endpointNameNotExistExceptionMessage = "O ponto de extremidade com o nome '{0}' não existe." + middlewareNoLogicSuppliedExceptionMessage = '[Middleware]: Nenhuma lógica fornecida no ScriptBlock.' + scriptBlockRequiredForMergingUsersExceptionMessage = 'É necessário um ScriptBlock para mesclar vários usuários autenticados em 1 objeto quando Valid é All.' + secretVaultAlreadyRegisteredExceptionMessage = "Um Cofre de Segredos com o nome '{0}' já foi registrado{1}." + deprecatedTitleVersionDescriptionWarningMessage = "AVISO: Título, Versão e Descrição em 'Enable-PodeOpenApi' estão obsoletos. Utilize 'Add-PodeOAInfo' em vez disso." + undefinedOpenApiReferencesMessage = 'Referências OpenAPI indefinidas:' + doneMessage = 'Concluído' + swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = 'Esta versão do Swagger-Editor não suporta OpenAPI 3.1' + durationMustBeZeroOrGreaterExceptionMessage = 'A duração deve ser 0 ou maior, mas foi obtido: {0}s' + viewsPathDoesNotExistExceptionMessage = 'O caminho das Views não existe: {0}' + discriminatorIncompatibleWithAllOfExceptionMessage = "O parâmetro 'Discriminator' é incompatível com 'allOf'." + noNameForWebSocketSendMessageExceptionMessage = 'Nenhum nome fornecido para enviar mensagem ao WebSocket.' + hashtableMiddlewareNoLogicExceptionMessage = 'Um Middleware do tipo Hashtable fornecido não tem lógica definida.' + openApiInfoMessage = 'Informações OpenAPI:' + invalidSchemeForAuthValidatorExceptionMessage = "O esquema '{0}' fornecido para o validador de autenticação '{1}' requer um ScriptBlock válido." + sseFailedToBroadcastExceptionMessage = 'SSE falhou em transmitir devido ao nível de transmissão SSE definido para {0}: {1}.' + adModuleWindowsOnlyExceptionMessage = 'O módulo Active Directory está disponível apenas no Windows.' + requestLoggingAlreadyEnabledExceptionMessage = 'O registro de solicitações já está habilitado.' + invalidAccessControlMaxAgeDurationExceptionMessage = 'Duração inválida fornecida para Access-Control-Max-Age: {0}. Deve ser maior que 0.' +} + diff --git a/src/Locales/zn/Pode.psd1 b/src/Locales/zn/Pode.psd1 index 77cc0d6aa..0d90180bb 100644 --- a/src/Locales/zn/Pode.psd1 +++ b/src/Locales/zn/Pode.psd1 @@ -1,284 +1,285 @@ -ConvertFrom-StringData -StringData @' -adModuleWindowsOnlyExceptionMessage = 仅支持 Windows 的 Active Directory 模块。 -adModuleNotInstalledExceptionMessage = 未安装 Active Directory 模块。 -secretManagementModuleNotInstalledExceptionMessage = 未安装 Microsoft.PowerShell.SecretManagement 模块。 -secretVaultAlreadyRegisteredAutoImportExceptionMessage = 已经注册了名称为 '{0}' 的秘密保险库,同时正在自动导入秘密保险库。 -failedToOpenRunspacePoolExceptionMessage = 打开 RunspacePool 失败: {0} -cronExpressionInvalidExceptionMessage = Cron 表达式应仅包含 5 个部分: {0} -invalidAliasFoundExceptionMessage = 找到了无效的 {0} 别名: {1} -invalidAtomCharacterExceptionMessage = 无效的原子字符: {0} -minValueGreaterThanMaxExceptionMessage = {0} 的最小值不应大于最大值。 -minValueInvalidExceptionMessage = {1} 的最小值 '{0}' 无效,应大于或等于 {2} -maxValueInvalidExceptionMessage = {1} 的最大值 '{0}' 无效,应小于或等于 {2} -valueOutOfRangeExceptionMessage = {1} 的值 '{0}' 无效,应在 {2} 和 {3} 之间 -daysInMonthExceededExceptionMessage = {0} 仅有 {1} 天,但提供了 {2} 天。 -nextTriggerCalculationErrorExceptionMessage = 似乎在尝试计算下一个触发器日期时间时出现了问题: {0} -incompatiblePodeDllExceptionMessage = 已加载存在不兼容的 Pode.DLL 版本 {0}。需要版本 {1}。请打开新的 Powershell/pwsh 会话并重试。 -endpointNotExistExceptionMessage = 具有协议 '{0}' 和地址 '{1}' 或本地地址 '{2}' 的端点不存在。 -endpointNameNotExistExceptionMessage = 名为 '{0}' 的端点不存在。 -failedToConnectToUrlExceptionMessage = 连接到 URL 失败: {0} -failedToParseAddressExceptionMessage = 无法将 '{0}' 解析为有效的 IP/主机:端口地址 -invalidIpAddressExceptionMessage = 提供的 IP 地址无效: {0} -invalidPortExceptionMessage = 端口不能为负数: {0} -pathNotExistExceptionMessage = 路径不存在: {0} -noSecretForHmac256ExceptionMessage = 未提供 HMAC256 哈希的密钥。 -noSecretForHmac384ExceptionMessage = 未提供 HMAC384 哈希的密钥。 -noSecretForHmac512ExceptionMessage = 未提供 HMAC512 哈希的密钥。 -noSecretForJwtSignatureExceptionMessage = 未提供 JWT 签名的密钥。 -noSecretExpectedForNoSignatureExceptionMessage = 预期未提供签名的密钥。 -unsupportedJwtAlgorithmExceptionMessage = 当前不支持的 JWT 算法: {0} -invalidBase64JwtExceptionMessage = 在 JWT 中找到无效的 Base64 编码值 -invalidJsonJwtExceptionMessage = 在 JWT 中找到无效的 JSON 值 -unsupportedFunctionInServerlessContextExceptionMessage = 不支持在无服务器上下文中使用 {0} 函数。 -invalidPathWildcardOrDirectoryExceptionMessage = 提供的路径不能是通配符或目录: {0} -invalidExceptionTypeExceptionMessage = 异常类型无效,应为 WebException 或 HttpRequestException, 但得到了: {0} -pathToLoadNotFoundExceptionMessage = 未找到要加载的路径 {0}: {1} -singleValueForIntervalExceptionMessage = 当使用间隔时,只能提供单个 {0} 值。 -scriptErrorExceptionMessage = 脚本 '{0}' 在 {1} {2} (第 {3} 行) 第 {4} 个字符处执行 {5} 对象 '{7}' 的错误。类: {8} 基类: {9} -noScriptBlockSuppliedExceptionMessage = 未提供脚本块。 -iisAspnetcoreTokenMissingExceptionMessage = 缺少 IIS ASPNETCORE_TOKEN。 -propertiesParameterWithoutNameExceptionMessage = 如果属性没有名称,则不能使用 Properties 参数。 -multiTypePropertiesRequireOpenApi31ExceptionMessage = 多类型属性需要 OpenApi 版本 3.1 或更高版本。 -openApiVersionPropertyMandatoryExceptionMessage = OpenApi 版本属性是必需的。 -webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = 在 OpenAPI v3.0.x 中不支持 Webhooks 功能 -authenticationMethodDoesNotExistExceptionMessage = 认证方法不存在: {0} -unsupportedObjectExceptionMessage = 不支持的对象 -validationOfAnyOfSchemaNotSupportedExceptionMessage = 不支持包含 'anyof' 的模式的验证。 -validationOfOneOfSchemaNotSupportedExceptionMessage = 不支持包含 'oneof' 的模式的验证。 -cannotCreatePropertyWithoutTypeExceptionMessage = 无法创建属性,因为未定义类型。 -headerMustHaveNameInEncodingContextExceptionMessage = 在编码上下文中使用时,标头必须有名称。 -descriptionRequiredExceptionMessage = 描述是必需的。 -openApiDocumentNotCompliantExceptionMessage = OpenAPI 文档不符合规范。 -noComponentInDefinitionExceptionMessage = 定义中没有类型为 {0} 名称为 {1} 的组件。 -methodPathAlreadyDefinedExceptionMessage = [{0}] {1}: 已经定义。 -methodPathAlreadyDefinedForUrlExceptionMessage = [{0}] {1}: 已经为 {2} 定义。 -invalidMiddlewareTypeExceptionMessage = 提供的中间件之一是无效的类型。期望是 ScriptBlock 或 Hashtable, 但得到了: {0} -hashtableMiddlewareNoLogicExceptionMessage = 提供的 Hashtable 中间件没有定义逻辑。 -invalidLogicTypeInHashtableMiddlewareExceptionMessage = 提供的 Hashtable 中间件具有无效的逻辑类型。期望是 ScriptBlockm, 但得到了: {0} -scopedVariableAlreadyDefinedExceptionMessage = 已经定义了作用域变量: {0} -valueForUsingVariableNotFoundExceptionMessage = 未找到 '`$using:{0}' 的值。 -unlockSecretRequiredExceptionMessage = 使用 Microsoft.PowerShell.SecretStore 时需要 'UnlockSecret' 属性。 -unlockSecretButNoScriptBlockExceptionMessage = 为自定义秘密保险库类型提供了解锁密钥,但未提供解锁 ScriptBlock。 -noUnlockScriptBlockForVaultExceptionMessage = 未为解锁保险库 '{0}' 提供解锁 ScriptBlock。 -noSetScriptBlockForVaultExceptionMessage = 未为更新/创建保险库 '{0}' 中的秘密提供设置 ScriptBlock。 -noRemoveScriptBlockForVaultExceptionMessage = 未为从保险库 '{0}' 中删除秘密提供删除 ScriptBlock。 -invalidSecretValueTypeExceptionMessage = 密钥值是无效的类型。期望类型: 字符串、SecureString、HashTable、Byte[] 或 PSCredential。但得到了: {0} -limitValueCannotBeZeroOrLessExceptionMessage = {0} 的限制值不能为 0 或更小。 -secondsValueCannotBeZeroOrLessExceptionMessage = {0} 的秒数值不能为 0 或更小。 -failedToCreateOpenSslCertExceptionMessage = 创建 openssl 证书失败: {0} -certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 证书指纹/名称仅在 Windows 上受支持。 -noCertificateFoundExceptionMessage = 在 {0}\{1} 中找不到证书 '{2}'。 -runspacePoolFailedToLoadExceptionMessage = {0} RunspacePool 加载失败。 -noServiceHandlersDefinedExceptionMessage = 未定义服务处理程序。 -noSessionToSetOnResponseExceptionMessage = 没有可用的会话来设置响应。 -noSessionToCalculateDataHashExceptionMessage = 没有可用的会话来计算数据哈希。 -moduleOrVersionNotFoundExceptionMessage = 在 {0} 上找不到模块或版本: {1}@{2} -noSmtpHandlersDefinedExceptionMessage = 未定义 SMTP 处理程序。 -taskTimedOutExceptionMessage = 任务在 {0} 毫秒后超时。 -verbAlreadyDefinedExceptionMessage = [Verb] {0}: 已经定义 -verbAlreadyDefinedForUrlExceptionMessage = [Verb] {0}: 已经为 {1} 定义 -pathOrScriptBlockRequiredExceptionMessage = 对于源自自定义访问值,需要路径或 ScriptBlock。 -accessMethodAlreadyDefinedExceptionMessage = 访问方法已经定义: {0} -accessMethodNotExistForMergingExceptionMessage = 合并时访问方法不存在: {0} -routeAlreadyContainsCustomAccessExceptionMessage = 路由 '[{0}] {1}' 已经包含名称为 '{2}' 的自定义访问。 -accessMethodNotExistExceptionMessage = 访问方法不存在: {0} -pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 在 OpenAPI v3.0.x 中不支持 PathItems 功能。 -nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 自定义身份验证方案需要一个非空的 ScriptBlock。 -oauth2InnerSchemeInvalidExceptionMessage = OAuth2 InnerScheme 只能是 Basic 或 Form 身份验证,但得到:{0} -sessionsRequiredForOAuth2WithPKCEExceptionMessage = 使用 PKCE 时需要会话来使用 OAuth2 -oauth2ClientSecretRequiredExceptionMessage = 不使用 PKCE 时, OAuth2 需要一个客户端密钥。 -authMethodAlreadyDefinedExceptionMessage = 身份验证方法已定义:{0} -invalidSchemeForAuthValidatorExceptionMessage = 提供的 '{0}' 方案用于 '{1}' 身份验证验证器,需要一个有效的 ScriptBlock。 -sessionsRequiredForSessionPersistentAuthExceptionMessage = 使用会话持久性身份验证需要会话。 -oauth2RequiresAuthorizeUrlExceptionMessage = OAuth2 需要提供授权 URL -authMethodNotExistForMergingExceptionMessage = 合并时身份验证方法不存在:{0} -mergeDefaultAuthNotInListExceptionMessage = MergeDefault 身份验证 '{0}' 不在提供的身份验证列表中。 -defaultAuthNotInListExceptionMessage = 默认身份验证 '{0}' 不在提供的身份验证列表中。 -scriptBlockRequiredForMergingUsersExceptionMessage = 当 Valid 是 All 时,需要一个 ScriptBlock 来将多个经过身份验证的用户合并为一个对象。 -noDomainServerNameForWindowsAdAuthExceptionMessage = 没有为 Windows AD 身份验证提供域服务器名称 -sessionsNotConfiguredExceptionMessage = 会话尚未配置。 -windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = Windows 本地身份验证支持仅适用于 Windows。 -iisAuthSupportIsForWindowsOnlyExceptionMessage = IIS 身份验证支持仅适用于 Windows。 -noAlgorithmInJwtHeaderExceptionMessage = JWT 头中未提供算法。 -invalidJwtSuppliedExceptionMessage = 提供的 JWT 无效。 -invalidJwtHeaderAlgorithmSuppliedExceptionMessage = 提供的 JWT 头算法无效。 -noJwtSignatureForAlgorithmExceptionMessage = 没有为 {0} 提供 JWT 签名。 -expectedNoJwtSignatureSuppliedExceptionMessage = 预期不提供 JWT 签名。 -invalidJwtSignatureSuppliedExceptionMessage = 提供的 JWT 签名无效。 -jwtExpiredExceptionMessage = JWT 已过期。 -jwtNotYetValidExceptionMessage = JWT 尚未有效。 -snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = Snapins 仅支持 Windows PowerShell。 -userFileDoesNotExistExceptionMessage = 用户文件不存在:{0} -schemeRequiresValidScriptBlockExceptionMessage = 提供的方案用于 '{0}' 身份验证验证器,需要一个有效的 ScriptBlock。 -oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = OAuth2 提供程序不支持 'code' response_type。 -oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = OAuth2 提供程序不支持使用 InnerScheme 所需的 'password' grant_type。 -eventAlreadyRegisteredExceptionMessage = {0} 事件已注册:{1} -noEventRegisteredExceptionMessage = 没有注册的 {0} 事件:{1} -sessionsRequiredForFlashMessagesExceptionMessage = 使用闪存消息需要会话。 -eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = 事件查看器日志记录仅支持Windows。 -nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 自定义日志输出方法需要非空的ScriptBlock。 -requestLoggingAlreadyEnabledExceptionMessage = 请求日志记录已启用。 -outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = 请求日志记录提供的输出方法需要有效的ScriptBlock。 -errorLoggingAlreadyEnabledExceptionMessage = 错误日志记录已启用。 -nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 日志记录方法需要非空的ScriptBlock。 -csrfMiddlewareNotInitializedExceptionMessage = CSRF中间件未初始化。 -sessionsRequiredForCsrfExceptionMessage = 使用CSRF需要会话, 除非您想使用Cookie。 -middlewareNoLogicSuppliedExceptionMessage = [中间件]: ScriptBlock中未提供逻辑。 -parameterHasNoNameExceptionMessage = 参数没有名称。请使用'Name'参数为此组件命名。 -reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = OpenAPI v3.0中不支持可重用组件功能'pathItems'。 -noPropertiesMutuallyExclusiveExceptionMessage = 参数'NoProperties'与'Properties'、'MinProperties'和'MaxProperties'互斥。 -discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = 参数'DiscriminatorMapping'只能在存在'DiscriminatorProperty'时使用。 -discriminatorIncompatibleWithAllOfExceptionMessage = 参数'Discriminator'与'allOf'不兼容。 -typeCanOnlyBeAssociatedWithObjectExceptionMessage = 类型{0}只能与对象关联。 -showPodeGuiOnlyAvailableOnWindowsExceptionMessage = Show-PodeGui目前仅适用于Windows PowerShell和Windows上的PowerShell 7+。 -nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = 如果提供了RedirectTo参数, 则需要为端点指定名称。 -clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 客户端证书仅支持HTTPS端点。 -explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 显式TLS模式仅支持SMTPS和TCPS端点。 -acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 确认消息仅支持SMTP和TCP端点。 -crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = CRLF消息结束检查仅支持TCP端点。 -mustBeRunningWithAdminPrivilegesExceptionMessage = 必须以管理员权限运行才能监听非本地主机地址。 -certificateSuppliedForNonHttpsWssEndpointExceptionMessage = 为非HTTPS/WSS端点提供的证书。 -websocketsNotConfiguredForSignalMessagesExceptionMessage = WebSockets未配置为发送信号消息。 -noPathSuppliedForRouteExceptionMessage = 未为路由提供路径。 -accessRequiresAuthenticationOnRoutesExceptionMessage = 访问需要在路由上进行身份验证。 -accessMethodDoesNotExistExceptionMessage = 访问方法不存在:{0}。 -routeParameterNeedsValidScriptblockExceptionMessage = 路由参数需要有效且非空的ScriptBlock。 -noCommandsSuppliedToConvertToRoutesExceptionMessage = 未提供要转换为路由的命令。 -nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 创建页面路由需要非空的ScriptBlock。 -sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = SSE只能在Accept标头值为text/event-stream的请求上配置。 -sseConnectionNameRequiredExceptionMessage = 需要SSE连接名称, 可以从-Name或`$WebEvent.Sse.Name获取。 -sseFailedToBroadcastExceptionMessage = 由于为{0}定义的SSE广播级别, SSE广播失败: {1} -podeNotInitializedExceptionMessage = Pode未初始化。 -invalidTaskTypeExceptionMessage = 任务类型无效,预期类型为[System.Threading.Tasks.Task]或[hashtable]。 -cannotLockValueTypeExceptionMessage = 无法锁定[ValueTypes]。 -cannotLockNullObjectExceptionMessage = 无法锁定空对象。 -failedToAcquireLockExceptionMessage = 未能获取对象的锁。 -cannotUnlockValueTypeExceptionMessage = 无法解锁[ValueTypes]。 -cannotUnlockNullObjectExceptionMessage = 无法解锁空对象。 -sessionMiddlewareAlreadyInitializedExceptionMessage = 会话中间件已初始化。 -customSessionStorageMethodNotImplementedExceptionMessage = 自定义会话存储未实现所需的方法'{0}()'。 -secretRequiredForCustomSessionStorageExceptionMessage = 使用自定义会话存储时需要一个密钥。 -noSessionAvailableToSaveExceptionMessage = 没有可保存的会话。 -cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = 当参数'Every'设置为None时, 无法提供间隔。 -cannotSupplyIntervalForQuarterExceptionMessage = 无法为每季度提供间隔值。 -cannotSupplyIntervalForYearExceptionMessage = 无法为每年提供间隔值。 -secretVaultAlreadyRegisteredExceptionMessage = 名为“{0}”的秘密保险库已注册{1}。 -secretVaultUnlockExpiryDateInPastExceptionMessage = 秘密保险库的解锁到期日期已过 (UTC) :{0} -secretAlreadyMountedExceptionMessage = 名为“{0}”的秘密已挂载。 -credentialsPassedWildcardForHeadersLiteralExceptionMessage = 传递凭据时,标头的通配符 * 将被视为文字字符串,而不是通配符。 -wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 标头的通配符 * 与 AutoHeaders 开关不兼容。 -wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 方法的通配符 * 与 AutoMethods 开关不兼容。 -invalidAccessControlMaxAgeDurationExceptionMessage = 提供的 Access-Control-Max-Age 时长无效:{0}。应大于 0。 -noNameForWebSocketDisconnectExceptionMessage = 没有提供断开连接的 WebSocket 的名称。 -noNameForWebSocketRemoveExceptionMessage = 没有提供要删除的 WebSocket 的名称。 -noNameForWebSocketSendMessageExceptionMessage = 没有提供要发送消息的 WebSocket 的名称。 -noSecretNamedMountedExceptionMessage = 没有挂载名为“{0}”的秘密。 -noNameForWebSocketResetExceptionMessage = 没有提供要重置的 WebSocket 的名称。 -schemaValidationRequiresPowerShell610ExceptionMessage = 架构验证需要 PowerShell 版本 6.1.0 或更高版本。 -routeParameterCannotBeNullExceptionMessage = 参数 'Route' 不能为空。 -encodingAttributeOnlyAppliesToMultipartExceptionMessage = 编码属性仅适用于 multipart 和 application/x-www-form-urlencoded 请求体。 -testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = 必须使用 'Enable-PodeOpenApi -EnableSchemaValidation' 启用 'Test-PodeOAComponentSchema'。 -openApiComponentSchemaDoesNotExistExceptionMessage = OpenApi 组件架构 {0} 不存在。 -openApiParameterRequiresNameExceptionMessage = OpenApi 参数需要指定名称。 -openApiLicenseObjectRequiresNameExceptionMessage = OpenAPI 对象 'license' 需要属性 'name'。请使用 -LicenseName 参数。 -parametersValueOrExternalValueMandatoryExceptionMessage = 参数 'Value' 或 'ExternalValue' 是必需的。 -parametersMutuallyExclusiveExceptionMessage = 参数 '{0}' 和 '{1}' 是互斥的。 -maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 最大并发 WebSocket 线程数必须 >=1, 但获得: {0} -maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 最大并发 WebSocket 线程数不能小于最小值 {0},但获得: {1} -alreadyConnectedToWebSocketExceptionMessage = 已连接到名为 '{0}' 的 WebSocket -failedToConnectToWebSocketExceptionMessage = 连接到 WebSocket 失败: {0} -verbNoLogicPassedExceptionMessage = [动词] {0}: 未传递逻辑 -scriptPathDoesNotExistExceptionMessage = 脚本路径不存在: {0} -failedToImportModuleExceptionMessage = 导入模块失败: {0} -modulePathDoesNotExistExceptionMessage = 模块路径不存在: {0} -defaultValueNotBooleanOrEnumExceptionMessage = 默认值不是布尔值且不属于枚举。 -propertiesTypeObjectAssociationExceptionMessage = 只有 Object 类型的属性可以与 {0} 关联。 -invalidContentTypeForSchemaExceptionMessage = 架构中发现无效的 'content-type': {0} -openApiRequestStyleInvalidForParameterExceptionMessage = OpenApi 请求样式不能为 {0},适用于 {1} 参数。 -pathParameterRequiresRequiredSwitchExceptionMessage = 如果参数位置是 'Path',则 'Required' 开关参数是必需的。 -operationIdMustBeUniqueForArrayExceptionMessage = 操作ID: {0} 必须唯一,不能应用于数组。 -operationIdMustBeUniqueExceptionMessage = 操作ID: {0} 必须唯一。 -noOpenApiUrlSuppliedExceptionMessage = 未提供 {0} 的 OpenAPI URL。 -noTitleSuppliedForPageExceptionMessage = 未提供 {0} 页面的标题。 -noRoutePathSuppliedForPageExceptionMessage = 未提供 {0} 页面的路由路径。 -swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = 此版本的 Swagger-Editor 不支持 OpenAPI 3.1 -rapidPdfDoesNotSupportOpenApi31ExceptionMessage = 文档工具 RapidPdf 不支持 OpenAPI 3.1 -definitionTagNotDefinedExceptionMessage = 定义标签 {0} 未定义。 -scopedVariableNotFoundExceptionMessage = 未找到范围变量: {0} -noSecretVaultRegisteredExceptionMessage = 未注册名为 '{0}' 的秘密保险库。 -invalidStrictTransportSecurityDurationExceptionMessage = 提供的严格传输安全持续时间无效: {0}。应大于 0。 -durationMustBeZeroOrGreaterExceptionMessage = 持续时间必须为 0 或更大,但获得: {0}s -taskAlreadyDefinedExceptionMessage = [任务] {0}: 任务已定义。 -maximumConcurrentTasksInvalidExceptionMessage = 最大并发任务数必须 >=1,但获得: {0} -maximumConcurrentTasksLessThanMinimumExceptionMessage = 最大并发任务数不能小于最小值 {0},但获得: {1} -taskDoesNotExistExceptionMessage = 任务 '{0}' 不存在。 -cacheStorageNotFoundForRetrieveExceptionMessage = 尝试检索缓存项 '{1}' 时,找不到名为 '{0}' 的缓存存储。 -cacheStorageNotFoundForSetExceptionMessage = 尝试设置缓存项 '{1}' 时,找不到名为 '{0}' 的缓存存储。 -cacheStorageNotFoundForExistsExceptionMessage = 尝试检查缓存项 '{1}' 是否存在时,找不到名为 '{0}' 的缓存存储。 -cacheStorageNotFoundForRemoveExceptionMessage = 尝试删除缓存项 '{1}' 时,找不到名为 '{0}' 的缓存存储。 -cacheStorageNotFoundForClearExceptionMessage = 尝试清除缓存时,找不到名为 '{0}' 的缓存存储。 -cacheStorageAlreadyExistsExceptionMessage = 名为 '{0}' 的缓存存储已存在。 -pathToIconForGuiDoesNotExistExceptionMessage = GUI 图标的路径不存在: {0} -invalidHostnameSuppliedExceptionMessage = 提供的主机名无效: {0} -endpointAlreadyDefinedExceptionMessage = 名为 '{0}' 的端点已定义。 -certificateExpiredExceptionMessage = 证书 '{0}' 已过期: {1} -endpointNotDefinedForRedirectingExceptionMessage = 未定义用于重定向的名为 '{0}' 的端点。 -fileWatcherAlreadyDefinedExceptionMessage = 名为 '{0}' 的文件监视器已定义。 -handlerAlreadyDefinedExceptionMessage = [{0}] {1}: 处理程序已定义。 -maxDaysInvalidExceptionMessage = MaxDays 必须大于或等于 0,但得到: {0} -maxSizeInvalidExceptionMessage = MaxSize 必须大于或等于 0,但得到: {0} -loggingMethodAlreadyDefinedExceptionMessage = 日志记录方法已定义: {0} -loggingMethodRequiresValidScriptBlockExceptionMessage = 为 '{0}' 日志记录方法提供的输出方法需要有效的 ScriptBlock。 -csrfCookieRequiresSecretExceptionMessage = 使用 CSRF 的 Cookie 时,需要一个密钥。您可以提供一个密钥或设置全局 Cookie 密钥 - (Set-PodeCookieSecret '' -Global) -bodyParserAlreadyDefinedForContentTypeExceptionMessage = 已为 {0} 内容类型定义了一个 body-parser。 -middlewareAlreadyDefinedExceptionMessage = [Middleware] {0}: 中间件已定义。 -parameterNotSuppliedInRequestExceptionMessage = 请求中未提供名为 '{0}' 的参数或没有可用数据。 -noDataForFileUploadedExceptionMessage = 请求中未上传文件 '{0}' 的数据。 -viewsFolderNameAlreadyExistsExceptionMessage = 视图文件夹名称已存在: {0} -viewsPathDoesNotExistExceptionMessage = 视图路径不存在: {0} -timerAlreadyDefinedExceptionMessage = [计时器] {0}: 计时器已定义。 -timerParameterMustBeGreaterThanZeroExceptionMessage = [计时器] {0}: {1} 必须大于 0。 -timerDoesNotExistExceptionMessage = 计时器 '{0}' 不存在。 -mutexAlreadyExistsExceptionMessage = 名为 '{0}' 的互斥量已存在。 -noMutexFoundExceptionMessage = 找不到名为 '{0}' 的互斥量 -failedToAcquireMutexOwnershipExceptionMessage = 未能获得互斥量的所有权。互斥量名称: {0} -semaphoreAlreadyExistsExceptionMessage = 名为 '{0}' 的信号量已存在。 -failedToAcquireSemaphoreOwnershipExceptionMessage = 未能获得信号量的所有权。信号量名称: {0} -scheduleAlreadyDefinedExceptionMessage = [计划] {0}: 计划已定义。 -scheduleCannotHaveNegativeLimitExceptionMessage = [计划] {0}: 不能有负数限制。 -scheduleEndTimeMustBeInFutureExceptionMessage = [计划] {0}: EndTime 值必须在将来。 -scheduleStartTimeAfterEndTimeExceptionMessage = [计划] {0}: 'StartTime' 不能在 'EndTime' 之后 -maximumConcurrentSchedulesInvalidExceptionMessage = 最大并发计划数必须 >=1,但得到: {0} -maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 最大并发计划数不能小于最小值 {0},但得到: {1} -scheduleDoesNotExistExceptionMessage = 计划 '{0}' 不存在。 -suppliedDateBeforeScheduleStartTimeExceptionMessage = 提供的日期早于计划的开始时间 {0} -suppliedDateAfterScheduleEndTimeExceptionMessage = 提供的日期晚于计划的结束时间 {0} -noSemaphoreFoundExceptionMessage = 找不到名为 '{0}' 的信号量 -noLogicPassedForRouteExceptionMessage = 没有为路径传递逻辑: {0} -noPathSuppliedForStaticRouteExceptionMessage = [{0}]: 没有为静态路径提供路径。 -sourcePathDoesNotExistForStaticRouteExceptionMessage = [{0})] {1}: 为静态路径提供的源路径不存在: {2} -noLogicPassedForMethodRouteExceptionMessage = [{0}] {1}: 没有传递逻辑。 -moduleDoesNotContainFunctionExceptionMessage = 模块 {0} 不包含要转换为路径的函数 {1}。 -pageNameShouldBeAlphaNumericExceptionMessage = 页面名称应为有效的字母数字值: {0} -filesHaveChangedMessage = 以下文件已更改: -multipleEndpointsForGuiMessage = 定义了多个端点,仅第一个将用于 GUI。 -openingGuiMessage = 正在打开 GUI。 -listeningOnEndpointsMessage = 正在监听以下 {0} 个端点 [{1} 个线程]: -specificationMessage = 规格 -documentationMessage = 文档 -restartingServerMessage = 正在重启服务器... -doneMessage = 完成 -deprecatedTitleVersionDescriptionWarningMessage = 警告: 'Enable-PodeOpenApi' 的标题、版本和描述已被弃用。请改用 'Add-PodeOAInfo'。 -undefinedOpenApiReferencesMessage = 未定义的 OpenAPI 引用: -definitionTagMessage = 定义 {0}: -openApiGenerationDocumentErrorMessage = OpenAPI 生成文档错误: -infoTitleMandatoryMessage = info.title 是必填项。 -infoVersionMandatoryMessage = info.version 是必填项。 -missingComponentsMessage = 缺少的组件 -openApiInfoMessage = OpenAPI 信息: -serverLoopingMessage = 服务器每 {0} 秒循环一次 -iisShutdownMessage = (IIS 关闭) -terminatingMessage = 正在终止... -eolPowerShellWarningMessage = [警告] Pode {0} 未在 PowerShell {1} 上测试,因为它已达到 EOL。 -untestedPowerShellVersionWarningMessage = [警告] Pode {0} 未在 PowerShell {1} 上测试,因为 Pode 发布时该版本不可用。 -'@ \ No newline at end of file +@{ + schemaValidationRequiresPowerShell610ExceptionMessage = '架构验证需要 PowerShell 版本 6.1.0 或更高版本。' + pathOrScriptBlockRequiredExceptionMessage = '对于源自自定义访问值,需要路径或 ScriptBlock。' + operationIdMustBeUniqueForArrayExceptionMessage = '操作ID: {0} 必须唯一,不能应用于数组。' + endpointNotDefinedForRedirectingExceptionMessage = "未定义用于重定向的名为 '{0}' 的端点。" + filesHaveChangedMessage = '以下文件已更改:' + iisAspnetcoreTokenMissingExceptionMessage = '缺少 IIS ASPNETCORE_TOKEN。' + minValueGreaterThanMaxExceptionMessage = '{0} 的最小值不应大于最大值。' + noLogicPassedForRouteExceptionMessage = '没有为路径传递逻辑: {0}' + scriptPathDoesNotExistExceptionMessage = '脚本路径不存在: {0}' + mutexAlreadyExistsExceptionMessage = "名为 '{0}' 的互斥量已存在。" + listeningOnEndpointsMessage = '正在监听以下 {0} 个端点 [{1} 个线程]:' + unsupportedFunctionInServerlessContextExceptionMessage = '不支持在无服务器上下文中使用 {0} 函数。' + expectedNoJwtSignatureSuppliedExceptionMessage = '预期不提供 JWT 签名。' + secretAlreadyMountedExceptionMessage = "名为'{0}'的秘密已挂载。" + failedToAcquireLockExceptionMessage = '未能获取对象的锁。' + noPathSuppliedForStaticRouteExceptionMessage = '[{0}]: 没有为静态路径提供路径。' + invalidHostnameSuppliedExceptionMessage = '提供的主机名无效: {0}' + authMethodAlreadyDefinedExceptionMessage = '身份验证方法已定义:{0}' + csrfCookieRequiresSecretExceptionMessage = "使用 CSRF 的 Cookie 时,需要一个密钥。您可以提供一个密钥或设置全局 Cookie 密钥 - (Set-PodeCookieSecret '' -Global)" + nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = '创建页面路由需要非空的ScriptBlock。' + noPropertiesMutuallyExclusiveExceptionMessage = "参数'NoProperties'与'Properties'、'MinProperties'和'MaxProperties'互斥。" + incompatiblePodeDllExceptionMessage = '已加载存在不兼容的 Pode.DLL 版本 {0}。需要版本 {1}。请打开新的 Powershell/pwsh 会话并重试。' + accessMethodDoesNotExistExceptionMessage = '访问方法不存在:{0}。' + scheduleAlreadyDefinedExceptionMessage = '[计划] {0}: 计划已定义。' + secondsValueCannotBeZeroOrLessExceptionMessage = '{0} 的秒数值不能为 0 或更小。' + pathToLoadNotFoundExceptionMessage = '未找到要加载的路径 {0}: {1}' + failedToImportModuleExceptionMessage = '导入模块失败: {0}' + endpointNotExistExceptionMessage = "具有协议 '{0}' 和地址 '{1}' 或本地地址 '{2}' 的端点不存在。" + terminatingMessage = '正在终止...' + noCommandsSuppliedToConvertToRoutesExceptionMessage = '未提供要转换为路由的命令。' + invalidTaskTypeExceptionMessage = '任务类型无效,预期类型为[System.Threading.Tasks.Task]或[hashtable]。' + alreadyConnectedToWebSocketExceptionMessage = "已连接到名为 '{0}' 的 WebSocket" + crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = 'CRLF消息结束检查仅支持TCP端点。' + testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = "必须使用 'Enable-PodeOpenApi -EnableSchemaValidation' 启用 'Test-PodeOAComponentSchema'。" + adModuleNotInstalledExceptionMessage = '未安装 Active Directory 模块。' + cronExpressionInvalidExceptionMessage = 'Cron 表达式应仅包含 5 个部分: {0}' + noSessionToSetOnResponseExceptionMessage = '没有可用的会话来设置响应。' + valueOutOfRangeExceptionMessage = "{1} 的值 '{0}' 无效,应在 {2} 和 {3} 之间" + loggingMethodAlreadyDefinedExceptionMessage = '日志记录方法已定义: {0}' + noSecretForHmac256ExceptionMessage = '未提供 HMAC256 哈希的密钥。' + eolPowerShellWarningMessage = '[警告] Pode {0} 未在 PowerShell {1} 上测试,因为它已达到 EOL。' + runspacePoolFailedToLoadExceptionMessage = '{0} RunspacePool 加载失败。' + noEventRegisteredExceptionMessage = '没有注册的 {0} 事件:{1}' + scheduleCannotHaveNegativeLimitExceptionMessage = '[计划] {0}: 不能有负数限制。' + openApiRequestStyleInvalidForParameterExceptionMessage = 'OpenApi 请求样式不能为 {0},适用于 {1} 参数。' + openApiDocumentNotCompliantExceptionMessage = 'OpenAPI 文档不符合规范。' + taskDoesNotExistExceptionMessage = "任务 '{0}' 不存在。" + scopedVariableNotFoundExceptionMessage = '未找到范围变量: {0}' + sessionsRequiredForCsrfExceptionMessage = '使用CSRF需要会话, 除非您想使用Cookie。' + nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = '日志记录方法需要非空的ScriptBlock。' + credentialsPassedWildcardForHeadersLiteralExceptionMessage = '传递凭据时,标头的通配符 * 将被视为文字字符串,而不是通配符。' + podeNotInitializedExceptionMessage = 'Pode未初始化。' + multipleEndpointsForGuiMessage = '定义了多个端点,仅第一个将用于 GUI。' + operationIdMustBeUniqueExceptionMessage = '操作ID: {0} 必须唯一。' + invalidJsonJwtExceptionMessage = '在 JWT 中找到无效的 JSON 值' + noAlgorithmInJwtHeaderExceptionMessage = 'JWT 头中未提供算法。' + openApiVersionPropertyMandatoryExceptionMessage = 'OpenApi 版本属性是必需的。' + limitValueCannotBeZeroOrLessExceptionMessage = '{0} 的限制值不能为 0 或更小。' + timerDoesNotExistExceptionMessage = "计时器 '{0}' 不存在。" + openApiGenerationDocumentErrorMessage = 'OpenAPI 生成文档错误:' + routeAlreadyContainsCustomAccessExceptionMessage = "路由 '[{0}] {1}' 已经包含名称为 '{2}' 的自定义访问。" + maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = '最大并发 WebSocket 线程数不能小于最小值 {0},但获得: {1}' + middlewareAlreadyDefinedExceptionMessage = '[Middleware] {0}: 中间件已定义。' + invalidAtomCharacterExceptionMessage = '无效的原子字符: {0}' + cacheStorageNotFoundForRetrieveExceptionMessage = "尝试检索缓存项 '{1}' 时,找不到名为 '{0}' 的缓存存储。" + headerMustHaveNameInEncodingContextExceptionMessage = '在编码上下文中使用时,标头必须有名称。' + moduleDoesNotContainFunctionExceptionMessage = '模块 {0} 不包含要转换为路径的函数 {1}。' + pathToIconForGuiDoesNotExistExceptionMessage = 'GUI 图标的路径不存在: {0}' + noTitleSuppliedForPageExceptionMessage = '未提供 {0} 页面的标题。' + certificateSuppliedForNonHttpsWssEndpointExceptionMessage = '为非HTTPS/WSS端点提供的证书。' + cannotLockNullObjectExceptionMessage = '无法锁定空对象。' + showPodeGuiOnlyAvailableOnWindowsExceptionMessage = 'Show-PodeGui目前仅适用于Windows PowerShell和Windows上的PowerShell 7+。' + unlockSecretButNoScriptBlockExceptionMessage = '为自定义秘密保险库类型提供了解锁密钥,但未提供解锁 ScriptBlock。' + invalidIpAddressExceptionMessage = '提供的 IP 地址无效: {0}' + maxDaysInvalidExceptionMessage = 'MaxDays 必须大于或等于 0, 但得到: {0}' + noRemoveScriptBlockForVaultExceptionMessage = "未为从保险库 '{0}' 中删除秘密提供删除 ScriptBlock。" + noSecretExpectedForNoSignatureExceptionMessage = '预期未提供签名的密钥。' + noCertificateFoundExceptionMessage = "在 {0}{1} 中找不到证书 '{2}'。" + minValueInvalidExceptionMessage = "{1} 的最小值 '{0}' 无效,应大于或等于 {2}" + accessRequiresAuthenticationOnRoutesExceptionMessage = '访问需要在路由上进行身份验证。' + noSecretForHmac384ExceptionMessage = '未提供 HMAC384 哈希的密钥。' + windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = 'Windows 本地身份验证支持仅适用于 Windows。' + definitionTagNotDefinedExceptionMessage = '定义标签 {0} 未定义。' + noComponentInDefinitionExceptionMessage = '定义中没有类型为 {0} 名称为 {1} 的组件。' + noSmtpHandlersDefinedExceptionMessage = '未定义 SMTP 处理程序。' + sessionMiddlewareAlreadyInitializedExceptionMessage = '会话中间件已初始化。' + reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = "OpenAPI v3.0中不支持可重用组件功能'pathItems'。" + wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = '标头的通配符 * 与 AutoHeaders 开关不兼容。' + noDataForFileUploadedExceptionMessage = "请求中未上传文件 '{0}' 的数据。" + sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = 'SSE只能在Accept标头值为text/event-stream的请求上配置。' + noSessionAvailableToSaveExceptionMessage = '没有可保存的会话。' + pathParameterRequiresRequiredSwitchExceptionMessage = "如果参数位置是 'Path',则 'Required' 开关参数是必需的。" + noOpenApiUrlSuppliedExceptionMessage = '未提供 {0} 的 OpenAPI URL。' + maximumConcurrentSchedulesInvalidExceptionMessage = '最大并发计划数必须 >=1, 但得到: {0}' + snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = 'Snapins 仅支持 Windows PowerShell。' + eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = '事件查看器日志记录仅支持Windows。' + parametersMutuallyExclusiveExceptionMessage = "参数 '{0}' 和 '{1}' 是互斥的。" + pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = '在 OpenAPI v3.0.x 中不支持 PathItems 功能。' + openApiParameterRequiresNameExceptionMessage = 'OpenApi 参数需要指定名称。' + maximumConcurrentTasksLessThanMinimumExceptionMessage = '最大并发任务数不能小于最小值 {0},但获得: {1}' + noSemaphoreFoundExceptionMessage = "找不到名为 '{0}' 的信号量" + singleValueForIntervalExceptionMessage = '当使用间隔时,只能提供单个 {0} 值。' + jwtNotYetValidExceptionMessage = 'JWT 尚未有效。' + verbAlreadyDefinedForUrlExceptionMessage = '[Verb] {0}: 已经为 {1} 定义' + noSecretNamedMountedExceptionMessage = "没有挂载名为'{0}'的秘密。" + moduleOrVersionNotFoundExceptionMessage = '在 {0} 上找不到模块或版本: {1}@{2}' + noScriptBlockSuppliedExceptionMessage = '未提供脚本块。' + noSecretVaultRegisteredExceptionMessage = "未注册名为 '{0}' 的秘密保险库。" + nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = '如果提供了RedirectTo参数, 则需要为端点指定名称。' + openApiLicenseObjectRequiresNameExceptionMessage = "OpenAPI 对象 'license' 需要属性 'name'。请使用 -LicenseName 参数。" + sourcePathDoesNotExistForStaticRouteExceptionMessage = '[{0})] {1}: 为静态路径提供的源路径不存在: {2}' + noNameForWebSocketDisconnectExceptionMessage = '没有提供断开连接的 WebSocket 的名称。' + certificateExpiredExceptionMessage = "证书 '{0}' 已过期: {1}" + secretVaultUnlockExpiryDateInPastExceptionMessage = '秘密保险库的解锁到期日期已过 (UTC) :{0}' + invalidExceptionTypeExceptionMessage = '异常类型无效,应为 WebException 或 HttpRequestException, 但得到了: {0}' + invalidSecretValueTypeExceptionMessage = '密钥值是无效的类型。期望类型: 字符串、SecureString、HashTable、Byte[] 或 PSCredential。但得到了: {0}' + explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = '显式TLS模式仅支持SMTPS和TCPS端点。' + discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = "参数'DiscriminatorMapping'只能在存在'DiscriminatorProperty'时使用。" + scriptErrorExceptionMessage = "脚本 '{0}' 在 {1} {2} (第 {3} 行) 第 {4} 个字符处执行 {5} 对象 '{7}' 的错误。类: {8} 基类: {9}" + cannotSupplyIntervalForQuarterExceptionMessage = '无法为每季度提供间隔值。' + scheduleEndTimeMustBeInFutureExceptionMessage = '[计划] {0}: EndTime 值必须在将来。' + invalidJwtSignatureSuppliedExceptionMessage = '提供的 JWT 签名无效。' + noSetScriptBlockForVaultExceptionMessage = "未为更新/创建保险库 '{0}' 中的秘密提供设置 ScriptBlock。" + accessMethodNotExistForMergingExceptionMessage = '合并时访问方法不存在: {0}' + defaultAuthNotInListExceptionMessage = "默认身份验证 '{0}' 不在提供的身份验证列表中。" + parameterHasNoNameExceptionMessage = "参数没有名称。请使用'Name'参数为此组件命名。" + methodPathAlreadyDefinedForUrlExceptionMessage = '[{0}] {1}: 已经为 {2} 定义。' + fileWatcherAlreadyDefinedExceptionMessage = "名为 '{0}' 的文件监视器已定义。" + noServiceHandlersDefinedExceptionMessage = '未定义服务处理程序。' + secretRequiredForCustomSessionStorageExceptionMessage = '使用自定义会话存储时需要一个密钥。' + secretManagementModuleNotInstalledExceptionMessage = '未安装 Microsoft.PowerShell.SecretManagement 模块。' + noPathSuppliedForRouteExceptionMessage = '未为路由提供路径。' + validationOfAnyOfSchemaNotSupportedExceptionMessage = "不支持包含 'anyof' 的模式的验证。" + iisAuthSupportIsForWindowsOnlyExceptionMessage = 'IIS 身份验证支持仅适用于 Windows。' + oauth2InnerSchemeInvalidExceptionMessage = 'OAuth2 InnerScheme 只能是 Basic 或 Form 身份验证,但得到:{0}' + noRoutePathSuppliedForPageExceptionMessage = '未提供 {0} 页面的路由路径。' + cacheStorageNotFoundForExistsExceptionMessage = "尝试检查缓存项 '{1}' 是否存在时,找不到名为 '{0}' 的缓存存储。" + handlerAlreadyDefinedExceptionMessage = '[{0}] {1}: 处理程序已定义。' + sessionsNotConfiguredExceptionMessage = '会话尚未配置。' + propertiesTypeObjectAssociationExceptionMessage = '只有 Object 类型的属性可以与 {0} 关联。' + sessionsRequiredForSessionPersistentAuthExceptionMessage = '使用会话持久性身份验证需要会话。' + invalidPathWildcardOrDirectoryExceptionMessage = '提供的路径不能是通配符或目录: {0}' + accessMethodAlreadyDefinedExceptionMessage = '访问方法已经定义: {0}' + parametersValueOrExternalValueMandatoryExceptionMessage = "参数 'Value' 或 'ExternalValue' 是必需的。" + maximumConcurrentTasksInvalidExceptionMessage = '最大并发任务数必须 >=1, 但获得: {0}' + cannotCreatePropertyWithoutTypeExceptionMessage = '无法创建属性,因为未定义类型。' + authMethodNotExistForMergingExceptionMessage = '合并时身份验证方法不存在:{0}' + maxValueInvalidExceptionMessage = "{1} 的最大值 '{0}' 无效,应小于或等于 {2}" + endpointAlreadyDefinedExceptionMessage = "名为 '{0}' 的端点已定义。" + eventAlreadyRegisteredExceptionMessage = '{0} 事件已注册:{1}' + parameterNotSuppliedInRequestExceptionMessage = "请求中未提供名为 '{0}' 的参数或没有可用数据。" + cacheStorageNotFoundForSetExceptionMessage = "尝试设置缓存项 '{1}' 时,找不到名为 '{0}' 的缓存存储。" + methodPathAlreadyDefinedExceptionMessage = '[{0}] {1}: 已经定义。' + errorLoggingAlreadyEnabledExceptionMessage = '错误日志记录已启用。' + valueForUsingVariableNotFoundExceptionMessage = "未找到 '`$using:{0}' 的值。" + rapidPdfDoesNotSupportOpenApi31ExceptionMessage = '文档工具 RapidPdf 不支持 OpenAPI 3.1' + oauth2ClientSecretRequiredExceptionMessage = '不使用 PKCE 时, OAuth2 需要一个客户端密钥。' + invalidBase64JwtExceptionMessage = '在 JWT 中找到无效的 Base64 编码值' + noSessionToCalculateDataHashExceptionMessage = '没有可用的会话来计算数据哈希。' + cacheStorageNotFoundForRemoveExceptionMessage = "尝试删除缓存项 '{1}' 时,找不到名为 '{0}' 的缓存存储。" + csrfMiddlewareNotInitializedExceptionMessage = 'CSRF中间件未初始化。' + infoTitleMandatoryMessage = 'info.title 是必填项。' + typeCanOnlyBeAssociatedWithObjectExceptionMessage = '类型{0}只能与对象关联。' + userFileDoesNotExistExceptionMessage = '用户文件不存在:{0}' + routeParameterNeedsValidScriptblockExceptionMessage = '路由参数需要有效且非空的ScriptBlock。' + nextTriggerCalculationErrorExceptionMessage = '似乎在尝试计算下一个触发器日期时间时出现了问题: {0}' + cannotLockValueTypeExceptionMessage = '无法锁定[ValueTypes]。' + failedToCreateOpenSslCertExceptionMessage = '创建 openssl 证书失败: {0}' + jwtExpiredExceptionMessage = 'JWT 已过期。' + openingGuiMessage = '正在打开 GUI。' + multiTypePropertiesRequireOpenApi31ExceptionMessage = '多类型属性需要 OpenApi 版本 3.1 或更高版本。' + noNameForWebSocketRemoveExceptionMessage = '没有提供要删除的 WebSocket 的名称。' + maxSizeInvalidExceptionMessage = 'MaxSize 必须大于或等于 0,但得到: {0}' + iisShutdownMessage = '(IIS 关闭)' + cannotUnlockValueTypeExceptionMessage = '无法解锁[ValueTypes]。' + noJwtSignatureForAlgorithmExceptionMessage = '没有为 {0} 提供 JWT 签名。' + maximumConcurrentWebSocketThreadsInvalidExceptionMessage = '最大并发 WebSocket 线程数必须 >=1, 但获得: {0}' + acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = '确认消息仅支持SMTP和TCP端点。' + failedToConnectToUrlExceptionMessage = '连接到 URL 失败: {0}' + failedToAcquireMutexOwnershipExceptionMessage = '未能获得互斥量的所有权。互斥量名称: {0}' + sessionsRequiredForOAuth2WithPKCEExceptionMessage = '使用 PKCE 时需要会话来使用 OAuth2' + failedToConnectToWebSocketExceptionMessage = '连接到 WebSocket 失败: {0}' + unsupportedObjectExceptionMessage = '不支持的对象' + failedToParseAddressExceptionMessage = "无法将 '{0}' 解析为有效的 IP/主机:端口地址" + mustBeRunningWithAdminPrivilegesExceptionMessage = '必须以管理员权限运行才能监听非本地主机地址。' + specificationMessage = '规格' + cacheStorageNotFoundForClearExceptionMessage = "尝试清除缓存时,找不到名为 '{0}' 的缓存存储。" + restartingServerMessage = '正在重启服务器...' + cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = "当参数'Every'设置为None时, 无法提供间隔。" + unsupportedJwtAlgorithmExceptionMessage = '当前不支持的 JWT 算法: {0}' + websocketsNotConfiguredForSignalMessagesExceptionMessage = 'WebSockets未配置为发送信号消息。' + invalidLogicTypeInHashtableMiddlewareExceptionMessage = '提供的 Hashtable 中间件具有无效的逻辑类型。期望是 ScriptBlockm, 但得到了: {0}' + maximumConcurrentSchedulesLessThanMinimumExceptionMessage = '最大并发计划数不能小于最小值 {0},但得到: {1}' + failedToAcquireSemaphoreOwnershipExceptionMessage = '未能获得信号量的所有权。信号量名称: {0}' + propertiesParameterWithoutNameExceptionMessage = '如果属性没有名称,则不能使用 Properties 参数。' + customSessionStorageMethodNotImplementedExceptionMessage = "自定义会话存储未实现所需的方法'{0}()'。" + authenticationMethodDoesNotExistExceptionMessage = '认证方法不存在: {0}' + webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = '在 OpenAPI v3.0.x 中不支持 Webhooks 功能' + invalidContentTypeForSchemaExceptionMessage = "架构中发现无效的 'content-type': {0}" + noUnlockScriptBlockForVaultExceptionMessage = "未为解锁保险库 '{0}' 提供解锁 ScriptBlock。" + definitionTagMessage = '定义 {0}:' + failedToOpenRunspacePoolExceptionMessage = '打开 RunspacePool 失败: {0}' + verbNoLogicPassedExceptionMessage = '[动词] {0}: 未传递逻辑' + noMutexFoundExceptionMessage = "找不到名为 '{0}' 的互斥量" + documentationMessage = '文档' + timerAlreadyDefinedExceptionMessage = '[计时器] {0}: 计时器已定义。' + invalidPortExceptionMessage = '端口不能为负数: {0}' + viewsFolderNameAlreadyExistsExceptionMessage = '视图文件夹名称已存在: {0}' + noNameForWebSocketResetExceptionMessage = '没有提供要重置的 WebSocket 的名称。' + mergeDefaultAuthNotInListExceptionMessage = "MergeDefault 身份验证 '{0}' 不在提供的身份验证列表中。" + descriptionRequiredExceptionMessage = '描述是必需的。' + pageNameShouldBeAlphaNumericExceptionMessage = '页面名称应为有效的字母数字值: {0}' + defaultValueNotBooleanOrEnumExceptionMessage = '默认值不是布尔值且不属于枚举。' + openApiComponentSchemaDoesNotExistExceptionMessage = 'OpenApi 组件架构 {0} 不存在。' + timerParameterMustBeGreaterThanZeroExceptionMessage = '[计时器] {0}: {1} 必须大于 0。' + taskTimedOutExceptionMessage = '任务在 {0} 毫秒后超时。' + scheduleStartTimeAfterEndTimeExceptionMessage = "[计划] {0}: 'StartTime' 不能在 'EndTime' 之后" + infoVersionMandatoryMessage = 'info.version 是必填项。' + cannotUnlockNullObjectExceptionMessage = '无法解锁空对象。' + nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = '自定义身份验证方案需要一个非空的 ScriptBlock。' + validationOfOneOfSchemaNotSupportedExceptionMessage = "不支持包含 'oneof' 的模式的验证。" + routeParameterCannotBeNullExceptionMessage = "参数 'Route' 不能为空。" + cacheStorageAlreadyExistsExceptionMessage = "名为 '{0}' 的缓存存储已存在。" + loggingMethodRequiresValidScriptBlockExceptionMessage = "为 '{0}' 日志记录方法提供的输出方法需要有效的 ScriptBlock。" + scopedVariableAlreadyDefinedExceptionMessage = '已经定义了作用域变量: {0}' + oauth2RequiresAuthorizeUrlExceptionMessage = 'OAuth2 需要提供授权 URL' + pathNotExistExceptionMessage = '路径不存在: {0}' + noDomainServerNameForWindowsAdAuthExceptionMessage = '没有为 Windows AD 身份验证提供域服务器名称' + suppliedDateAfterScheduleEndTimeExceptionMessage = '提供的日期晚于计划的结束时间 {0}' + wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = '方法的通配符 * 与 AutoMethods 开关不兼容。' + cannotSupplyIntervalForYearExceptionMessage = '无法为每年提供间隔值。' + missingComponentsMessage = '缺少的组件' + invalidStrictTransportSecurityDurationExceptionMessage = '提供的严格传输安全持续时间无效: {0}。应大于 0。' + noSecretForHmac512ExceptionMessage = '未提供 HMAC512 哈希的密钥。' + daysInMonthExceededExceptionMessage = '{0} 仅有 {1} 天,但提供了 {2} 天。' + nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = '自定义日志输出方法需要非空的ScriptBlock。' + encodingAttributeOnlyAppliesToMultipartExceptionMessage = '编码属性仅适用于 multipart 和 application/x-www-form-urlencoded 请求体。' + suppliedDateBeforeScheduleStartTimeExceptionMessage = '提供的日期早于计划的开始时间 {0}' + unlockSecretRequiredExceptionMessage = "使用 Microsoft.PowerShell.SecretStore 时需要 'UnlockSecret' 属性。" + noLogicPassedForMethodRouteExceptionMessage = '[{0}] {1}: 没有传递逻辑。' + bodyParserAlreadyDefinedForContentTypeExceptionMessage = '已为 {0} 内容类型定义了一个 body-parser。' + invalidJwtSuppliedExceptionMessage = '提供的 JWT 无效。' + sessionsRequiredForFlashMessagesExceptionMessage = '使用闪存消息需要会话。' + outputMethodRequiresValidScriptBlockForRequestLoggingExceptionMessage = '请求日志记录提供的输出方法需要有效的ScriptBlock。' + semaphoreAlreadyExistsExceptionMessage = "名为 '{0}' 的信号量已存在。" + invalidJwtHeaderAlgorithmSuppliedExceptionMessage = '提供的 JWT 头算法无效。' + oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = "OAuth2 提供程序不支持使用 InnerScheme 所需的 'password' grant_type。" + invalidAliasFoundExceptionMessage = '找到了无效的 {0} 别名: {1}' + scheduleDoesNotExistExceptionMessage = "计划 '{0}' 不存在。" + accessMethodNotExistExceptionMessage = '访问方法不存在: {0}' + oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = "OAuth2 提供程序不支持 'code' response_type。" + untestedPowerShellVersionWarningMessage = '[警告] Pode {0} 未在 PowerShell {1} 上测试,因为 Pode 发布时该版本不可用。' + secretVaultAlreadyRegisteredAutoImportExceptionMessage = "已经注册了名称为 '{0}' 的秘密保险库,同时正在自动导入秘密保险库。" + schemeRequiresValidScriptBlockExceptionMessage = "提供的方案用于 '{0}' 身份验证验证器,需要一个有效的 ScriptBlock。" + serverLoopingMessage = '服务器每 {0} 秒循环一次' + certificateThumbprintsNameSupportedOnWindowsExceptionMessage = '证书指纹/名称仅在 Windows 上受支持。' + sseConnectionNameRequiredExceptionMessage = "需要SSE连接名称, 可以从-Name或`$WebEvent.Sse.Name获取。" + invalidMiddlewareTypeExceptionMessage = '提供的中间件之一是无效的类型。期望是 ScriptBlock 或 Hashtable, 但得到了: {0}' + noSecretForJwtSignatureExceptionMessage = '未提供 JWT 签名的密钥。' + modulePathDoesNotExistExceptionMessage = '模块路径不存在: {0}' + taskAlreadyDefinedExceptionMessage = '[任务] {0}: 任务已定义。' + verbAlreadyDefinedExceptionMessage = '[Verb] {0}: 已经定义' + clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = '客户端证书仅支持HTTPS端点。' + endpointNameNotExistExceptionMessage = "名为 '{0}' 的端点不存在。" + middlewareNoLogicSuppliedExceptionMessage = '[中间件]: ScriptBlock中未提供逻辑。' + scriptBlockRequiredForMergingUsersExceptionMessage = '当 Valid 是 All 时,需要一个 ScriptBlock 来将多个经过身份验证的用户合并为一个对象。' + secretVaultAlreadyRegisteredExceptionMessage = "名为'{0}'的秘密保险库已注册{1}。" + deprecatedTitleVersionDescriptionWarningMessage = "警告: 'Enable-PodeOpenApi' 的标题、版本和描述已被弃用。请改用 'Add-PodeOAInfo'。" + undefinedOpenApiReferencesMessage = '未定义的 OpenAPI 引用:' + doneMessage = '完成' + swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = '此版本的 Swagger-Editor 不支持 OpenAPI 3.1' + durationMustBeZeroOrGreaterExceptionMessage = '持续时间必须为 0 或更大,但获得: {0}s' + viewsPathDoesNotExistExceptionMessage = '视图路径不存在: {0}' + discriminatorIncompatibleWithAllOfExceptionMessage = "参数'Discriminator'与'allOf'不兼容。" + noNameForWebSocketSendMessageExceptionMessage = '没有提供要发送消息的 WebSocket 的名称。' + hashtableMiddlewareNoLogicExceptionMessage = '提供的 Hashtable 中间件没有定义逻辑。' + openApiInfoMessage = 'OpenAPI 信息:' + invalidSchemeForAuthValidatorExceptionMessage = "提供的 '{0}' 方案用于 '{1}' 身份验证验证器,需要一个有效的 ScriptBlock。" + sseFailedToBroadcastExceptionMessage = '由于为{0}定义的SSE广播级别, SSE广播失败: {1}' + adModuleWindowsOnlyExceptionMessage = '仅支持 Windows 的 Active Directory 模块。' + requestLoggingAlreadyEnabledExceptionMessage = '请求日志记录已启用。' + invalidAccessControlMaxAgeDurationExceptionMessage = '提供的 Access-Control-Max-Age 时长无效:{0}。应大于 0。' +} + diff --git a/tests/unit/Localization.Tests.ps1 b/tests/unit/Localization.Tests.ps1 index 0c44f77b1..9ef3fdcea 100644 --- a/tests/unit/Localization.Tests.ps1 +++ b/tests/unit/Localization.Tests.ps1 @@ -28,19 +28,15 @@ Describe 'Localization Check' { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src' + # All language directories $localizationDir = "$src/Locales" - # Path to the English localization file - $englishFilePath = "$localizationDir/en/Pode.psd1" - $podeFileContent = Get-Content -Path $englishFilePath -Raw - # Execute the content and assign the result to a variable - $localizationMessages = Invoke-Expression $podeFileContent + $localizationMessages = Import-LocalizedData -FileName 'Pode.psd1' -BaseDirectory $localizationDir -UICulture 'en' $global:localizationKeys = $localizationMessages.Keys # Discover all language directories $languageDirs = Get-ChildItem -Path $localizationDir -Directory | Where-Object { $_.Name -ne 'en' } - # Get all source code files recursively from the specified directory $sourceFiles = Get-ChildItem -Path $src -Recurse -Include *.ps1, *.psm1 @@ -56,11 +52,12 @@ Describe 'Localization Check' { it 'Language resource file exist' { Test-Path -Path "$($_.FullName)/Pode.psd1" | Should -BeTrue } - $podeFileContent = Get-Content -Path "$($_.FullName)/Pode.psd1" -Raw - $global:content = Invoke-Expression $podeFileContent + + $global:content = Import-LocalizedData -FileName 'Pode.psd1' -BaseDirectory $localizationDir -UICulture $_.Name it 'Number of entry equal to the [en]' { $global:content.Keys.Count | Should -be $global:localizationKeys.Count } + It -ForEach ($global:localizationKeys) -Name 'Resource File contain <_>' { foreach ($key in $global:localizationKeys) { $global:content.Keys -contains $_ | Should -BeTrue From 4d098b26ba5d5b019f7b2fe1127e44e1f016c7d2 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Thu, 6 Jun 2024 11:17:53 -0700 Subject: [PATCH 037/177] Delete Convert-HashtableToPsd1.ps1 --- Convert-HashtableToPsd1.ps1 | 39 ------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 Convert-HashtableToPsd1.ps1 diff --git a/Convert-HashtableToPsd1.ps1 b/Convert-HashtableToPsd1.ps1 deleted file mode 100644 index 138dcddda..000000000 --- a/Convert-HashtableToPsd1.ps1 +++ /dev/null @@ -1,39 +0,0 @@ - -param ( - [Parameter(Mandatory = $false)] - [string]$Path = 'c:\Users\m_dan\Documents\GitHub\Pode\src\Locales' -) - - - -function Convert-HashTable { - param ( - [Parameter(Mandatory = $true)] - [hashtable]$hashtable - ) - - - $sb = New-Object System.Text.StringBuilder - $sb.AppendLine('@{') | Out-Null - - foreach ($key in $hashtable.Keys) { - $value = $hashtable[$key] - $sb.AppendLine(" $key = `"$value`"") | Out-Null - } - - $sb.AppendLine('}') | Out-Null - return $sb.ToString() -} - -$languageDirs = Get-ChildItem -Path $Path -Directory -foreach ($item in $languageDirs) { - $fullName = Join-Path -Path $item.FullName -ChildPath 'Pode.psd1' - - $PodeFileContent = Get-content $fullName -raw - $value = Invoke-Expression $podeFileContent - - - $result = Convert-HashTable -hashtable $value - Move-Item -path $fullName -destination "$fullName.old" - Set-Content -Path $fullName -Value $result -} \ No newline at end of file From b330511c8eccc40dfa12e0388a4711f1c6f0107b Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Thu, 6 Jun 2024 19:26:40 +0100 Subject: [PATCH 038/177] Make preview builds optional, until they're more stable --- .github/workflows/ci-pwsh_preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-pwsh_preview.yml b/.github/workflows/ci-pwsh_preview.yml index 56c9dde71..81bb80c3d 100644 --- a/.github/workflows/ci-pwsh_preview.yml +++ b/.github/workflows/ci-pwsh_preview.yml @@ -28,7 +28,7 @@ env: POWERSHELL_VERSION: 'Preview' jobs: - build: + build-preview: runs-on: ${{ matrix.os }} strategy: From a98cbc6a45190c216f46328adb9d54db26393ee1 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Thu, 6 Jun 2024 19:35:21 +0100 Subject: [PATCH 039/177] Allow 'no-build-needed' CI to run when just the preview CI workflow is updated --- .github/workflows/ci-no-build-needed.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-no-build-needed.yml b/.github/workflows/ci-no-build-needed.yml index e27e5bafe..3345471f0 100644 --- a/.github/workflows/ci-no-build-needed.yml +++ b/.github/workflows/ci-no-build-needed.yml @@ -12,7 +12,8 @@ on: - 'src/**' - 'tests/**' - '.github/workflows/ci-docs.yml' - - '.github/workflows/ci-pwsh*.yml' + - '.github/workflows/ci-pwsh_lts.yml' + - '.github/workflows/ci-pwsh7_2.yml' - '.github/workflows/ci-powershell.yml' - '.github/workflows/ci-coverage.yml' - '.github/workflows/PSScriptAnalyzer.yml' @@ -30,7 +31,8 @@ on: - 'src/**' - 'tests/**' - '.github/workflows/ci-docs.yml' - - '.github/workflows/ci-pwsh*.yml' + - '.github/workflows/ci-pwsh_lts.yml' + - '.github/workflows/ci-pwsh7_2.yml' - '.github/workflows/ci-powershell.yml' - '.github/workflows/ci-coverage.yml' - '.github/workflows/PSScriptAnalyzer.yml' From d00ef81b9517d62b3b5de60015b87c64801e2335 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 7 Jun 2024 16:11:52 -0700 Subject: [PATCH 040/177] file browsing i18n support --- .../public/string_performance_test.html | 100 ++++++ src/Misc/default-file-browsing.html.pode | 295 ++++++++++++++---- 2 files changed, 331 insertions(+), 64 deletions(-) create mode 100644 examples/FileBrowser/public/string_performance_test.html diff --git a/examples/FileBrowser/public/string_performance_test.html b/examples/FileBrowser/public/string_performance_test.html new file mode 100644 index 000000000..1b3423e1b --- /dev/null +++ b/examples/FileBrowser/public/string_performance_test.html @@ -0,0 +1,100 @@ + + + + + + + String Interpolation Performance Test + + + +

String Interpolation Performance Test

+ +
+ + + + + \ No newline at end of file diff --git a/src/Misc/default-file-browsing.html.pode b/src/Misc/default-file-browsing.html.pode index 2c5c6103b..45a95ef21 100644 --- a/src/Misc/default-file-browsing.html.pode +++ b/src/Misc/default-file-browsing.html.pode @@ -6,7 +6,7 @@ " - }) - - -
- + + + $($data.Title) + + + + + + + $(if ($data.DarkMode) { + "" + }) + + + +
+ + \ No newline at end of file From 2eb35caa74a1541138915a49f6079df66bd64a9f Mon Sep 17 00:00:00 2001 From: mdaneri Date: Thu, 25 Jul 2024 09:21:17 -0700 Subject: [PATCH 128/177] Replace new-object with ::new() --- src/Private/OpenApi.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index 27173906c..81be1e4e0 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -1324,7 +1324,7 @@ function Initialize-PodeOpenApiTable { ) # Initialization of the OpenAPI table with default settings $OpenAPI = @{ - DefinitionTagSelectionStack = New-Object 'System.Collections.Generic.Stack[System.Object]' + DefinitionTagSelectionStack = [System.Collections.Generic.Stack[System.Object]]::new() } # Set the currently selected definition tag From b752c14cf70cb070407d573405fd5eb419bbb6c0 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 26 Jul 2024 06:54:23 -0700 Subject: [PATCH 129/177] Update OpenApi.ps1 --- src/Public/OpenApi.ps1 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index 0f08f95a9..26a64d1eb 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -118,9 +118,11 @@ function Enable-PodeOpenApi { [string] $RouteFilter = '/*', + [Parameter()] [string[]] $EndpointName, + [Parameter()] [object[]] $Middleware, @@ -144,21 +146,26 @@ function Enable-PodeOpenApi { [switch] $RestrictRoutes, + [Parameter()] [ValidateSet('View', 'Download')] [String] $Mode = 'view', + [Parameter()] [ValidateSet('Json', 'Json-Compress', 'Yaml')] [String] $MarkupLanguage = 'Json', + [Parameter()] [switch] $EnableSchemaValidation, + [Parameter()] [ValidateRange(1, 100)] [int] $Depth = 20, + [Parameter()] [switch] $DisableMinimalDefinitions, @@ -170,6 +177,7 @@ function Enable-PodeOpenApi { [switch] $NoDefaultResponses, + [Parameter()] [string] $DefinitionTag From e4683a26f5d27339c14dd6fabc0946fc263c7866 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Thu, 1 Aug 2024 14:42:12 -0700 Subject: [PATCH 130/177] Test task improvement - Pode.psm1 dll load improvement --- pode.build.ps1 | 42 +++++++++++++++++++++++++++++++++++++++--- src/Pode.psm1 | 22 ++++++++++++++++------ 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/pode.build.ps1 b/pode.build.ps1 index 8cdb9b0c3..aadbe9f62 100644 --- a/pode.build.ps1 +++ b/pode.build.ps1 @@ -501,15 +501,51 @@ Task TestNoBuild TestDeps, { else { $Script:TestStatus = Invoke-Pester -Configuration $configuration } - if ($originalUICulture){ + if ($originalUICulture) { Write-Output "Restore UICulture to $originalUICulture" # restore original UICulture [System.Threading.Thread]::CurrentThread.CurrentUICulture = $originalUICulture } }, PushCodeCoverage, CheckFailedTests -# Synopsis: Run tests after a build -Task Test Build, TestNoBuild +# Synopsis: Run tests after a build if needed +Task Test { + + # Get the .NET framework description to determine the runtime version + $frameworkDescription = [System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription + $found = $false + + # Match and extract the major version number from the framework description + if ($frameworkDescription -match '(\d+)\.(\d+)\.(\d+)') { + $majorVersion = [int]$matches[1] + + # Loop through the major versions from the detected version down to 6 + for ($version = $majorVersion; $version -ge 6; $version--) { + # Check if the corresponding Pode.dll file exists for the version + if (Test-Path "./src/Libs/net$version.0/Pode.dll") { + $found = $true + break + } + } + } + + # If no specific versioned Pode.dll was found, check for the netstandard2.0 version + if (-not $found) { + $found = Test-Path "./src/Libs/netstandard2.0/Pode.dll" + } + + # If any Pode.dll was found, skip the build task + if ($found) { + Write-Output 'Build Task not needed' + } + else { + # If no Pode.dll was found, invoke the build task + Invoke-Build Build + } + + # Always run the test task, assuming that the build task has already been run if needed + Invoke-Build TestNoBuild +} # Synopsis: Check if any of the tests failed diff --git a/src/Pode.psm1 b/src/Pode.psm1 index 700a06a14..992f76a8f 100644 --- a/src/Pode.psm1 +++ b/src/Pode.psm1 @@ -90,15 +90,25 @@ try { } } else { - if ($PSVersionTable.PSVersion -ge [version]'7.4.0') { - Add-Type -LiteralPath "$($root)/Libs/net8.0/Pode.dll" -ErrorAction Stop - } - elseif ($PSVersionTable.PSVersion -ge [version]'7.2.0') { - Add-Type -LiteralPath "$($root)/Libs/net6.0/Pode.dll" -ErrorAction Stop + $frameworkDescription = [System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription + $loaded = $false + if ($frameworkDescription -match '(\d+)\.(\d+)\.(\d+)') { + $majorVersion = [int]$matches[1] + + for ($version = $majorVersion; $version -ge 6; $version--) { + $dllPath = "$($root)/Libs/net$version.0/Pode.dll" + if (Test-Path $dllPath) { + Add-Type -LiteralPath $dllPath -ErrorAction Stop + $loaded = $true + break + } + } } - else { + + if (-not $loaded) { Add-Type -LiteralPath "$($root)/Libs/netstandard2.0/Pode.dll" -ErrorAction Stop } + } # load private functions From e25d7d419e30fa339b5a693d1e8a4094065f97ac Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 2 Aug 2024 06:29:20 -0700 Subject: [PATCH 131/177] added $ProgressPreference = 'SilentlyContinue' --- .github/workflows/ci-pwsh_preview.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-pwsh_preview.yml b/.github/workflows/ci-pwsh_preview.yml index 81bb80c3d..4e82924ac 100644 --- a/.github/workflows/ci-pwsh_preview.yml +++ b/.github/workflows/ci-pwsh_preview.yml @@ -66,6 +66,7 @@ jobs: - name: Install Invoke-Build shell: pwsh run: | + $ProgressPreference = 'SilentlyContinue' Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force - name: Run Pester Tests From df78a1d722993663b46068806066e3734e3440c7 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Tue, 13 Aug 2024 16:33:13 -0700 Subject: [PATCH 132/177] Changed getRequestBodyNotAllowedExceptionMessage check --- src/Locales/ar/Pode.psd1 | 2 +- src/Locales/de/Pode.psd1 | 2 +- src/Locales/en-us/Pode.psd1 | 2 +- src/Locales/en/Pode.psd1 | 2 +- src/Locales/es/Pode.psd1 | 2 +- src/Locales/fr/Pode.psd1 | 2 +- src/Locales/it/Pode.psd1 | 2 +- src/Locales/ja/Pode.psd1 | 2 +- src/Locales/ko/Pode.psd1 | 2 +- src/Locales/nl/Pode.psd1 | 2 +- src/Locales/pl/Pode.psd1 | 2 +- src/Locales/pt/Pode.psd1 | 2 +- src/Locales/zh/Pode.psd1 | 2 +- src/Public/OpenApi.ps1 | 7 ++++--- 14 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 90e8cbd76..b6cd8b697 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -286,5 +286,5 @@ openApiDefinitionAlreadyExistsExceptionMessage = 'تعريف OpenAPI باسم {0} موجود بالفعل.' renamePodeOADefinitionTagExceptionMessage = "لا يمكن استخدام Rename-PodeOADefinitionTag داخل Select-PodeOADefinition 'ScriptBlock'." definitionTagChangeNotAllowedExceptionMessage = 'لا يمكن تغيير علامة التعريف لمسار.' - getRequestBodyNotAllowedExceptionMessage = 'لا يمكن أن تحتوي عمليات GET على محتوى الطلب.' + getRequestBodyNotAllowedExceptionMessage = 'لا يمكن أن تحتوي عمليات {0} على محتوى الطلب.' } diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index 1655c5b4e..fb7b0c6ad 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -286,5 +286,5 @@ openApiDefinitionAlreadyExistsExceptionMessage = 'Die OpenAPI-Definition mit dem Namen {0} existiert bereits.' renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag kann nicht innerhalb eines 'ScriptBlock' von Select-PodeOADefinition verwendet werden." definitionTagChangeNotAllowedExceptionMessage = 'Definitionstag für eine Route kann nicht geändert werden.' - getRequestBodyNotAllowedExceptionMessage = 'GET-Operationen können keinen Anforderungstext haben.' + getRequestBodyNotAllowedExceptionMessage = '{0}-Operationen können keinen Anforderungstext haben.' } \ No newline at end of file diff --git a/src/Locales/en-us/Pode.psd1 b/src/Locales/en-us/Pode.psd1 index 108dabd76..53aba0d1c 100644 --- a/src/Locales/en-us/Pode.psd1 +++ b/src/Locales/en-us/Pode.psd1 @@ -286,5 +286,5 @@ openApiDefinitionAlreadyExistsExceptionMessage = 'OpenAPI definition named {0} already exists.' renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." definitionTagChangeNotAllowedExceptionMessage = 'Definition Tag for a Route cannot be changed.' - getRequestBodyNotAllowedExceptionMessage = 'GET operations cannot have a Request Body.' + getRequestBodyNotAllowedExceptionMessage = '{0} operations cannot have a Request Body.' } \ No newline at end of file diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index a1ad6d385..8f97eead4 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -286,6 +286,6 @@ openApiDefinitionAlreadyExistsExceptionMessage = 'OpenAPI definition named {0} already exists.' renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." definitionTagChangeNotAllowedExceptionMessage = 'Definition Tag for a Route cannot be changed.' - getRequestBodyNotAllowedExceptionMessage = 'GET operations cannot have a Request Body.' + getRequestBodyNotAllowedExceptionMessage = '{0} operations cannot have a Request Body.' } diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 321339d12..9ca60ee62 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -286,5 +286,5 @@ openApiDefinitionAlreadyExistsExceptionMessage = 'La definición de OpenAPI con el nombre {0} ya existe.' renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag no se puede usar dentro de un 'ScriptBlock' de Select-PodeOADefinition." definitionTagChangeNotAllowedExceptionMessage = 'La etiqueta de definición para una Route no se puede cambiar.' - getRequestBodyNotAllowedExceptionMessage = 'Las operaciones GET no pueden tener un cuerpo de solicitud.' + getRequestBodyNotAllowedExceptionMessage = 'Las operaciones {0} no pueden tener un cuerpo de solicitud.' } \ No newline at end of file diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index e2b266e4f..8b9d047d3 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -286,6 +286,6 @@ openApiDefinitionAlreadyExistsExceptionMessage = 'La définition OpenAPI nommée {0} existe déjà.' renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag ne peut pas être utilisé à l'intérieur d'un 'ScriptBlock' de Select-PodeOADefinition." definitionTagChangeNotAllowedExceptionMessage = 'Le tag de définition pour une Route ne peut pas être modifié.' - getRequestBodyNotAllowedExceptionMessage = 'Les opérations GET ne peuvent pas avoir de corps de requête.' + getRequestBodyNotAllowedExceptionMessage = 'Les opérations {0} ne peuvent pas avoir de corps de requête.' } diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index 89073fcb3..ff9ccfc73 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -286,5 +286,5 @@ openApiDefinitionAlreadyExistsExceptionMessage = 'La definizione OpenAPI denominata {0} esiste già.' renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag non può essere utilizzato all'interno di un 'ScriptBlock' di Select-PodeOADefinition." definitionTagChangeNotAllowedExceptionMessage = 'Il tag di definizione per una Route non può essere cambiato.' - getRequestBodyNotAllowedExceptionMessage = 'Le operazioni GET non possono avere un corpo della richiesta.' + getRequestBodyNotAllowedExceptionMessage = 'Le operazioni {0} non possono avere un corpo della richiesta.' } \ No newline at end of file diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index 982c9e568..ffc193a46 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -286,6 +286,6 @@ openApiDefinitionAlreadyExistsExceptionMessage = '名前が {0} の OpenAPI 定義は既に存在します。' renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag は Select-PodeOADefinition 'ScriptBlock' 内で使用できません。" definitionTagChangeNotAllowedExceptionMessage = 'Routeの定義タグは変更できません。' - getRequestBodyNotAllowedExceptionMessage = 'GET操作にはリクエストボディを含めることはできません。' + getRequestBodyNotAllowedExceptionMessage = '{0}操作にはリクエストボディを含めることはできません。' } diff --git a/src/Locales/ko/Pode.psd1 b/src/Locales/ko/Pode.psd1 index 4d3998910..25e3c3d10 100644 --- a/src/Locales/ko/Pode.psd1 +++ b/src/Locales/ko/Pode.psd1 @@ -286,5 +286,5 @@ openApiDefinitionAlreadyExistsExceptionMessage = '이름이 {0}인 OpenAPI 정의가 이미 존재합니다.' renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag은 Select-PodeOADefinition 'ScriptBlock' 내에서 사용할 수 없습니다." definitionTagChangeNotAllowedExceptionMessage = 'Route에 대한 정의 태그는 변경할 수 없습니다.' - getRequestBodyNotAllowedExceptionMessage = 'GET 작업에는 요청 본문이 있을 수 없습니다.' + getRequestBodyNotAllowedExceptionMessage = '{0} 작업에는 요청 본문이 있을 수 없습니다.' } diff --git a/src/Locales/nl/Pode.psd1 b/src/Locales/nl/Pode.psd1 index 677603c64..3f20960a0 100644 --- a/src/Locales/nl/Pode.psd1 +++ b/src/Locales/nl/Pode.psd1 @@ -286,6 +286,6 @@ openApiDefinitionAlreadyExistsExceptionMessage = 'OpenAPI-definitie met de naam {0} bestaat al.' renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag kan niet worden gebruikt binnen een Select-PodeOADefinition 'ScriptBlock'." definitionTagChangeNotAllowedExceptionMessage = 'Definitietag voor een route kan niet worden gewijzigd.' - getRequestBodyNotAllowedExceptionMessage = 'GET-operaties kunnen geen Request Body hebben.' + getRequestBodyNotAllowedExceptionMessage = '{0}-operaties kunnen geen Request Body hebben.' } diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index 1f2301f46..6c4f2da03 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -286,6 +286,6 @@ openApiDefinitionAlreadyExistsExceptionMessage = 'Definicja OpenAPI o nazwie {0} już istnieje.' renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag nie może być używany wewnątrz 'ScriptBlock' Select-PodeOADefinition." definitionTagChangeNotAllowedExceptionMessage = 'Tag definicji dla Route nie może zostać zmieniony.' - getRequestBodyNotAllowedExceptionMessage = 'Operacje GET nie mogą mieć treści żądania.' + getRequestBodyNotAllowedExceptionMessage = 'Operacje {0} nie mogą mieć treści żądania.' } diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index f7753082d..df0073012 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -286,5 +286,5 @@ openApiDefinitionAlreadyExistsExceptionMessage = 'A definição OpenAPI com o nome {0} já existe.' renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag não pode ser usado dentro de um 'ScriptBlock' Select-PodeOADefinition." definitionTagChangeNotAllowedExceptionMessage = 'A Tag de definição para uma Route não pode ser alterada.' - getRequestBodyNotAllowedExceptionMessage = 'As operações GET não podem ter um corpo de solicitação.' + getRequestBodyNotAllowedExceptionMessage = 'As operações {0} não podem ter um corpo de solicitação.' } \ No newline at end of file diff --git a/src/Locales/zh/Pode.psd1 b/src/Locales/zh/Pode.psd1 index 52b00eab2..daa9ad110 100644 --- a/src/Locales/zh/Pode.psd1 +++ b/src/Locales/zh/Pode.psd1 @@ -286,5 +286,5 @@ openApiDefinitionAlreadyExistsExceptionMessage = '名为 {0} 的 OpenAPI 定义已存在。' renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag 不能在 Select-PodeOADefinition 'ScriptBlock' 内使用。" definitionTagChangeNotAllowedExceptionMessage = 'Route的定义标签无法更改。' - getRequestBodyNotAllowedExceptionMessage = 'GET 操作不能包含请求体。' + getRequestBodyNotAllowedExceptionMessage = '{0} 操作不能包含请求体。' } \ No newline at end of file diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index 26a64d1eb..bea3cd2cf 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -779,9 +779,10 @@ function Set-PodeOARequest { } if ($null -ne $RequestBody) { - if ($r.Method -eq 'Get') { - # GET operations cannot have a Request Body. - throw $PodeLocale.getRequestBodyNotAllowedExceptionMessage + # Only 'POST', 'PUT', 'PATCH' can have a request body + if (('POST', 'PUT', 'PATCH') -icontains $r.Method ) { + # {0} operations cannot have a Request Body. + throw ($PodeLocale.getRequestBodyNotAllowedExceptionMessage -f $r.Method) } $r.OpenApi.RequestBody = $RequestBody } From 79e1f4ed4af84cc845afed840901163e4a6a0ad3 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Wed, 14 Aug 2024 08:24:49 -0700 Subject: [PATCH 133/177] Add test for Set-PodeOARequest --- src/Public/OpenApi.ps1 | 2 +- tests/unit/OpenApi.Tests.ps1 | 64 ++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index bea3cd2cf..77dd0a4d4 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -780,7 +780,7 @@ function Set-PodeOARequest { if ($null -ne $RequestBody) { # Only 'POST', 'PUT', 'PATCH' can have a request body - if (('POST', 'PUT', 'PATCH') -icontains $r.Method ) { + if (('POST', 'PUT', 'PATCH') -inotcontains $r.Method ) { # {0} operations cannot have a Request Body. throw ($PodeLocale.getRequestBodyNotAllowedExceptionMessage -f $r.Method) } diff --git a/tests/unit/OpenApi.Tests.ps1 b/tests/unit/OpenApi.Tests.ps1 index 2dbbf3708..aab9ca389 100644 --- a/tests/unit/OpenApi.Tests.ps1 +++ b/tests/unit/OpenApi.Tests.ps1 @@ -3107,6 +3107,70 @@ Describe 'OpenApi' { } + Describe 'Set-PodeOARequest' { + + It 'Sets Parameters on the route if provided' { + $route = @{ + Method = 'GET' + OpenApi = @{} + } + $parameters = @( + @{ Name = 'param1'; In = 'query' } + ) + + Set-PodeOARequest -Route $route -Parameters $parameters + + $route.OpenApi.Parameters | Should -BeExactly $parameters + } + + It 'Sets RequestBody on the route if method is POST' { + $route = @{ + Method = 'POST' + OpenApi = @{} + } + $requestBody = @{ Content = 'application/json' } + + Set-PodeOARequest -Route $route -RequestBody $requestBody + + $route.OpenApi.RequestBody | Should -BeExactly $requestBody + } + + It 'Throws an exception if RequestBody is set on a method that does not allow it' { + $route = @{ + Method = 'GET' + OpenApi = @{} + } + $requestBody = @{ Content = 'application/json' } + + { + Set-PodeOARequest -Route $route -RequestBody $requestBody + } | Should -Throw -ExpectedMessage ($PodeLocale.getRequestBodyNotAllowedExceptionMessage -f 'GET') + } + + It 'Returns the route when PassThru is used' { + $route = @{ + Method = 'POST' + OpenApi = @{} + } + + $result = Set-PodeOARequest -Route $route -PassThru + + $result | Should -BeExactly $route + } + + It 'Does not set RequestBody if not provided' { + $route = @{ + Method = 'PUT' + OpenApi = @{} + } + + Set-PodeOARequest -Route $route + + $route.OpenApi.RequestBody | Should -BeNullOrEmpty + } + } + + Context 'Pet Object example' { BeforeEach { From d4544e55b64a1373753e9965670d015470912d83 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Wed, 28 Aug 2024 22:19:17 +0100 Subject: [PATCH 134/177] #1291: rewrite of socket receiver to resolve NET8 SSL I/O changes --- examples/sse.ps1 | 4 +- examples/web-pages-https.ps1 | 5 + examples/web-pages.ps1 | 14 +-- src/Listener/Pode.csproj | 1 + src/Listener/PodeConnector.cs | 3 +- src/Listener/PodeContext.cs | 158 +++++++++---------------- src/Listener/PodeEndpoint.cs | 6 +- src/Listener/PodeFileWatcher.cs | 10 +- src/Listener/PodeForm.cs | 2 +- src/Listener/PodeFormData.cs | 10 +- src/Listener/PodeHelpers.cs | 37 +++++- src/Listener/PodeHttpRequest.cs | 161 +++++++++++++------------ src/Listener/PodeListener.cs | 22 ++-- src/Listener/PodeReceiver.cs | 12 +- src/Listener/PodeRequest.cs | 169 +++++++++++++++------------ src/Listener/PodeResponse.cs | 99 ++++++++-------- src/Listener/PodeSignalRequest.cs | 14 ++- src/Listener/PodeSmtpRequest.cs | 72 ++++++------ src/Listener/PodeSocket.cs | 156 +++++++------------------ src/Listener/PodeTcpRequest.cs | 31 ++--- src/Listener/PodeWatcher.cs | 4 +- src/Listener/PodeWebSocket.cs | 57 ++++----- src/Listener/PodeWebSocketRequest.cs | 4 +- src/Private/PodeServer.ps1 | 2 +- src/Public/Responses.ps1 | 2 +- src/Public/SSE.ps1 | 4 +- src/Public/WebSockets.ps1 | 8 +- 27 files changed, 500 insertions(+), 567 deletions(-) diff --git a/examples/sse.ps1 b/examples/sse.ps1 index 0fa57b0bd..564e97696 100644 --- a/examples/sse.ps1 +++ b/examples/sse.ps1 @@ -15,9 +15,9 @@ Start-PodeServer -Threads 3 { # open local sse connection, and send back data Add-PodeRoute -Method Get -Path '/data' -ScriptBlock { ConvertTo-PodeSseConnection -Name 'Data' -Scope Local - Send-PodeSseEvent -Id 1234 -EventType Action -Data 'hello, there!' + Send-PodeSseEvent -Id 1234 -EventType Action -Data 'hello, there!' -FromEvent Start-Sleep -Seconds 3 - Send-PodeSseEvent -Id 1337 -EventType BoldOne -Data 'general kenobi' + Send-PodeSseEvent -Id 1337 -EventType BoldOne -Data 'general kenobi' -FromEvent } # home page to get sse events diff --git a/examples/web-pages-https.ps1 b/examples/web-pages-https.ps1 index a62a40c28..5a61ef689 100644 --- a/examples/web-pages-https.ps1 +++ b/examples/web-pages-https.ps1 @@ -11,6 +11,7 @@ Import-Module "$($path)/src/Pode.psm1" -Force -ErrorAction Stop # create a server, flagged to generate a self-signed cert for dev/testing Start-PodeServer { + New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging -Levels Error # bind to ip/port and set as https with self-signed cert Add-PodeEndpoint -Address * -Port 8443 -Protocol Https -SelfSigned @@ -31,4 +32,8 @@ Start-PodeServer { Set-PodeResponseStatus -Code 500 } + Add-PodeRoute -Method 'GET' -Path '/test' -ScriptBlock { + Write-PodeTextResponse -Value (Get-Date) + } + } diff --git a/examples/web-pages.ps1 b/examples/web-pages.ps1 index 2d1dcb53b..76d7bf98d 100644 --- a/examples/web-pages.ps1 +++ b/examples/web-pages.ps1 @@ -10,22 +10,22 @@ Import-Module "$($path)/src/Pode.psm1" -Force -ErrorAction Stop # Import-Module Pode # create a server, and start listening on port 8085 -Start-PodeServer -Threads 2 -Verbose { +Start-PodeServer -Threads 1 -Verbose { # listen on localhost:8085 Add-PodeEndpoint -Address * -Port 8090 -Protocol Http -Name '8090Address' Add-PodeEndpoint -Address * -Port $Port -Protocol Http -Name '8085Address' -RedirectTo '8090Address' # allow the local ip and some other ips - Add-PodeAccessRule -Access Allow -Type IP -Values @('127.0.0.1', '[::1]') - Add-PodeAccessRule -Access Allow -Type IP -Values @('192.169.0.1', '192.168.0.2') + # Add-PodeAccessRule -Access Allow -Type IP -Values @('127.0.0.1', '[::1]') + # Add-PodeAccessRule -Access Allow -Type IP -Values @('192.169.0.1', '192.168.0.2') # deny an ip - Add-PodeAccessRule -Access Deny -Type IP -Values 10.10.10.10 - Add-PodeAccessRule -Access Deny -Type IP -Values '10.10.0.0/24' - Add-PodeAccessRule -Access Deny -Type IP -Values all + # Add-PodeAccessRule -Access Deny -Type IP -Values 10.10.10.10 + # Add-PodeAccessRule -Access Deny -Type IP -Values '10.10.0.0/24' + # Add-PodeAccessRule -Access Deny -Type IP -Values all # limit - Add-PodeLimitRule -Type IP -Values all -Limit 100 -Seconds 5 + # Add-PodeLimitRule -Type IP -Values all -Limit 100 -Seconds 5 # log requests to the terminal New-PodeLoggingMethod -Terminal -Batch 10 -BatchTimeout 10 | Enable-PodeRequestLogging diff --git a/src/Listener/Pode.csproj b/src/Listener/Pode.csproj index ad20a3158..ee7d5af90 100644 --- a/src/Listener/Pode.csproj +++ b/src/Listener/Pode.csproj @@ -2,5 +2,6 @@ netstandard2.0;net6.0;net8.0 $(NoWarn);SYSLIB0001 + 9.0 diff --git a/src/Listener/PodeConnector.cs b/src/Listener/PodeConnector.cs index be7a3d5a8..b75aff220 100644 --- a/src/Listener/PodeConnector.cs +++ b/src/Listener/PodeConnector.cs @@ -15,9 +15,8 @@ public class PodeConnector : IDisposable { CancellationToken = cancellationToken == default(CancellationToken) ? cancellationToken - : (new CancellationTokenSource()).Token; + : new CancellationTokenSource().Token; - // IsConnected = true; IsDisposed = false; } diff --git a/src/Listener/PodeContext.cs b/src/Listener/PodeContext.cs index a2de17fe5..66ed462a7 100644 --- a/src/Listener/PodeContext.cs +++ b/src/Listener/PodeContext.cs @@ -5,6 +5,7 @@ using System.Net.Sockets; using System.Security.Cryptography; using System.Threading; +using System.Threading.Tasks; namespace Pode { @@ -18,13 +19,9 @@ public class PodeContext : PodeProtocol, IDisposable public PodeSocket PodeSocket { get; private set; } public DateTime Timestamp { get; private set; } public Hashtable Data { get; private set; } + public string EndpointName => PodeSocket.Name; - public string EndpointName - { - get => PodeSocket.Name; - } - - private object _lockable = new object(); + private object _lockable = new(); private PodeContextState _state; public PodeContextState State @@ -39,73 +36,25 @@ private set } } - public bool CloseImmediately - { - get => (State == PodeContextState.Error + public bool CloseImmediately => State == PodeContextState.Error || State == PodeContextState.Closing || State == PodeContextState.Timeout - || Request.CloseImmediately); - } - - public new bool IsWebSocket - { - get => (base.IsWebSocket || (base.IsUnknown && PodeSocket.IsWebSocket)); - } - - public bool IsWebSocketUpgraded - { - get => (IsWebSocket && Request is PodeSignalRequest); - } - - public new bool IsSmtp - { - get => (base.IsSmtp || (base.IsUnknown && PodeSocket.IsSmtp)); - } - - public new bool IsHttp - { - get => (base.IsHttp || (base.IsUnknown && PodeSocket.IsHttp)); - } - - public PodeSmtpRequest SmtpRequest - { - get => (PodeSmtpRequest)Request; - } - - public PodeHttpRequest HttpRequest - { - get => (PodeHttpRequest)Request; - } + || Request.CloseImmediately; - public PodeSignalRequest SignalRequest - { - get => (PodeSignalRequest)Request; - } - - public bool IsKeepAlive - { - get => ((Request.IsKeepAlive && Response.SseScope != PodeSseScope.Local) || Response.SseScope == PodeSseScope.Global); - } - - public bool IsErrored - { - get => (State == PodeContextState.Error || State == PodeContextState.SslError); - } + public new bool IsWebSocket => base.IsWebSocket || (IsUnknown && PodeSocket.IsWebSocket); + public bool IsWebSocketUpgraded => IsWebSocket && Request is PodeSignalRequest; + public new bool IsSmtp => base.IsSmtp || (IsUnknown && PodeSocket.IsSmtp); + public new bool IsHttp => base.IsHttp || (IsUnknown && PodeSocket.IsHttp); - public bool IsTimeout - { - get => (State == PodeContextState.Timeout); - } + public PodeSmtpRequest SmtpRequest => (PodeSmtpRequest)Request; + public PodeHttpRequest HttpRequest => (PodeHttpRequest)Request; + public PodeSignalRequest SignalRequest => (PodeSignalRequest)Request; - public bool IsClosed - { - get => (State == PodeContextState.Closed); - } - - public bool IsOpened - { - get => (State == PodeContextState.Open); - } + public bool IsKeepAlive => (Request.IsKeepAlive && Response.SseScope != PodeSseScope.Local) || Response.SseScope == PodeSseScope.Global; + public bool IsErrored => State == PodeContextState.Error || State == PodeContextState.SslError; + public bool IsTimeout => State == PodeContextState.Timeout; + public bool IsClosed => State == PodeContextState.Closed; + public bool IsOpened => State == PodeContextState.Open; public CancellationTokenSource ContextTimeoutToken { get; private set; } private Timer TimeoutTimer; @@ -121,14 +70,17 @@ public PodeContext(Socket socket, PodeSocket podeSocket, PodeListener listener) Type = PodeProtocolType.Unknown; State = PodeContextState.New; + } + public async Task Initialise() + { NewResponse(); - NewRequest(); + await NewRequest().ConfigureAwait(false); } private void TimeoutCallback(object state) { - if (Response.SseEnabled) + if (Response.SseEnabled || Request.IsWebSocket) { return; } @@ -140,54 +92,51 @@ private void TimeoutCallback(object state) Request.Error = new HttpRequestException("Request timeout"); Request.Error.Data.Add("PodeStatusCode", 408); - this.Dispose(); + Dispose(); } private void NewResponse() { - Response = new PodeResponse(); - Response.SetContext(this); + Response = new PodeResponse(this); } - private void NewRequest() + private async Task NewRequest() { // create a new request switch (PodeSocket.Type) { case PodeProtocolType.Smtp: - Request = new PodeSmtpRequest(Socket, PodeSocket); + Request = new PodeSmtpRequest(Socket, PodeSocket, this); break; case PodeProtocolType.Tcp: - Request = new PodeTcpRequest(Socket, PodeSocket); + Request = new PodeTcpRequest(Socket, PodeSocket, this); break; default: - Request = new PodeHttpRequest(Socket, PodeSocket); + Request = new PodeHttpRequest(Socket, PodeSocket, this); break; } - Request.SetContext(this); - // attempt to open the request stream try { - Request.Open(); + await Request.Open(CancellationToken.None).ConfigureAwait(false); State = PodeContextState.Open; } catch (AggregateException aex) { PodeHelpers.HandleAggregateException(aex, Listener, PodeLoggingLevel.Debug, true); - State = (Request.InputStream == default(Stream) + State = Request.InputStream == default(Stream) ? PodeContextState.Error - : PodeContextState.SslError); + : PodeContextState.SslError; } catch (Exception ex) { PodeHelpers.WriteException(ex, Listener, PodeLoggingLevel.Debug); - State = (Request.InputStream == default(Stream) + State = Request.InputStream == default(Stream) ? PodeContextState.Error - : PodeContextState.SslError); + : PodeContextState.SslError; } // if request is SMTP or TCP, send ACK if available @@ -195,11 +144,11 @@ private void NewRequest() { if (PodeSocket.IsSmtp) { - SmtpRequest.SendAck(); + await SmtpRequest.SendAck().ConfigureAwait(false); } else if (PodeSocket.IsTcp && !string.IsNullOrWhiteSpace(PodeSocket.AcknowledgeMessage)) { - Response.WriteLine(PodeSocket.AcknowledgeMessage, true); + await Response.WriteLine(PodeSocket.AcknowledgeMessage, true).ConfigureAwait(false); } } } @@ -261,21 +210,17 @@ private void SetContextType() } } - public void RenewTimeoutToken() - { - ContextTimeoutToken = new CancellationTokenSource(); - } - public void CancelTimeout() { TimeoutTimer.Dispose(); } - public async void Receive() + public async Task Receive() { try { // start timeout + ContextTimeoutToken = new CancellationTokenSource(); TimeoutTimer = new Timer(TimeoutCallback, null, Listener.RequestTimeout * 1000, Timeout.Infinite); // start receiving @@ -283,9 +228,9 @@ public async void Receive() try { PodeHelpers.WriteErrorMessage($"Receiving request", Listener, PodeLoggingLevel.Verbose, this); - var close = await Request.Receive(ContextTimeoutToken.Token); + var close = await Request.Receive(ContextTimeoutToken.Token).ConfigureAwait(false); SetContextType(); - EndReceive(close); + await EndReceive(close).ConfigureAwait(false); } catch (OperationCanceledException) { } } @@ -293,11 +238,11 @@ public async void Receive() { PodeHelpers.WriteException(ex, Listener, PodeLoggingLevel.Debug); State = PodeContextState.Error; - PodeSocket.HandleContext(this); + await PodeSocket.HandleContext(this).ConfigureAwait(false); } } - public void EndReceive(bool close) + public async Task EndReceive(bool close) { State = close ? PodeContextState.Closing : PodeContextState.Received; if (close) @@ -305,7 +250,7 @@ public void EndReceive(bool close) Response.StatusCode = 400; } - PodeSocket.HandleContext(this); + await PodeSocket.HandleContext(this).ConfigureAwait(false); } public void StartReceive() @@ -316,7 +261,7 @@ public void StartReceive() PodeHelpers.WriteErrorMessage($"Socket listening", Listener, PodeLoggingLevel.Verbose, this); } - public void UpgradeWebSocket(string clientId = null) + public async Task UpgradeWebSocket(string clientId = null) { PodeHelpers.WriteErrorMessage($"Upgrading Websocket", Listener, PodeLoggingLevel.Verbose, this); @@ -355,7 +300,7 @@ public void UpgradeWebSocket(string clientId = null) } // send message to upgrade web socket - Response.Send(); + await Response.Send().ConfigureAwait(false); // add open web socket to listener var signal = new PodeSignal(this, HttpRequest.Url.AbsolutePath, clientId); @@ -373,10 +318,12 @@ public void Dispose(bool force) { lock (_lockable) { + PodeHelpers.WriteErrorMessage($"Disposing Context", Listener, PodeLoggingLevel.Verbose, this); Listener.RemoveProcessingContext(this); if (IsClosed) { + PodeSocket.RemovePendingSocket(Socket); Request.Dispose(); Response.Dispose(); ContextTimeoutToken.Dispose(); @@ -402,7 +349,7 @@ public void Dispose(bool force) // are we awaiting for more info? if (IsHttp) { - _awaitingBody = (HttpRequest.AwaitingBody && !IsErrored && !IsTimeout); + _awaitingBody = HttpRequest.AwaitingBody && !IsErrored && !IsTimeout; } // only send a response if Http @@ -410,11 +357,11 @@ public void Dispose(bool force) { if (IsTimeout) { - Response.SendTimeout(); + Response.SendTimeout().Wait(); } else { - Response.Send(); + Response.Send().Wait(); } } @@ -431,7 +378,7 @@ public void Dispose(bool force) if (Response.SseEnabled) { - Response.CloseSseConnection(); + Response.CloseSseConnection().Wait(); } Request.Dispose(); @@ -447,8 +394,13 @@ public void Dispose(bool force) // if keep-alive, or awaiting body, setup for re-receive if ((_awaitingBody || (IsKeepAlive && !IsErrored && !IsTimeout && !Response.SseEnabled)) && !force) { + PodeHelpers.WriteErrorMessage($"Re-receiving Request", Listener, PodeLoggingLevel.Verbose, this); StartReceive(); } + else + { + PodeSocket.RemovePendingSocket(Socket); + } } } } diff --git a/src/Listener/PodeEndpoint.cs b/src/Listener/PodeEndpoint.cs index 917dfb643..ceaf167d3 100644 --- a/src/Listener/PodeEndpoint.cs +++ b/src/Listener/PodeEndpoint.cs @@ -1,6 +1,8 @@ using System; using System.Net; using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; namespace Pode { @@ -52,7 +54,7 @@ public void Listen() Socket.Listen(int.MaxValue); } - public bool AcceptAsync(SocketAsyncEventArgs args) + public bool Accept(SocketAsyncEventArgs args) { if (IsDisposed) { @@ -66,7 +68,7 @@ public void Dispose() { IsDisposed = true; PodeSocket.CloseSocket(Socket); - Socket = default(Socket); + Socket = default; } public new bool Equals(object obj) diff --git a/src/Listener/PodeFileWatcher.cs b/src/Listener/PodeFileWatcher.cs index da1249cdb..941b78be6 100644 --- a/src/Listener/PodeFileWatcher.cs +++ b/src/Listener/PodeFileWatcher.cs @@ -16,10 +16,12 @@ public PodeFileWatcher(string name, string path, bool includeSubdirectories, int { Name = name; - FileWatcher = new RecoveringFileSystemWatcher(path); - FileWatcher.IncludeSubdirectories = includeSubdirectories; - FileWatcher.InternalBufferSize = internalBufferSize; - FileWatcher.NotifyFilter = notifyFilters; + FileWatcher = new RecoveringFileSystemWatcher(path) + { + IncludeSubdirectories = includeSubdirectories, + InternalBufferSize = internalBufferSize, + NotifyFilter = notifyFilters + }; EventsRegistered = new HashSet(); RegisterEvent(PodeFileWatcherChangeType.Errored); diff --git a/src/Listener/PodeForm.cs b/src/Listener/PodeForm.cs index 5bfe7e170..b740e06c6 100644 --- a/src/Listener/PodeForm.cs +++ b/src/Listener/PodeForm.cs @@ -202,7 +202,7 @@ private static bool IsLineBoundary(byte[] bytes, string boundary, Encoding conte return false; } - return (contentEncoding.GetString(bytes).StartsWith(boundary)); + return contentEncoding.GetString(bytes).StartsWith(boundary); } public static bool IsLineBoundary(string line, string boundary) diff --git a/src/Listener/PodeFormData.cs b/src/Listener/PodeFormData.cs index 09e1dcf76..487fe8dda 100644 --- a/src/Listener/PodeFormData.cs +++ b/src/Listener/PodeFormData.cs @@ -11,15 +11,17 @@ public class PodeFormData public string[] Values => _values.ToArray(); public int Count => _values.Count; - public bool IsSingular => (_values.Count == 1); - public bool IsEmpty => (_values.Count == 0); + public bool IsSingular => _values.Count == 1; + public bool IsEmpty => _values.Count == 0; public PodeFormData(string key, string value) { Key = key; - _values = new List(); - _values.Add(value); + _values = new List + { + value + }; } public void AddValue(string value) diff --git a/src/Listener/PodeHelpers.cs b/src/Listener/PodeHelpers.cs index bb68f6742..44a7e8f95 100644 --- a/src/Listener/PodeHelpers.cs +++ b/src/Listener/PodeHelpers.cs @@ -5,6 +5,8 @@ using System.Security.Cryptography; using System.Reflection; using System.Runtime.Versioning; +using System.Threading.Tasks; +using System.Threading; namespace Pode { @@ -13,12 +15,14 @@ public class PodeHelpers public static readonly string[] HTTP_METHODS = new string[] { "CONNECT", "DELETE", "GET", "HEAD", "MERGE", "OPTIONS", "PATCH", "POST", "PUT", "TRACE" }; public const string WEB_SOCKET_MAGIC_KEY = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; public readonly static char[] NEW_LINE_ARRAY = new char[] { '\r', '\n' }; + public readonly static char[] SPACE_ARRAY = new char[] { ' ' }; public const string NEW_LINE = "\r\n"; public const string NEW_LINE_UNIX = "\n"; public const int BYTE_SIZE = sizeof(byte); public const byte NEW_LINE_BYTE = 10; public const byte CARRIAGE_RETURN_BYTE = 13; public const byte DASH_BYTE = 45; + public const byte PERIOD_BYTE = 46; private static string _dotnet_version = string.Empty; private static bool _is_net_framework = false; @@ -26,7 +30,7 @@ public static bool IsNetFramework { get { - if (String.IsNullOrWhiteSpace(_dotnet_version)) + if (string.IsNullOrWhiteSpace(_dotnet_version)) { _dotnet_version = Assembly.GetEntryAssembly()?.GetCustomAttribute()?.FrameworkName ?? "Framework"; _is_net_framework = _dotnet_version.Equals("Framework", StringComparison.InvariantCultureIgnoreCase); @@ -71,7 +75,7 @@ public static bool IsNetFramework return true; } - PodeHelpers.WriteException(ex, connector, level); + WriteException(ex, connector, level); return false; }); } @@ -114,27 +118,50 @@ public static string NewGuid(int length = 16) { var bytes = new byte[length]; rnd.GetBytes(bytes); - return (new Guid(bytes)).ToString(); + return new Guid(bytes).ToString(); } } - public static void WriteTo(MemoryStream stream, byte[] array, int startIndex, int count = 0) + public static async Task WriteTo(MemoryStream stream, byte[] array, int startIndex, int count, CancellationToken cancellationToken) { + // Validate startIndex and count to avoid unnecessary work + if (startIndex < 0 || startIndex > array.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + if (count <= 0 || startIndex + count > array.Length) { count = array.Length - startIndex; } - stream.Write(array, startIndex, count); + // Perform the asynchronous write operation + if (count > 0) + { + await stream.WriteAsync(array, startIndex, count, cancellationToken).ConfigureAwait(false); + } } public static byte[] Slice(byte[] array, int startIndex, int count = 0) { + // Validate startIndex and adjust count if needed + if (startIndex < 0 || startIndex > array.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + // If count is zero or less, or exceeds the array bounds, adjust it if (count <= 0 || startIndex + count > array.Length) { count = array.Length - startIndex; } + // If the count is zero, return an empty array + if (count == 0) + { + return Array.Empty(); + } + var newArray = new byte[count]; Buffer.BlockCopy(array, startIndex * BYTE_SIZE, newArray, 0, count * BYTE_SIZE); return newArray; diff --git a/src/Listener/PodeHttpRequest.cs b/src/Listener/PodeHttpRequest.cs index 54b6ffbd4..2d713eb67 100644 --- a/src/Listener/PodeHttpRequest.cs +++ b/src/Listener/PodeHttpRequest.cs @@ -5,10 +5,11 @@ using System.Net.Http; using System.Net.Sockets; using System.Text; -using System.Text.RegularExpressions; using System.Web; using System.Linq; using System.IO; +using System.Threading; +using System.Threading.Tasks; namespace Pode { @@ -58,17 +59,17 @@ public string Body public override bool CloseImmediately { - get => (string.IsNullOrWhiteSpace(HttpMethod) - || (IsWebSocket && !HttpMethod.Equals("GET", StringComparison.InvariantCultureIgnoreCase))); + get => string.IsNullOrWhiteSpace(HttpMethod) + || (IsWebSocket && !HttpMethod.Equals("GET", StringComparison.InvariantCultureIgnoreCase)); } public override bool IsProcessable { - get => (!CloseImmediately && !AwaitingBody); + get => !CloseImmediately && !AwaitingBody; } - public PodeHttpRequest(Socket socket, PodeSocket podeSocket) - : base(socket, podeSocket) + public PodeHttpRequest(Socket socket, PodeSocket podeSocket, PodeContext context) + : base(socket, podeSocket, context) { Protocol = "HTTP/1.1"; Type = PodeProtocolType.Http; @@ -85,12 +86,11 @@ protected override bool ValidateInput(byte[] bytes) // wait until we have the rest of the payload if (AwaitingBody) { - return (bytes.Length >= (ContentLength - BodyStream.Length)); + return bytes.Length >= (ContentLength - BodyStream.Length); } - var lf = (byte)10; var previousIndex = -1; - var index = Array.IndexOf(bytes, lf); + var index = Array.IndexOf(bytes, PodeHelpers.NEW_LINE_BYTE); // do we have a request line yet? if (index == -1) @@ -102,7 +102,8 @@ protected override bool ValidateInput(byte[] bytes) if (!IsRequestLineValid) { var reqLine = Encoding.GetString(bytes, 0, index).Trim(); - var reqMeta = Regex.Split(reqLine, "\\s+"); + var reqMeta = reqLine.Split(PodeHelpers.SPACE_ARRAY, StringSplitOptions.RemoveEmptyEntries); + if (reqMeta.Length != 3) { throw new HttpRequestException($"Invalid request line: {reqLine} [{reqMeta.Length}]"); @@ -115,27 +116,17 @@ protected override bool ValidateInput(byte[] bytes) while (true) { previousIndex = index; - index = Array.IndexOf(bytes, lf, index + 1); + index = Array.IndexOf(bytes, PodeHelpers.NEW_LINE_BYTE, index + 1); - if (index - previousIndex <= 2) - { - if (index - previousIndex == 1) - { - break; - } - - if (bytes[previousIndex + 1] == (byte)13) - { - break; - } - } - - if (index == bytes.Length - 1) + // If the difference between indexes indicates the end of headers, exit the loop + if (index == previousIndex + 1 || + (index > previousIndex + 1 && bytes[previousIndex + 1] == PodeHelpers.CARRIAGE_RETURN_BYTE)) { break; } - if (index == -1) + // Return false if LF not found and end of array is reached + if (index == -1 || index >= bytes.Length - 1) { return false; } @@ -146,7 +137,7 @@ protected override bool ValidateInput(byte[] bytes) return true; } - protected override bool Parse(byte[] bytes) + protected override async Task Parse(byte[] bytes, CancellationToken cancellationToken) { // if there are no bytes, return (0 bytes read means we can close the socket) if (bytes.Length == 0) @@ -168,14 +159,14 @@ protected override bool Parse(byte[] bytes) var reqLines = content.Split(new string[] { newline }, StringSplitOptions.None); content = string.Empty; - bodyIndex = ParseHeaders(reqLines, newline); + bodyIndex = ParseHeaders(reqLines); bodyIndex = reqLines.Take(bodyIndex).Sum(x => x.Length) + (bodyIndex * newline.Length); - reqLines = default(string[]); + reqLines = default; } // parse the body - ParseBody(bytes, newline, bodyIndex); - AwaitingBody = (ContentLength > 0 && BodyStream.Length < ContentLength && Error == default(HttpRequestException)); + await ParseBody(bytes, newline, bodyIndex, cancellationToken).ConfigureAwait(false); + AwaitingBody = ContentLength > 0 && BodyStream.Length < ContentLength && Error == default(HttpRequestException); if (!AwaitingBody) { @@ -184,21 +175,21 @@ protected override bool Parse(byte[] bytes) if (BodyStream != default(MemoryStream)) { BodyStream.Dispose(); - BodyStream = default(MemoryStream); + BodyStream = default; } } - return (!AwaitingBody); + return !AwaitingBody; } - private int ParseHeaders(string[] reqLines, string newline) + private int ParseHeaders(string[] reqLines) { // reset raw body - RawBody = default(byte[]); + RawBody = default; _body = string.Empty; // first line is method/url - var reqMeta = Regex.Split(reqLines[0].Trim(), "\\s+"); + var reqMeta = reqLines[0].Trim().Split(' '); if (reqMeta.Length != 3) { throw new HttpRequestException($"Invalid request line: {reqLines[0]} [{reqMeta.Length}]"); @@ -206,18 +197,18 @@ private int ParseHeaders(string[] reqLines, string newline) // http method HttpMethod = reqMeta[0].Trim(); - if (Array.IndexOf(PodeHelpers.HTTP_METHODS, HttpMethod) == -1) + if (!PodeHelpers.HTTP_METHODS.Contains(HttpMethod)) { throw new HttpRequestException($"Invalid request HTTP method: {HttpMethod}"); } // query string var reqQuery = reqMeta[1].Trim(); - var qmIndex = string.IsNullOrEmpty(reqQuery) ? 0 : reqQuery.IndexOf("?"); + var qmIndex = reqQuery.IndexOf("?"); QueryString = qmIndex > 0 - ? HttpUtility.ParseQueryString(reqQuery.Substring(qmIndex)) - : default(NameValueCollection); + ? HttpUtility.ParseQueryString(reqQuery.Substring(qmIndex + 1)) + : default; // http protocol version Protocol = (reqMeta[2] ?? "HTTP/1.1").Trim(); @@ -226,7 +217,7 @@ private int ParseHeaders(string[] reqLines, string newline) throw new HttpRequestException($"Invalid request version: {Protocol}"); } - ProtocolVersion = Regex.Split(Protocol, "/")[1]; + ProtocolVersion = Protocol.Split('/')[1]; // headers Headers = new Hashtable(StringComparer.InvariantCultureIgnoreCase); @@ -246,38 +237,41 @@ private int ParseHeaders(string[] reqLines, string newline) } h_index = h_line.IndexOf(":"); - h_name = h_line.Substring(0, h_index).Trim(); - h_value = h_line.Substring(h_index + 1).Trim(); - Headers.Add(h_name, h_value); + if (h_index > 0) + { + h_name = h_line.Substring(0, h_index).Trim(); + h_value = h_line.Substring(h_index + 1).Trim(); + Headers.Add(h_name, h_value); + } } // build required URI details - var _proto = (IsSsl ? "https" : "http"); - Host = $"{Headers["Host"]}"; - Url = new Uri($"{_proto}://{Host}{reqQuery}"); + var _proto = IsSsl ? "https" : "http"; + Host = Headers["Host"]?.ToString(); // check the host header - if (!Context.PodeSocket.CheckHostname(Host)) + if (string.IsNullOrWhiteSpace(Host) || !Context.PodeSocket.CheckHostname(Host)) { - throw new HttpRequestException($"Invalid request Host: {Host}"); + throw new HttpRequestException($"Invalid Host header: {Host}"); } + // build the URL + Url = new Uri($"{_proto}://{Host}{reqQuery}"); + // get the content length - var strContentLength = $"{Headers["Content-Length"]}"; - if (string.IsNullOrWhiteSpace(strContentLength)) + ContentLength = 0; + if (int.TryParse(Headers["Content-Length"]?.ToString(), out int _contentLength)) { - strContentLength = "0"; + ContentLength = _contentLength; } - ContentLength = int.Parse(strContentLength); - // set the transfer encoding - TransferEncoding = $"{Headers["Transfer-Encoding"]}"; + TransferEncoding = Headers["Transfer-Encoding"]?.ToString(); // set other default headers - UrlReferrer = $"{Headers["Referer"]}"; - UserAgent = $"{Headers["User-Agent"]}"; - ContentType = $"{Headers["Content-Type"]}"; + UrlReferrer = Headers["Referer"]?.ToString(); + UserAgent = Headers["User-Agent"]?.ToString(); + ContentType = Headers["Content-Type"]?.ToString(); // set content encoding ContentEncoding = System.Text.Encoding.UTF8; @@ -286,9 +280,9 @@ private int ParseHeaders(string[] reqLines, string newline) var atoms = ContentType.Split(';'); foreach (var atom in atoms) { - if (atom.Trim().ToLowerInvariant().StartsWith("charset")) + if (atom.Trim().StartsWith("charset", StringComparison.InvariantCultureIgnoreCase)) { - ContentEncoding = System.Text.Encoding.GetEncoding((atom.Split('=')[1].Trim())); + ContentEncoding = System.Text.Encoding.GetEncoding(atom.Split('=')[1].Trim()); break; } } @@ -301,30 +295,29 @@ private int ParseHeaders(string[] reqLines, string newline) } // do we have an SSE ClientId? - SseClientId = $"{Headers["X-Pode-Sse-Client-Id"]}"; + SseClientId = Headers["X-Pode-Sse-Client-Id"]?.ToString(); if (HasSseClientId) { - SseClientName = $"{Headers["X-Pode-Sse-Name"]}"; - SseClientGroup = $"{Headers["X-Pode-Sse-Group"]}"; + SseClientName = Headers["X-Pode-Sse-Name"]?.ToString(); + SseClientGroup = Headers["X-Pode-Sse-Group"]?.ToString(); } // keep-alive? - IsKeepAlive = (IsWebSocket || + IsKeepAlive = IsWebSocket || (Headers.ContainsKey("Connection") - && $"{Headers["Connection"]}".Equals("keep-alive", StringComparison.InvariantCultureIgnoreCase))); + && Headers["Connection"]?.ToString().Equals("keep-alive", StringComparison.InvariantCultureIgnoreCase) == true); // return index where body starts in req return bodyIndex; } - private void ParseBody(byte[] bytes, string newline, int start) + private async Task ParseBody(byte[] bytes, string newline, int start, CancellationToken cancellationToken) { - if (BodyStream == default(MemoryStream)) - { - BodyStream = new MemoryStream(); - } + // set the body stream + BodyStream ??= new MemoryStream(); - var isChunked = (!string.IsNullOrWhiteSpace(TransferEncoding) && TransferEncoding.Contains("chunked")); + // are we chunked? + var isChunked = !string.IsNullOrWhiteSpace(TransferEncoding) && TransferEncoding.Contains("chunked"); // if chunked, and we have a content-length, fail if (isChunked && ContentLength > 0) @@ -346,12 +339,7 @@ private void ParseBody(byte[] bytes, string newline, int start) // get index of newline char, read start>index bytes as HEX for length c_index = Array.IndexOf(bytes, (byte)newline[0], start); c_hexBytes = PodeHelpers.Slice(bytes, start, c_index - start); - - c_hex = string.Empty; - foreach (var b in c_hexBytes) - { - c_hex += (char)b; - } + c_hex = Encoding.GetString(c_hexBytes.ToArray()); // if no length, continue c_length = Convert.ToInt32(c_hex, 16); @@ -368,19 +356,19 @@ private void ParseBody(byte[] bytes, string newline, int start) start = (start + c_length - 1) + newline.Length + 1; } - PodeHelpers.WriteTo(BodyStream, c_rawBytes.ToArray(), 0, c_rawBytes.Count); + await PodeHelpers.WriteTo(BodyStream, c_rawBytes.ToArray(), 0, c_rawBytes.Count, cancellationToken).ConfigureAwait(false); } // else use content length else if (ContentLength > 0) { - PodeHelpers.WriteTo(BodyStream, bytes, start, ContentLength); + await PodeHelpers.WriteTo(BodyStream, bytes, start, ContentLength, cancellationToken).ConfigureAwait(false); } // else just read all else { - PodeHelpers.WriteTo(BodyStream, bytes, start); + await PodeHelpers.WriteTo(BodyStream, bytes, start, 0, cancellationToken).ConfigureAwait(false); } // check body size @@ -398,9 +386,20 @@ public void ParseFormData() Form = PodeForm.Parse(RawBody, ContentType, ContentEncoding); } + public override void PartialDispose() + { + if (BodyStream != default(MemoryStream)) + { + BodyStream.Dispose(); + BodyStream = default; + } + + base.PartialDispose(); + } + public override void Dispose() { - RawBody = default(byte[]); + RawBody = default; _body = string.Empty; if (BodyStream != default(MemoryStream)) diff --git a/src/Listener/PodeListener.cs b/src/Listener/PodeListener.cs index f5a1dc655..64d8c1a06 100644 --- a/src/Listener/PodeListener.cs +++ b/src/Listener/PodeListener.cs @@ -46,7 +46,7 @@ public bool ShowServerDetails } } - public PodeListener(CancellationToken cancellationToken = default(CancellationToken)) + public PodeListener(CancellationToken cancellationToken = default) : base(cancellationToken) { Sockets = new List(); @@ -77,12 +77,12 @@ private void Bind(PodeSocket socket) Sockets.Add(socket); } - public PodeContext GetContext(CancellationToken cancellationToken = default(CancellationToken)) + public PodeContext GetContext(CancellationToken cancellationToken = default) { return Contexts.Get(cancellationToken); } - public Task GetContextAsync(CancellationToken cancellationToken = default(CancellationToken)) + public Task GetContextAsync(CancellationToken cancellationToken = default) { return Contexts.GetAsync(cancellationToken); } @@ -137,7 +137,7 @@ public void AddSseConnection(PodeServerEvent sse) public void SendSseEvent(string name, string[] groups, string[] clientIds, string eventType, string data, string id = null) { - Task.Factory.StartNew(() => + Task.Run(async () => { if (!ServerEvents.ContainsKey(name)) { @@ -158,7 +158,7 @@ public void SendSseEvent(string name, string[] groups, string[] clientIds, strin if (ServerEvents[name][clientId].IsForGroup(groups)) { - ServerEvents[name][clientId].Context.Response.SendSseEvent(eventType, data, id); + await ServerEvents[name][clientId].Context.Response.SendSseEvent(eventType, data, id).ConfigureAwait(false); } } }, CancellationToken); @@ -166,7 +166,7 @@ public void SendSseEvent(string name, string[] groups, string[] clientIds, strin public void CloseSseConnection(string name, string[] groups, string[] clientIds) { - Task.Factory.StartNew(() => + Task.Run(async () => { if (!ServerEvents.ContainsKey(name)) { @@ -187,7 +187,7 @@ public void CloseSseConnection(string name, string[] groups, string[] clientIds) if (ServerEvents[name][clientId].IsForGroup(groups)) { - ServerEvents[name][clientId].Context.Response.CloseSseConnection(); + await ServerEvents[name][clientId].Context.Response.CloseSseConnection().ConfigureAwait(false); } } }, CancellationToken); @@ -211,12 +211,12 @@ public bool TestSseConnectionExists(string name, string clientId) return true; } - public PodeServerSignal GetServerSignal(CancellationToken cancellationToken = default(CancellationToken)) + public PodeServerSignal GetServerSignal(CancellationToken cancellationToken = default) { return ServerSignals.Get(cancellationToken); } - public Task GetServerSignalAsync(CancellationToken cancellationToken = default(CancellationToken)) + public Task GetServerSignalAsync(CancellationToken cancellationToken = default) { return ServerSignals.GetAsync(cancellationToken); } @@ -231,12 +231,12 @@ public void RemoveProcessingServerSignal(PodeServerSignal signal) ServerSignals.RemoveProcessing(signal); } - public PodeClientSignal GetClientSignal(CancellationToken cancellationToken = default(CancellationToken)) + public PodeClientSignal GetClientSignal(CancellationToken cancellationToken = default) { return ClientSignals.Get(cancellationToken); } - public Task GetClientSignalAsync(CancellationToken cancellationToken = default(CancellationToken)) + public Task GetClientSignalAsync(CancellationToken cancellationToken = default) { return ClientSignals.GetAsync(cancellationToken); } diff --git a/src/Listener/PodeReceiver.cs b/src/Listener/PodeReceiver.cs index c723e2e2c..21cff8f2c 100644 --- a/src/Listener/PodeReceiver.cs +++ b/src/Listener/PodeReceiver.cs @@ -20,8 +20,10 @@ public class PodeReceiver : PodeConnector Start(); } - public void ConnectWebSocket(string name, string url, string contentType) + public async Task ConnectWebSocket(string name, string url, string contentType) { + var socket = default(PodeWebSocket); + lock (WebSockets) { if (WebSockets.ContainsKey(name)) @@ -29,16 +31,16 @@ public void ConnectWebSocket(string name, string url, string contentType) throw new Exception($"WebSocket connection with name {name} already defined"); } - var socket = new PodeWebSocket(name, url, contentType); - socket.BindReceiver(this); - socket.Connect(); + socket = new PodeWebSocket(name, url, contentType, this); WebSockets.Add(name, socket); } + + await socket.Connect().ConfigureAwait(false); } public PodeWebSocket GetWebSocket(string name) { - return (WebSockets.ContainsKey(name) ? WebSockets[name] : default(PodeWebSocket)); + return WebSockets.ContainsKey(name) ? WebSockets[name] : default; } public void DisconnectWebSocket(string name) diff --git a/src/Listener/PodeRequest.cs b/src/Listener/PodeRequest.cs index e0633e3a7..bc3bfc07e 100644 --- a/src/Listener/PodeRequest.cs +++ b/src/Listener/PodeRequest.cs @@ -30,20 +30,14 @@ public class PodeRequest : PodeProtocol, IDisposable public SslPolicyErrors ClientCertificateErrors { get; set; } public SslProtocols Protocols { get; private set; } public HttpRequestException Error { get; set; } - public bool IsAborted => (Error != default(HttpRequestException)); + public bool IsAborted => Error != default(HttpRequestException); public bool IsDisposed { get; private set; } - public virtual string Address - { - get => (Context.PodeSocket.HasHostnames + public virtual string Address => Context.PodeSocket.HasHostnames ? $"{Context.PodeSocket.Hostname}:{((IPEndPoint)LocalEndPoint).Port}" - : $"{((IPEndPoint)LocalEndPoint).Address}:{((IPEndPoint)LocalEndPoint).Port}"); - } + : $"{((IPEndPoint)LocalEndPoint).Address}:{((IPEndPoint)LocalEndPoint).Port}"; - public virtual string Scheme - { - get => (SslUpgraded ? $"{Context.PodeSocket.Type}s" : $"{Context.PodeSocket.Type}"); - } + public virtual string Scheme => SslUpgraded ? $"{Context.PodeSocket.Type}s" : $"{Context.PodeSocket.Type}"; private Socket Socket; protected PodeContext Context; @@ -53,16 +47,17 @@ public virtual string Scheme private MemoryStream BufferStream; private const int BufferSize = 16384; - public PodeRequest(Socket socket, PodeSocket podeSocket) + public PodeRequest(Socket socket, PodeSocket podeSocket, PodeContext context) { Socket = socket; RemoteEndPoint = socket.RemoteEndPoint; LocalEndPoint = socket.LocalEndPoint; TlsMode = podeSocket.TlsMode; Certificate = podeSocket.Certificate; - IsSsl = (Certificate != default(X509Certificate)); + IsSsl = Certificate != default(X509Certificate); AllowClientCertificate = podeSocket.AllowClientCertificate; Protocols = podeSocket.Protocols; + Context = context; } public PodeRequest(PodeRequest request) @@ -81,7 +76,7 @@ public PodeRequest(PodeRequest request) TlsMode = request.TlsMode; } - public void Open() + public async Task Open(CancellationToken cancellationToken) { // open the socket's stream InputStream = new NetworkStream(Socket, true); @@ -92,20 +87,41 @@ public void Open() } // otherwise, convert the stream to an ssl stream - UpgradeToSSL(); + await UpgradeToSSL(cancellationToken).ConfigureAwait(false); } - public void UpgradeToSSL() + public async Task UpgradeToSSL(CancellationToken cancellationToken) { + // if we've already upgraded, return if (SslUpgraded) { return; } + // create the ssl stream var ssl = new SslStream(InputStream, false, new RemoteCertificateValidationCallback(ValidateCertificateCallback)); - ssl.AuthenticateAsServerAsync(Certificate, AllowClientCertificate, Protocols, false).Wait(Context.Listener.CancellationToken); - InputStream = ssl; - SslUpgraded = true; + + using (cancellationToken.Register(() => ssl.Dispose())) + { + try + { + // authenticate the stream + await ssl.AuthenticateAsServerAsync(Certificate, AllowClientCertificate, Protocols, false).ConfigureAwait(false); + + // if we've upgraded, set the stream + InputStream = ssl; + SslUpgraded = true; + } + catch (OperationCanceledException) { } + catch (IOException) { } + catch (ObjectDisposedException) { } + catch (Exception ex) + { + PodeHelpers.WriteException(ex, Context.Listener, PodeLoggingLevel.Error); + Error = new HttpRequestException(ex.Message, ex); + Error.Data.Add("PodeStatusCode", 502); + } + } } private bool ValidateCertificateCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) @@ -113,69 +129,71 @@ private bool ValidateCertificateCallback(object sender, X509Certificate certific ClientCertificateErrors = sslPolicyErrors; ClientCertificate = certificate == default(X509Certificate) - ? default(X509Certificate2) + ? default : new X509Certificate2(certificate); return true; } - protected async Task BeginRead(byte[] buffer, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - return await Task.Factory.FromAsync(InputStream.BeginRead, InputStream.EndRead, buffer, 0, BufferSize, null); - } - public async Task Receive(CancellationToken cancellationToken) { try { - Error = default(HttpRequestException); + Error = default; Buffer = new byte[BufferSize]; - BufferStream = new MemoryStream(); - - var read = 0; - var close = true; - - while ((read = await BeginRead(Buffer, cancellationToken)) > 0) + using (BufferStream = new MemoryStream()) { - cancellationToken.ThrowIfCancellationRequested(); - BufferStream.Write(Buffer, 0, read); + var close = true; - if (Socket.Available > 0 || !ValidateInput(BufferStream.ToArray())) + while (true) { - continue; - } - - if (!Parse(BufferStream.ToArray())) - { - BufferStream.Dispose(); - BufferStream = new MemoryStream(); - continue; + // read the input stream + var read = await InputStream.ReadAsync(Buffer, 0, BufferSize, cancellationToken).ConfigureAwait(false); + if (read <= 0) + { + break; + } + + // write the buffer to the stream + await BufferStream.WriteAsync(Buffer, 0, read, cancellationToken).ConfigureAwait(false); + + // if we have more data, or the input is invalid, continue + if (Socket.Available > 0 || !ValidateInput(BufferStream.ToArray())) + { + continue; + } + + // parse the buffer + if (!await Parse(BufferStream.ToArray(), cancellationToken).ConfigureAwait(false)) + { + BufferStream.SetLength(0); + continue; + } + + close = false; + break; } - close = false; - break; + return close; } - - cancellationToken.ThrowIfCancellationRequested(); - return close; } + catch (OperationCanceledException) { } + catch (IOException) { } catch (HttpRequestException httpex) { + PodeHelpers.WriteException(httpex, Context.Listener, PodeLoggingLevel.Error); Error = httpex; } catch (Exception ex) { - cancellationToken.ThrowIfCancellationRequested(); + PodeHelpers.WriteException(ex, Context.Listener, PodeLoggingLevel.Error); Error = new HttpRequestException(ex.Message, ex); Error.Data.Add("PodeStatusCode", 400); } finally { - BufferStream.Dispose(); - BufferStream = default(MemoryStream); - Buffer = default(byte[]); + PartialDispose(); } return false; @@ -184,16 +202,21 @@ public async Task Receive(CancellationToken cancellationToken) public async Task Read(byte[] checkBytes, CancellationToken cancellationToken) { var buffer = new byte[BufferSize]; - var bufferStream = new MemoryStream(); - - try + using (var bufferStream = new MemoryStream()) { - var read = 0; - while ((read = await BeginRead(buffer, cancellationToken)) > 0) + while (true) { - cancellationToken.ThrowIfCancellationRequested(); - bufferStream.Write(buffer, 0, read); + // read the input stream + var read = await InputStream.ReadAsync(buffer, 0, BufferSize, cancellationToken).ConfigureAwait(false); + if (read <= 0) + { + break; + } + + // write the buffer to the stream + await bufferStream.WriteAsync(buffer, 0, read, cancellationToken).ConfigureAwait(false); + // if we have more data, or the input is invalid, continue if (Socket.Available > 0 || !ValidateInputInternal(bufferStream.ToArray(), checkBytes)) { continue; @@ -202,15 +225,8 @@ public async Task Read(byte[] checkBytes, CancellationToken cancellation break; } - cancellationToken.ThrowIfCancellationRequested(); return Encoding.GetString(bufferStream.ToArray()).Trim(); } - finally - { - bufferStream.Dispose(); - bufferStream = default(MemoryStream); - buffer = default(byte[]); - } } private bool ValidateInputInternal(byte[] bytes, byte[] checkBytes) @@ -245,7 +261,7 @@ private bool ValidateInputInternal(byte[] bytes, byte[] checkBytes) return true; } - protected virtual bool Parse(byte[] bytes) + protected virtual Task Parse(byte[] bytes, CancellationToken cancellationToken) { throw new NotImplementedException(); } @@ -255,9 +271,15 @@ protected virtual bool ValidateInput(byte[] bytes) return true; } - public void SetContext(PodeContext context) + public virtual void PartialDispose() { - Context = context; + if (BufferStream != default(MemoryStream)) + { + BufferStream.Dispose(); + BufferStream = default; + } + + Buffer = default; } public virtual void Dispose() @@ -277,15 +299,10 @@ public virtual void Dispose() if (InputStream != default(Stream)) { InputStream.Dispose(); - InputStream = default(Stream); - } - - if (BufferStream != default(MemoryStream)) - { - BufferStream.Dispose(); - BufferStream = default(MemoryStream); + InputStream = default; } + PartialDispose(); PodeHelpers.WriteErrorMessage($"Request disposed", Context.Listener, PodeLoggingLevel.Verbose, Context); } } diff --git a/src/Listener/PodeResponse.cs b/src/Listener/PodeResponse.cs index 3c42a9865..786545994 100644 --- a/src/Listener/PodeResponse.cs +++ b/src/Listener/PodeResponse.cs @@ -5,6 +5,7 @@ using System.IO; using System.Net; using System.Text; +using System.Threading.Tasks; namespace Pode { @@ -77,13 +78,14 @@ public string HttpResponseLine private static UTF8Encoding Encoding = new UTF8Encoding(); - public PodeResponse() + public PodeResponse(PodeContext context) { Headers = new PodeResponseHeaders(); OutputStream = new MemoryStream(); + Context = context; } - public void Send() + public async Task Send() { if (Sent || IsDisposed || (SentHeaders && SseEnabled)) { @@ -94,12 +96,12 @@ public void Send() try { - SendHeaders(Context.IsTimeout); - SendBody(Context.IsTimeout); + await SendHeaders(Context.IsTimeout).ConfigureAwait(false); + await SendBody(Context.IsTimeout).ConfigureAwait(false); PodeHelpers.WriteErrorMessage($"Response sent", Context.Listener, PodeLoggingLevel.Verbose, Context); } - catch (OperationCanceledException) {} - catch (IOException) {} + catch (OperationCanceledException) { } + catch (IOException) { } catch (AggregateException aex) { PodeHelpers.HandleAggregateException(aex, Context.Listener); @@ -111,11 +113,11 @@ public void Send() } finally { - Flush(); + await Flush().ConfigureAwait(false); } } - public void SendTimeout() + public async Task SendTimeout() { if (SentHeaders || IsDisposed) { @@ -127,11 +129,11 @@ public void SendTimeout() try { - SendHeaders(true); + await SendHeaders(true).ConfigureAwait(false); PodeHelpers.WriteErrorMessage($"Response timed-out sent", Context.Listener, PodeLoggingLevel.Verbose, Context); } - catch (OperationCanceledException) {} - catch (IOException) {} + catch (OperationCanceledException) { } + catch (IOException) { } catch (AggregateException aex) { PodeHelpers.HandleAggregateException(aex, Context.Listener); @@ -143,11 +145,11 @@ public void SendTimeout() } finally { - Flush(); + await Flush().ConfigureAwait(false); } } - private void SendHeaders(bool timeout) + private async Task SendHeaders(bool timeout) { if (SentHeaders || !Request.InputStream.CanWrite) { @@ -164,12 +166,12 @@ private void SendHeaders(bool timeout) // stream response output var buffer = Encoding.GetBytes(BuildHeaders(Headers)); - Request.InputStream.WriteAsync(buffer, 0, buffer.Length).Wait(Context.Listener.CancellationToken); - buffer = default(byte[]); + await Request.InputStream.WriteAsync(buffer, 0, buffer.Length, Context.Listener.CancellationToken).ConfigureAwait(false); + buffer = default; SentHeaders = true; } - private void SendBody(bool timeout) + private async Task SendBody(bool timeout) { if (SentBody || SseEnabled || !Request.InputStream.CanWrite) { @@ -179,21 +181,21 @@ private void SendBody(bool timeout) // stream response output if (!timeout && OutputStream.Length > 0) { - OutputStream.WriteTo(Request.InputStream); + await Task.Run(() => OutputStream.WriteTo(Request.InputStream), Context.Listener.CancellationToken).ConfigureAwait(false); } SentBody = true; } - public void Flush() + public async Task Flush() { if (Request.InputStream.CanWrite) { - Request.InputStream.Flush(); + await Request.InputStream.FlushAsync().ConfigureAwait(false); } } - public string SetSseConnection(PodeSseScope scope, string clientId, string name, string group, int retry, bool allowAllOrigins) + public async Task SetSseConnection(PodeSseScope scope, string clientId, string name, string group, int retry, bool allowAllOrigins) { // do nothing for no scope if (scope == PodeSseScope.None) @@ -231,9 +233,9 @@ public string SetSseConnection(PodeSseScope scope, string clientId, string name, } // send headers, and open event - Send(); - SendSseRetry(retry); - SendSseEvent("pode.open", $"{{\"clientId\":\"{clientId}\",\"group\":\"{group}\",\"name\":\"{name}\"}}"); + await Send().ConfigureAwait(false); + await SendSseRetry(retry).ConfigureAwait(false); + await SendSseEvent("pode.open", $"{{\"clientId\":\"{clientId}\",\"group\":\"{group}\",\"name\":\"{name}\"}}").ConfigureAwait(false); // if global, cache connection in listener if (scope == PodeSseScope.Global) @@ -245,60 +247,60 @@ public string SetSseConnection(PodeSseScope scope, string clientId, string name, return clientId; } - public void CloseSseConnection() + public async Task CloseSseConnection() { - SendSseEvent("pode.close", string.Empty); + await SendSseEvent("pode.close", string.Empty).ConfigureAwait(false); } - public void SendSseEvent(string eventType, string data, string id = null) + public async Task SendSseEvent(string eventType, string data, string id = null) { if (!string.IsNullOrEmpty(id)) { - WriteLine($"id: {id}"); + await WriteLine($"id: {id}").ConfigureAwait(false); } if (!string.IsNullOrEmpty(eventType)) { - WriteLine($"event: {eventType}"); + await WriteLine($"event: {eventType}").ConfigureAwait(false); } - WriteLine($"data: {data}{PodeHelpers.NEW_LINE}", true); + await WriteLine($"data: {data}{PodeHelpers.NEW_LINE}", true).ConfigureAwait(false); } - public void SendSseRetry(int retry) + public async Task SendSseRetry(int retry) { if (retry <= 0) { return; } - WriteLine($"retry: {retry}", true); + await WriteLine($"retry: {retry}", true).ConfigureAwait(false); } - public void SendSignal(PodeServerSignal signal) + public async Task SendSignal(PodeServerSignal signal) { if (!string.IsNullOrEmpty(signal.Value)) { - Write(signal.Value); + await Write(signal.Value).ConfigureAwait(false); } } - public void Write(string message, bool flush = false) + public async Task Write(string message, bool flush = false) { // simple messages if (!Context.IsWebSocket) { - Write(Encoding.GetBytes(message), flush); + await Write(Encoding.GetBytes(message), flush).ConfigureAwait(false); } // web socket message else { - WriteFrame(message, PodeWsOpCode.Text, flush); + await WriteFrame(message, PodeWsOpCode.Text, flush).ConfigureAwait(false); } } - public void WriteFrame(string message, PodeWsOpCode opCode = PodeWsOpCode.Text, bool flush = false) + public async Task WriteFrame(string message, PodeWsOpCode opCode = PodeWsOpCode.Text, bool flush = false) { if (IsDisposed) { @@ -332,15 +334,15 @@ public void WriteFrame(string message, PodeWsOpCode opCode = PodeWsOpCode.Text, } buffer.AddRange(msgBytes); - Write(buffer.ToArray(), flush); + await Write(buffer.ToArray(), flush).ConfigureAwait(false); } - public void WriteLine(string message, bool flush = false) + public async Task WriteLine(string message, bool flush = false) { - Write(Encoding.GetBytes($"{message}{PodeHelpers.NEW_LINE}"), flush); + await Write(Encoding.GetBytes($"{message}{PodeHelpers.NEW_LINE}"), flush).ConfigureAwait(false); } - public void Write(byte[] buffer, bool flush = false) + public async Task Write(byte[] buffer, bool flush = false) { if (Request.IsDisposed || !Request.InputStream.CanWrite) { @@ -349,15 +351,15 @@ public void Write(byte[] buffer, bool flush = false) try { - Request.InputStream.WriteAsync(buffer, 0, buffer.Length).Wait(Context.Listener.CancellationToken); + await Request.InputStream.WriteAsync(buffer, 0, buffer.Length, Context.Listener.CancellationToken).ConfigureAwait(false); if (flush) { - Flush(); + await Flush().ConfigureAwait(false); } } - catch (OperationCanceledException) {} - catch (IOException) {} + catch (OperationCanceledException) { } + catch (IOException) { } catch (AggregateException aex) { PodeHelpers.HandleAggregateException(aex, Context.Listener); @@ -445,11 +447,6 @@ private string BuildHeaders(PodeResponseHeaders headers) return builder.ToString(); } - public void SetContext(PodeContext context) - { - Context = context; - } - public void Dispose() { if (IsDisposed) @@ -462,7 +459,7 @@ public void Dispose() if (OutputStream != default(MemoryStream)) { OutputStream.Dispose(); - OutputStream = default(MemoryStream); + OutputStream = default; } PodeHelpers.WriteErrorMessage($"Response disposed", Context.Listener, PodeLoggingLevel.Verbose, Context); diff --git a/src/Listener/PodeSignalRequest.cs b/src/Listener/PodeSignalRequest.cs index 903a7f35e..f7acc49cb 100644 --- a/src/Listener/PodeSignalRequest.cs +++ b/src/Listener/PodeSignalRequest.cs @@ -1,5 +1,7 @@ using System; using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; namespace Pode { @@ -27,12 +29,12 @@ public string CloseDescription public override bool CloseImmediately { - get => (OpCode == PodeWsOpCode.Close); + get => OpCode == PodeWsOpCode.Close; } public override bool IsProcessable { - get => (!CloseImmediately && OpCode != PodeWsOpCode.Pong && OpCode != PodeWsOpCode.Ping && !string.IsNullOrEmpty(Body)); + get => !CloseImmediately && OpCode != PodeWsOpCode.Pong && OpCode != PodeWsOpCode.Ping && !string.IsNullOrEmpty(Body); } public PodeSignalRequest(PodeHttpRequest request, PodeSignal signal) @@ -42,7 +44,7 @@ public PodeSignalRequest(PodeHttpRequest request, PodeSignal signal) IsKeepAlive = true; Type = PodeProtocolType.Ws; - var _proto = (IsSsl ? "wss" : "ws"); + var _proto = IsSsl ? "wss" : "ws"; Host = request.Host; Url = new Uri($"{_proto}://{request.Url.Authority}{request.Url.PathAndQuery}"); } @@ -52,7 +54,7 @@ public PodeClientSignal NewClientSignal() return new PodeClientSignal(Signal, Body, Context.Listener); } - protected override bool Parse(byte[] bytes) + protected override async Task Parse(byte[] bytes, CancellationToken cancellationToken) { // get the length and op-code var dataLength = bytes[1] - 128; @@ -118,7 +120,7 @@ protected override bool Parse(byte[] bytes) // send back a pong case PodeWsOpCode.Ping: - Context.Response.WriteFrame(string.Empty, PodeWsOpCode.Pong); + await Context.Response.WriteFrame(string.Empty, PodeWsOpCode.Pong).ConfigureAwait(false); break; } @@ -131,7 +133,7 @@ public override void Dispose() if (!IsDisposed) { PodeHelpers.WriteErrorMessage($"Closing Websocket", Context.Listener, PodeLoggingLevel.Verbose, Context); - Context.Response.WriteFrame(string.Empty, PodeWsOpCode.Close); + Context.Response.WriteFrame(string.Empty, PodeWsOpCode.Close).Wait(); } // remove client, and dispose diff --git a/src/Listener/PodeSmtpRequest.cs b/src/Listener/PodeSmtpRequest.cs index 8039d45f3..6bb1290d5 100644 --- a/src/Listener/PodeSmtpRequest.cs +++ b/src/Listener/PodeSmtpRequest.cs @@ -8,6 +8,8 @@ using System.Globalization; using _Encoding = System.Text.Encoding; using System.IO; +using System.Threading.Tasks; +using System.Threading; namespace Pode { @@ -29,17 +31,17 @@ public class PodeSmtpRequest : PodeRequest public override bool CloseImmediately { - get => (Command == PodeSmtpCommand.None || Command == PodeSmtpCommand.Quit); + get => Command == PodeSmtpCommand.None || Command == PodeSmtpCommand.Quit; } private bool _canProcess = false; public override bool IsProcessable { - get => (!CloseImmediately && _canProcess); + get => !CloseImmediately && _canProcess; } - public PodeSmtpRequest(Socket socket, PodeSocket podeSocket) - : base(socket, podeSocket) + public PodeSmtpRequest(Socket socket, PodeSocket podeSocket, PodeContext context) + : base(socket, podeSocket, context) { _canProcess = false; IsKeepAlive = true; @@ -58,13 +60,13 @@ private bool IsCommand(string content, string command) return content.StartsWith(command, true, CultureInfo.InvariantCulture); } - public void SendAck() + public async Task SendAck() { var ack = string.IsNullOrWhiteSpace(Context.PodeSocket.AcknowledgeMessage) ? $"{Context.PodeSocket.Hostname} -- Pode Proxy Server" : Context.PodeSocket.AcknowledgeMessage; - Context.Response.WriteLine($"220 {ack}", true); + await Context.Response.WriteLine($"220 {ack}", true).ConfigureAwait(false); } protected override bool ValidateInput(byte[] bytes) @@ -83,15 +85,15 @@ protected override bool ValidateInput(byte[] bytes) return false; } - return (bytes[bytes.Length - 3] == (byte)46 - && bytes[bytes.Length - 2] == (byte)13 - && bytes[bytes.Length - 1] == (byte)10); + return bytes[bytes.Length - 3] == PodeHelpers.PERIOD_BYTE + && bytes[bytes.Length - 2] == PodeHelpers.CARRIAGE_RETURN_BYTE + && bytes[bytes.Length - 1] == PodeHelpers.NEW_LINE_BYTE; } return true; } - protected override bool Parse(byte[] bytes) + protected override async Task Parse(byte[] bytes, CancellationToken cancellationToken) { // if there are no bytes, return (0 bytes read means we can close the socket) if (bytes.Length == 0) @@ -107,7 +109,7 @@ protected override bool Parse(byte[] bytes) if (string.IsNullOrWhiteSpace(content)) { Command = PodeSmtpCommand.None; - Context.Response.WriteLine("501 Invalid command received", true); + await Context.Response.WriteLine("501 Invalid command received", true).ConfigureAwait(false); return true; } @@ -115,7 +117,7 @@ protected override bool Parse(byte[] bytes) if (IsCommand(content, "QUIT")) { Command = PodeSmtpCommand.Quit; - Context.Response.WriteLine("221 OK", true); + await Context.Response.WriteLine("221 OK", true).ConfigureAwait(false); return true; } @@ -123,7 +125,7 @@ protected override bool Parse(byte[] bytes) if (StartType == PodeSmtpStartType.Ehlo && TlsMode == PodeTlsMode.Explicit && !SslUpgraded && !IsCommand(content, "STARTTLS")) { Command = PodeSmtpCommand.None; - Context.Response.WriteLine("530 Must issue a STARTTLS command first", true); + await Context.Response.WriteLine("530 Must issue a STARTTLS command first", true).ConfigureAwait(false); return true; } @@ -132,7 +134,7 @@ protected override bool Parse(byte[] bytes) { Command = PodeSmtpCommand.Helo; StartType = PodeSmtpStartType.Helo; - Context.Response.WriteLine("250 OK", true); + await Context.Response.WriteLine("250 OK", true).ConfigureAwait(false); return true; } @@ -141,14 +143,14 @@ protected override bool Parse(byte[] bytes) { Command = PodeSmtpCommand.Ehlo; StartType = PodeSmtpStartType.Ehlo; - Context.Response.WriteLine($"250-{Context.PodeSocket.Hostname} hello there", true); + await Context.Response.WriteLine($"250-{Context.PodeSocket.Hostname} hello there", true).ConfigureAwait(false); if (TlsMode == PodeTlsMode.Explicit && !SslUpgraded) { - Context.Response.WriteLine("250-STARTTLS", true); + await Context.Response.WriteLine("250-STARTTLS", true).ConfigureAwait(false); } - Context.Response.WriteLine("250 OK", true); + await Context.Response.WriteLine("250 OK", true).ConfigureAwait(false); return true; } @@ -158,14 +160,14 @@ protected override bool Parse(byte[] bytes) if (TlsMode != PodeTlsMode.Explicit) { Command = PodeSmtpCommand.None; - Context.Response.WriteLine("501 SMTP server not running on Explicit TLS for the STARTTLS command", true); + await Context.Response.WriteLine("501 SMTP server not running on Explicit TLS for the STARTTLS command", true).ConfigureAwait(false); return true; } Reset(); Command = PodeSmtpCommand.StartTls; - Context.Response.WriteLine("220 Ready to start TLS"); - UpgradeToSSL(); + await Context.Response.WriteLine("220 Ready to start TLS").ConfigureAwait(false); + await UpgradeToSSL(cancellationToken).ConfigureAwait(false); return true; } @@ -174,7 +176,7 @@ protected override bool Parse(byte[] bytes) { Reset(); Command = PodeSmtpCommand.Reset; - Context.Response.WriteLine("250 OK", true); + await Context.Response.WriteLine("250 OK", true).ConfigureAwait(false); return true; } @@ -182,7 +184,7 @@ protected override bool Parse(byte[] bytes) if (IsCommand(content, "NOOP")) { Command = PodeSmtpCommand.NoOp; - Context.Response.WriteLine("250 OK", true); + await Context.Response.WriteLine("250 OK", true).ConfigureAwait(false); return true; } @@ -190,7 +192,7 @@ protected override bool Parse(byte[] bytes) if (IsCommand(content, "RCPT TO")) { Command = PodeSmtpCommand.RcptTo; - Context.Response.WriteLine("250 OK", true); + await Context.Response.WriteLine("250 OK", true).ConfigureAwait(false); To.Add(ParseEmail(content)); return true; } @@ -199,7 +201,7 @@ protected override bool Parse(byte[] bytes) if (IsCommand(content, "MAIL FROM")) { Command = PodeSmtpCommand.MailFrom; - Context.Response.WriteLine("250 OK", true); + await Context.Response.WriteLine("250 OK", true).ConfigureAwait(false); From = ParseEmail(content); return true; } @@ -208,7 +210,7 @@ protected override bool Parse(byte[] bytes) if (IsCommand(content, "DATA")) { Command = PodeSmtpCommand.Data; - Context.Response.WriteLine("354 Start mail input; end with .", true); + await Context.Response.WriteLine("354 Start mail input; end with .", true).ConfigureAwait(false); return true; } @@ -217,17 +219,17 @@ protected override bool Parse(byte[] bytes) { case PodeSmtpCommand.Data: _canProcess = true; - Context.Response.WriteLine("250 OK", true); + await Context.Response.WriteLine("250 OK", true).ConfigureAwait(false); RawBody = bytes; Attachments = new List(); // parse the headers Headers = ParseHeaders(content); - Subject = $"{Headers["Subject"]}"; - IsUrgent = ($"{Headers["Priority"]}".Equals("urgent", StringComparison.InvariantCultureIgnoreCase) || $"{Headers["Importance"]}".Equals("high", StringComparison.InvariantCultureIgnoreCase)); - ContentEncoding = $"{Headers["Content-Transfer-Encoding"]}"; + Subject = Headers["Subject"]?.ToString(); + IsUrgent = $"{Headers["Priority"]}".Equals("urgent", StringComparison.InvariantCultureIgnoreCase) || $"{Headers["Importance"]}".Equals("high", StringComparison.InvariantCultureIgnoreCase); + ContentEncoding = Headers["Content-Transfer-Encoding"]?.ToString(); - ContentType = $"{Headers["Content-Type"]}"; + ContentType = Headers["Content-Type"]?.ToString(); if (!string.IsNullOrEmpty(Boundary) && !ContentType.Contains("boundary=")) { ContentType = ContentType.TrimEnd(';'); @@ -249,7 +251,7 @@ protected override bool Parse(byte[] bytes) else { Command = PodeSmtpCommand.None; - Context.Response.WriteLine("501 Invalid DATA received", true); + await Context.Response.WriteLine("501 Invalid DATA received", true).ConfigureAwait(false); return true; } break; @@ -270,7 +272,7 @@ public void Reset() From = string.Empty; To = new List(); Body = string.Empty; - RawBody = default(byte[]); + RawBody = default; Command = PodeSmtpCommand.None; ContentType = string.Empty; ContentEncoding = string.Empty; @@ -365,7 +367,7 @@ private Hashtable ParseHeaders(string value) private bool IsBodyValid(string value) { var lines = value.Split(new string[] { PodeHelpers.NEW_LINE }, StringSplitOptions.None); - return (Array.LastIndexOf(lines, ".") > -1); + return Array.LastIndexOf(lines, ".") > -1; } private void ParseBoundary() @@ -464,7 +466,7 @@ private byte[] ConvertBodyEncoding(string body, string contentEncoding) var match = default(Match); while ((match = Regex.Match(body, "(?=(?[0-9A-F]{2}))")).Success) { - body = (body.Replace(match.Groups["code"].Value, $"{(char)Convert.ToInt32(match.Groups["hex"].Value, 16)}")); + body = body.Replace(match.Groups["code"].Value, $"{(char)Convert.ToInt32(match.Groups["hex"].Value, 16)}"); } return _Encoding.UTF8.GetBytes(body); @@ -516,7 +518,7 @@ private string ConvertBodyType(byte[] bytes, string contentType) public override void Dispose() { - RawBody = default(byte[]); + RawBody = default; Body = string.Empty; if (Attachments != default(List)) diff --git a/src/Listener/PodeSocket.cs b/src/Listener/PodeSocket.cs index 8f8b5fd7d..7c337c9e3 100644 --- a/src/Listener/PodeSocket.cs +++ b/src/Listener/PodeSocket.cs @@ -25,15 +25,11 @@ public class PodeSocket : PodeProtocol, IDisposable public bool DualMode { get; private set; } private ConcurrentQueue AcceptConnections; - private ConcurrentQueue ReceiveConnections; private IDictionary PendingSockets; private PodeListener Listener; - public bool IsSsl - { - get => Certificate != default(X509Certificate); - } + public bool IsSsl => Certificate != default(X509Certificate); private int _receiveTimeout; public int ReceiveTimeout @@ -50,11 +46,7 @@ public int ReceiveTimeout } public bool HasHostnames => Hostnames.Any(); - - public string Hostname - { - get => HasHostnames ? Hostnames[0] : Endpoints[0].IPAddress.ToString(); - } + public string Hostname => HasHostnames ? Hostnames[0] : Endpoints[0].IPAddress.ToString(); public PodeSocket(string name, IPAddress[] ipAddress, int port, SslProtocols protocols, PodeProtocolType type, X509Certificate certificate = null, bool allowClientCertificate = false, PodeTlsMode tlsMode = PodeTlsMode.Implicit, bool dualMode = false) : base(type) @@ -68,7 +60,6 @@ public PodeSocket(string name, IPAddress[] ipAddress, int port, SslProtocols pro DualMode = dualMode; AcceptConnections = new ConcurrentQueue(); - ReceiveConnections = new ConcurrentQueue(); PendingSockets = new Dictionary(); Endpoints = new List(); @@ -95,13 +86,13 @@ public void Start() { foreach (var ep in Endpoints) { - StartEndpoint(ep); + _ = Task.Run(() => StartEndpoint(ep), Listener.CancellationToken); } } private void StartEndpoint(PodeEndpoint endpoint) { - if (endpoint.IsDisposed) + if (endpoint.IsDisposed || Listener.CancellationToken.IsCancellationRequested) { return; } @@ -117,7 +108,7 @@ private void StartEndpoint(PodeEndpoint endpoint) try { - raised = endpoint.AcceptAsync(args); + raised = endpoint.Accept(args); } catch (ObjectDisposedException) { @@ -130,49 +121,46 @@ private void StartEndpoint(PodeEndpoint endpoint) } } - private void StartReceive(Socket acceptedSocket) + private async Task StartReceive(Socket acceptedSocket) { + // add the socket to pending + AddPendingSocket(acceptedSocket); + + // create the context var context = new PodeContext(acceptedSocket, this, Listener); + PodeHelpers.WriteErrorMessage($"Opening Receive", Listener, PodeLoggingLevel.Verbose, context); + + // initialise the context + await context.Initialise().ConfigureAwait(false); if (context.IsErrored) { context.Dispose(true); return; } + // start receiving data StartReceive(context); } public void StartReceive(PodeContext context) { - var args = GetReceiveConnection(); - args.AcceptSocket = context.Socket; - args.UserToken = context; - StartReceive(args); - } - - private void StartReceive(SocketAsyncEventArgs args) - { - args.SetBuffer(new byte[0], 0, 0); - bool raised; + PodeHelpers.WriteErrorMessage($"Starting Receive", Listener, PodeLoggingLevel.Verbose, context); try { - AddPendingSocket(args.AcceptSocket); - raised = args.AcceptSocket.ReceiveAsync(args); + _ = Task.Run(async () => await context.Receive().ConfigureAwait(false), Listener.CancellationToken); } - catch (ObjectDisposedException) + catch (OperationCanceledException) { } + catch (IOException) { } + catch (AggregateException aex) { - return; + PodeHelpers.HandleAggregateException(aex, Listener, PodeLoggingLevel.Error, true); + context.Socket.Close(); } catch (Exception ex) { PodeHelpers.WriteException(ex, Listener); - throw; - } - - if (!raised) - { - ProcessReceive(args); + context.Socket.Close(); } } @@ -205,69 +193,28 @@ private void ProcessAccept(SocketAsyncEventArgs args) else { // start receive - StartReceive(args.AcceptSocket); - } - - // add args back to connections - ClearSocketAsyncEvent(args); - AcceptConnections.Enqueue(args); - } - - private void ProcessReceive(SocketAsyncEventArgs args) - { - // get details - var received = args.AcceptSocket; - var context = (PodeContext)args.UserToken; - var error = args.SocketError; - - // remove the socket from pending - RemovePendingSocket(received); - - // close socket if not successful, or if listener is stopped - close now! - if ((received == default(Socket)) || (error != SocketError.Success) || (!Listener.IsConnected)) - { - if (error != SocketError.Success) + try { - PodeHelpers.WriteErrorMessage($"Closing receiving socket: {error}", Listener, PodeLoggingLevel.Debug); + _ = Task.Run(async () => await StartReceive(accepted), Listener.CancellationToken).ConfigureAwait(false); } - - // close socket - if (received != default(Socket)) + catch (OperationCanceledException) { } + catch (IOException) { } + catch (AggregateException aex) { - received.Close(); + PodeHelpers.HandleAggregateException(aex, Listener, PodeLoggingLevel.Error, true); + } + catch (Exception ex) + { + PodeHelpers.WriteException(ex, Listener); } - - // close the context - context.Dispose(true); - - // add args back to connections - ClearSocketAsyncEvent(args); - ReceiveConnections.Enqueue(args); - return; - } - - try - { - context.RenewTimeoutToken(); - Task.Factory.StartNew(() => context.Receive(), context.ContextTimeoutToken.Token); - } - catch (OperationCanceledException) { } - catch (IOException) { } - catch (AggregateException aex) - { - PodeHelpers.HandleAggregateException(aex, Listener, PodeLoggingLevel.Error, true); - } - catch (Exception ex) - { - PodeHelpers.WriteException(ex, Listener); } // add args back to connections ClearSocketAsyncEvent(args); - ReceiveConnections.Enqueue(args); + AcceptConnections.Enqueue(args); } - public void HandleContext(PodeContext context) + public async Task HandleContext(PodeContext context) { try { @@ -287,7 +234,7 @@ public void HandleContext(PodeContext context) { if (!context.IsWebSocketUpgraded) { - context.UpgradeWebSocket(); + await context.UpgradeWebSocket().ConfigureAwait(false); process = false; context.Dispose(); } @@ -350,36 +297,11 @@ private SocketAsyncEventArgs NewAcceptConnection() } } - private SocketAsyncEventArgs NewReceiveConnection() - { - lock (ReceiveConnections) - { - var args = new SocketAsyncEventArgs(); - args.Completed += new EventHandler(Receive_Completed); - return args; - } - } - - private SocketAsyncEventArgs GetReceiveConnection() - { - if (!ReceiveConnections.TryDequeue(out SocketAsyncEventArgs args)) - { - args = NewReceiveConnection(); - } - - return args; - } - private void Accept_Completed(object sender, SocketAsyncEventArgs e) { ProcessAccept(e); } - private void Receive_Completed(object sender, SocketAsyncEventArgs e) - { - ProcessReceive(e); - } - private void AddPendingSocket(Socket socket) { lock (PendingSockets) @@ -392,7 +314,7 @@ private void AddPendingSocket(Socket socket) } } - private void RemovePendingSocket(Socket socket) + public void RemovePendingSocket(Socket socket) { lock (PendingSockets) { @@ -468,8 +390,8 @@ public static void CloseSocket(Socket socket) private void ClearSocketAsyncEvent(SocketAsyncEventArgs e) { - e.AcceptSocket = default(Socket); - e.UserToken = default(object); + e.AcceptSocket = default; + e.UserToken = default; } public new bool Equals(object obj) diff --git a/src/Listener/PodeTcpRequest.cs b/src/Listener/PodeTcpRequest.cs index af2a60aea..c48982538 100644 --- a/src/Listener/PodeTcpRequest.cs +++ b/src/Listener/PodeTcpRequest.cs @@ -1,4 +1,6 @@ using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; namespace Pode { @@ -22,11 +24,11 @@ public string Body public override bool CloseImmediately { - get => (IsDisposed || RawBody == default(byte[]) || RawBody.Length == 0); + get => IsDisposed || RawBody == default(byte[]) || RawBody.Length == 0; } - public PodeTcpRequest(Socket socket, PodeSocket podeSocket) - : base(socket, podeSocket) + public PodeTcpRequest(Socket socket, PodeSocket podeSocket, PodeContext context) + : base(socket, podeSocket, context) { IsKeepAlive = true; Type = PodeProtocolType.Tcp; @@ -43,31 +45,30 @@ protected override bool ValidateInput(byte[] bytes) // expect to end with ? if (Context.PodeSocket.CRLFMessageEnd) { - return (bytes[bytes.Length - 2] == (byte)13 - && bytes[bytes.Length - 1] == (byte)10); + return bytes[bytes.Length - 2] == PodeHelpers.CARRIAGE_RETURN_BYTE + && bytes[bytes.Length - 1] == PodeHelpers.NEW_LINE_BYTE; } return true; } - protected override bool Parse(byte[] bytes) + protected override Task Parse(byte[] bytes, CancellationToken cancellationToken) { - RawBody = bytes; + // check if the request is cancelled + cancellationToken.ThrowIfCancellationRequested(); - // if there are no bytes, return (0 bytes read means we can close the socket) - if (bytes.Length == 0) - { - return true; - } + // set the raw body + RawBody = bytes; - return true; + // return that we're done + return Task.FromResult(true); } public void Reset() { PodeHelpers.WriteErrorMessage($"Request reset", Context.Listener, PodeLoggingLevel.Verbose, Context); _body = string.Empty; - RawBody = default(byte[]); + RawBody = default; } public void Close() @@ -77,7 +78,7 @@ public void Close() public override void Dispose() { - RawBody = default(byte[]); + RawBody = default; _body = string.Empty; base.Dispose(); } diff --git a/src/Listener/PodeWatcher.cs b/src/Listener/PodeWatcher.cs index eebdec709..ed3134cb6 100644 --- a/src/Listener/PodeWatcher.cs +++ b/src/Listener/PodeWatcher.cs @@ -11,7 +11,7 @@ public class PodeWatcher : PodeConnector public PodeItemQueue FileEvents { get; private set; } - public PodeWatcher(CancellationToken cancellationToken = default(CancellationToken)) + public PodeWatcher(CancellationToken cancellationToken = default) : base(cancellationToken) { FileWatchers = new List(); @@ -24,7 +24,7 @@ public void AddFileWatcher(PodeFileWatcher watcher) FileWatchers.Add(watcher); } - public Task GetFileEventAsync(CancellationToken cancellationToken = default(CancellationToken)) + public Task GetFileEventAsync(CancellationToken cancellationToken = default) { return FileEvents.GetAsync(cancellationToken); } diff --git a/src/Listener/PodeWebSocket.cs b/src/Listener/PodeWebSocket.cs index 10d6a75f9..87cf4ed79 100644 --- a/src/Listener/PodeWebSocket.cs +++ b/src/Listener/PodeWebSocket.cs @@ -17,27 +17,23 @@ public class PodeWebSocket : IDisposable public string ContentType { get; private set; } public bool IsConnected { - get => (WebSocket != default(ClientWebSocket) && WebSocket.State == WebSocketState.Open); + get => WebSocket != default(ClientWebSocket) && WebSocket.State == WebSocketState.Open; } private ClientWebSocket WebSocket; - public PodeWebSocket(string name, string url, string contentType) + public PodeWebSocket(string name, string url, string contentType, PodeReceiver receiver) { Name = name; URL = new Uri(url); + Receiver = receiver; ContentType = string.IsNullOrWhiteSpace(contentType) ? "application/json" : contentType; } - public void BindReceiver(PodeReceiver receiver) - { - Receiver = receiver; - } - - public async void Connect() + public async Task Connect() { if (IsConnected) { @@ -46,29 +42,29 @@ public async void Connect() if (WebSocket != default(ClientWebSocket)) { - Disconnect(PodeWebSocketCloseFrom.Client); + await Disconnect(PodeWebSocketCloseFrom.Client).ConfigureAwait(false); WebSocket.Dispose(); } WebSocket = new ClientWebSocket(); WebSocket.Options.KeepAliveInterval = TimeSpan.FromSeconds(60); - await WebSocket.ConnectAsync(URL, Receiver.CancellationToken); - await Task.Factory.StartNew(Receive, Receiver.CancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default); + await WebSocket.ConnectAsync(URL, Receiver.CancellationToken).ConfigureAwait(false); + await Task.Factory.StartNew(Receive, Receiver.CancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default).ConfigureAwait(false); } - public void Reconnect(string url) + public async Task Reconnect(string url) { if (!string.IsNullOrWhiteSpace(url)) { URL = new Uri(url); } - Disconnect(PodeWebSocketCloseFrom.Client); - Connect(); + await Disconnect(PodeWebSocketCloseFrom.Client).ConfigureAwait(false); + await Connect().ConfigureAwait(false); } - public async void Receive() + public async Task Receive() { var result = default(WebSocketReceiveResult); var buffer = _WebSocket.CreateClientBuffer(1024, 1024); @@ -80,7 +76,7 @@ public async void Receive() { do { - result = await WebSocket.ReceiveAsync(buffer, Receiver.CancellationToken); + result = await WebSocket.ReceiveAsync(buffer, Receiver.CancellationToken).ConfigureAwait(false); if (result.MessageType != WebSocketMessageType.Close) { bufferStream.Write(buffer.ToArray(), 0, result.Count); @@ -90,7 +86,7 @@ public async void Receive() if (result.MessageType == WebSocketMessageType.Close) { - Disconnect(PodeWebSocketCloseFrom.Server); + await Disconnect(PodeWebSocketCloseFrom.Server).ConfigureAwait(false); break; } @@ -105,7 +101,8 @@ public async void Receive() bufferStream = new MemoryStream(); } } - catch (TaskCanceledException) {} + catch (OperationCanceledException) { } + catch (IOException) { } catch (WebSocketException ex) { PodeHelpers.WriteException(ex, Receiver, PodeLoggingLevel.Debug); @@ -113,23 +110,27 @@ public async void Receive() } finally { - bufferStream.Dispose(); - bufferStream = default(MemoryStream); - buffer = default(ArraySegment); + if (bufferStream != default) + { + bufferStream.Dispose(); + bufferStream = default; + } + + buffer = default; } } - public void Send(string message, WebSocketMessageType type = WebSocketMessageType.Text) + public async Task Send(string message, WebSocketMessageType type = WebSocketMessageType.Text) { if (!IsConnected) { return; } - WebSocket.SendAsync(new ArraySegment(Encoding.UTF8.GetBytes(message)), type, true, Receiver.CancellationToken).Wait(); + await WebSocket.SendAsync(new ArraySegment(Encoding.UTF8.GetBytes(message)), type, true, Receiver.CancellationToken).ConfigureAwait(false); } - public void Disconnect(PodeWebSocketCloseFrom closeFrom) + public async Task Disconnect(PodeWebSocketCloseFrom closeFrom) { if (WebSocket == default(ClientWebSocket)) { @@ -143,26 +144,26 @@ public void Disconnect(PodeWebSocketCloseFrom closeFrom) // only close output in client closing if (closeFrom == PodeWebSocketCloseFrom.Client) { - WebSocket.CloseOutputAsync(WebSocketCloseStatus.Empty, string.Empty, CancellationToken.None).Wait(); + await WebSocket.CloseOutputAsync(WebSocketCloseStatus.Empty, string.Empty, CancellationToken.None).ConfigureAwait(false); } // if the server is closing, or client and netcore, then close properly if (closeFrom == PodeWebSocketCloseFrom.Server || !PodeHelpers.IsNetFramework) { - WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait(); + await WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).ConfigureAwait(false); } PodeHelpers.WriteErrorMessage($"Closed client web socket: {Name}", Receiver, PodeLoggingLevel.Verbose); } WebSocket.Dispose(); - WebSocket = default(ClientWebSocket); + WebSocket = default; PodeHelpers.WriteErrorMessage($"Disconnected client web socket: {Name}", Receiver, PodeLoggingLevel.Verbose); } public void Dispose() { - Disconnect(PodeWebSocketCloseFrom.Client); + Disconnect(PodeWebSocketCloseFrom.Client).Wait(); } } } \ No newline at end of file diff --git a/src/Listener/PodeWebSocketRequest.cs b/src/Listener/PodeWebSocketRequest.cs index 7305d9666..39f623f29 100644 --- a/src/Listener/PodeWebSocketRequest.cs +++ b/src/Listener/PodeWebSocketRequest.cs @@ -13,7 +13,7 @@ public class PodeWebSocketRequest : IDisposable public int ContentLength { - get => (RawBody == default(byte[]) ? 0 : RawBody.Length); + get => RawBody == default(byte[]) ? 0 : RawBody.Length; } private string _body = string.Empty; @@ -39,7 +39,7 @@ public PodeWebSocketRequest(PodeWebSocket webSocket, MemoryStream bytes) public void Dispose() { WebSocket.Receiver.RemoveProcessingWebSocketRequest(this); - RawBody = default(byte[]); + RawBody = default; _body = string.Empty; } diff --git a/src/Private/PodeServer.ps1 b/src/Private/PodeServer.ps1 index 69dc7107c..d18adddf2 100644 --- a/src/Private/PodeServer.ps1 +++ b/src/Private/PodeServer.ps1 @@ -326,7 +326,7 @@ function Start-PodeWebServer { # send the message to all found sockets foreach ($socket in $sockets) { try { - $socket.Context.Response.SendSignal($message) + $null = Wait-PodeTask -Task $socket.Context.Response.SendSignal($message) } catch { $null = $Listener.Signals.Remove($socket.ClientId) diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index 0a3130e31..e46bb932a 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -1787,6 +1787,6 @@ function Send-PodeResponse { param() if ($null -ne $WebEvent.Response) { - $WebEvent.Response.Send() + $null = Wait-PodeTask -Task $WebEvent.Response.Send() } } \ No newline at end of file diff --git a/src/Public/SSE.ps1 b/src/Public/SSE.ps1 index 87ba03f80..07b708612 100644 --- a/src/Public/SSE.ps1 +++ b/src/Public/SSE.ps1 @@ -91,7 +91,7 @@ function ConvertTo-PodeSseConnection { $ClientId = New-PodeSseClientId -ClientId $ClientId # set and send SSE headers - $ClientId = $WebEvent.Response.SetSseConnection($Scope, $ClientId, $Name, $Group, $RetryDuration, $AllowAllOrigins.IsPresent) + $ClientId = Wait-PodeTask -Task $WebEvent.Response.SetSseConnection($Scope, $ClientId, $Name, $Group, $RetryDuration, $AllowAllOrigins.IsPresent) # create SSE property on WebEvent $WebEvent.Sse = @{ @@ -252,7 +252,7 @@ function Send-PodeSseEvent { # send directly back to current connection if ($FromEvent -and $WebEvent.Sse.IsLocal) { - $WebEvent.Response.SendSseEvent($EventType, $Data, $Id) + $null = Wait-PodeTask -Task $WebEvent.Response.SendSseEvent($EventType, $Data, $Id) return } diff --git a/src/Public/WebSockets.ps1 b/src/Public/WebSockets.ps1 index 9ea868852..e1d9f4958 100644 --- a/src/Public/WebSockets.ps1 +++ b/src/Public/WebSockets.ps1 @@ -133,7 +133,7 @@ function Connect-PodeWebSocket { # connect try { - $PodeContext.Server.WebSockets.Receiver.ConnectWebSocket($Name, $Url, $ContentType) + $null = Wait-PodeTask -Task $PodeContext.Server.WebSockets.Receiver.ConnectWebSocket($Name, $Url, $ContentType) } catch { # Failed to connect to websocket @@ -283,7 +283,7 @@ function Send-PodeWebSocket { $Message = ConvertTo-PodeResponseContent -InputObject $Message -ContentType $ws.ContentType -Depth $Depth # send message - $ws.Send($Message, $Type) + $null = Wait-PodeTask -Task $ws.Send($Message, $Type) } <# @@ -318,7 +318,7 @@ function Reset-PodeWebSocket { ) if ([string]::IsNullOrWhiteSpace($Name) -and ($null -ne $WsEvent)) { - $WsEvent.Request.WebSocket.Reconnect($Url) + $null = Wait-PodeTask -Task $WsEvent.Request.WebSocket.Reconnect($Url) return } @@ -328,7 +328,7 @@ function Reset-PodeWebSocket { } if (Test-PodeWebSocket -Name $Name) { - $PodeContext.Server.WebSockets.Receiver.GetWebSocket($Name).Reconnect($Url) + $null = Wait-PodeTask -Task $PodeContext.Server.WebSockets.Receiver.GetWebSocket($Name).Reconnect($Url) } } From 2942fe397cbba82354bf8f4fe6e89fc592d9e90a Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Thu, 29 Aug 2024 09:35:35 +0100 Subject: [PATCH 135/177] #1291: set RestApi.Https.Tests to use both Invoke-RestMethod and curl, to help detect SSL issues in the future --- tests/integration/RestApi.Https.Tests.ps1 | 346 +++++++++++----------- 1 file changed, 165 insertions(+), 181 deletions(-) diff --git a/tests/integration/RestApi.Https.Tests.ps1 b/tests/integration/RestApi.Https.Tests.ps1 index 141b30c04..17dea15fe 100644 --- a/tests/integration/RestApi.Https.Tests.ps1 +++ b/tests/integration/RestApi.Https.Tests.ps1 @@ -5,46 +5,28 @@ param() Describe 'REST API Requests' { BeforeAll { $splatter = @{} - $UseCurl = $true $version = $PSVersionTable.PSVersion - if ( $version.Major -eq 5) { + + if ($version.Major -eq 5) { # Ignore SSL certificate validation errors Add-Type @' -using System.Net; -using System.Security.Cryptography.X509Certificates; -public class TrustAllCertsPolicy : ICertificatePolicy { -public bool CheckValidationResult( - ServicePoint srvPoint, X509Certificate certificate, - WebRequest request, int certificateProblem) { - return true; -} -} + using System.Net; + using System.Security.Cryptography.X509Certificates; + public class TrustAllCertsPolicy : ICertificatePolicy { + public bool CheckValidationResult( + ServicePoint srvPoint, X509Certificate certificate, + WebRequest request, int certificateProblem) { + return true; + } + } '@ [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy - $UseCurl = $false - } - elseif ($PSVersionTable.OS -like '*Windows*') { - # OS check passed, now check PowerShell version - # Split version by '.' and compare major and minor version - if ( $version.Major -gt 7 -or ($version.Major -eq 7 -and $version.Minor -ge 4)) { - # Running on Windows with PowerShell Core 7.4 or greater. - $UseCurl = $true - } - else { - $UseCurl = $false - $splatter.SkipCertificateCheck = $true - # Running on Windows but with PowerShell version less than 7.4. - } - } else { - # Not running on Windows." - $UseCurl = $false $splatter.SkipCertificateCheck = $true } - $Port = 8080 $Endpoint = "https://127.0.0.1:$($Port)" @@ -136,139 +118,135 @@ public bool CheckValidationResult( AfterAll { Receive-Job -Name 'Pode' | Out-Default - if ($UseCurl) { - curl -s -X DELETE "$($Endpoint)/close" -k - } - else { - Invoke-RestMethod -Uri "$($Endpoint)/close" -Method Get @splatter | Out-Null - } + Invoke-RestMethod -Uri "$($Endpoint)/close" -Method Get @splatter | Out-Null Get-Job -Name 'Pode' | Remove-Job -Force } It 'responds back with pong' { - if ($UseCurl) { - $result = (curl -s -X GET "$($Endpoint)/ping" -k) | ConvertFrom-Json - } - else { - $result = Invoke-RestMethod -Uri "$($Endpoint)/ping" -Method Get @splatter - } + # test curl + $result = (curl -s -X GET "$($Endpoint)/ping" -k) | ConvertFrom-Json + $result.Result | Should -Be 'Pong' + + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/ping" -Method Get @splatter $result.Result | Should -Be 'Pong' } It 'responds back with 404 for invalid route' { - if ($UseCurl) { - $status_code = (curl -s -o /dev/null -w '%{http_code}' "$Endpoint/eek" -k) - $status_code | Should -be 404 - } - else { - { Invoke-RestMethod -Uri "$($Endpoint)/eek" -Method Get -ErrorAction Stop @splatter } | Should -Throw -ExpectedMessage '*404*' - } + # test curl + $status_code = (curl -s -o /dev/null -w '%{http_code}' "$Endpoint/eek" -k) + $status_code | Should -be 404 + + # test Invoke-RestMethod + { Invoke-RestMethod -Uri "$($Endpoint)/eek" -Method Get -ErrorAction Stop @splatter } | Should -Throw -ExpectedMessage '*404*' } It 'responds back with 405 for incorrect method' { - if ($UseCurl) { - $status_code = (curl -X POST -s -o /dev/null -w '%{http_code}' "$Endpoint/ping" -k) - $status_code | Should -be 405 - } - else { - { Invoke-RestMethod -Uri "$($Endpoint)/ping" -Method Post -ErrorAction Stop @splatter } | Should -Throw -ExpectedMessage '*405*' - } + # test curl + $status_code = (curl -X POST -s -o /dev/null -w '%{http_code}' "$Endpoint/ping" -k) + $status_code | Should -be 405 + + # test Invoke-RestMethod + { Invoke-RestMethod -Uri "$($Endpoint)/ping" -Method Post -ErrorAction Stop @splatter } | Should -Throw -ExpectedMessage '*405*' } It 'responds with simple query parameter' { - if ($UseCurl) { - $result = (curl -s -X GET "$($Endpoint)/data/query?username=rick" -k) | ConvertFrom-Json - } - else { - $result = Invoke-RestMethod -Uri "$($Endpoint)/data/query?username=rick" -Method Get @splatter - } + # test curl + $result = (curl -s -X GET "$($Endpoint)/data/query?username=rick" -k) | ConvertFrom-Json + $result.Username | Should -Be 'rick' + + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/data/query?username=rick" -Method Get @splatter $result.Username | Should -Be 'rick' } It 'responds with simple payload parameter - json' { - if ($UseCurl) { - $result = curl -s -X POST "$($Endpoint)/data/payload" -H 'Content-Type: application/json' -d '{"username":"rick"}' -k | ConvertFrom-Json - } - else { - $result = Invoke-RestMethod -Uri "$($Endpoint)/data/payload" -Method Post -Body '{"username":"rick"}' -ContentType 'application/json' @splatter - } + # test curl + $result = curl -s -X POST "$($Endpoint)/data/payload" -H 'Content-Type: application/json' -d '{"username":"rick"}' -k | ConvertFrom-Json + $result.Username | Should -Be 'rick' + + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/data/payload" -Method Post -Body '{"username":"rick"}' -ContentType 'application/json' @splatter $result.Username | Should -Be 'rick' } It 'responds with simple payload parameter - xml' { - if ($UseCurl) { - $result = curl -s -X POST "$($Endpoint)/data/payload" -H 'Content-Type: application/xml' -d 'rick' -k | ConvertFrom-Json - } - else { - $result = Invoke-RestMethod -Uri "$($Endpoint)/data/payload" -Method Post -Body 'rick' -ContentType 'application/xml' @splatter - } + # test curl + $result = curl -s -X POST "$($Endpoint)/data/payload" -H 'Content-Type: application/xml' -d 'rick' -k | ConvertFrom-Json + $result.Username | Should -Be 'rick' + + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/data/payload" -Method Post -Body 'rick' -ContentType 'application/xml' @splatter $result.Username | Should -Be 'rick' } It 'responds with simple payload parameter forced to json' { - if ($UseCurl) { - $result = curl -s -X POST "$($Endpoint)/data/payload-forced-type" -d '{"username":"rick"}' -k | ConvertFrom-Json - } - else { - $result = Invoke-RestMethod -Uri "$($Endpoint)/data/payload-forced-type" -Method Post -Body '{"username":"rick"}' @splatter - } + # test curl + $result = curl -s -X POST "$($Endpoint)/data/payload-forced-type" -d '{"username":"rick"}' -k | ConvertFrom-Json + $result.Username | Should -Be 'rick' + + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/data/payload-forced-type" -Method Post -Body '{"username":"rick"}' @splatter $result.Username | Should -Be 'rick' } It 'responds with simple route parameter' { - if ($UseCurl) { - $result = (curl -s -X GET "$($Endpoint)/data/param/rick" -k) | ConvertFrom-Json - } - else { - $result = Invoke-RestMethod -Uri "$($Endpoint)/data/param/rick" -Method Get @splatter - } + # test curl + $result = (curl -s -X GET "$($Endpoint)/data/param/rick" -k) | ConvertFrom-Json + $result.Username | Should -Be 'rick' + + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/data/param/rick" -Method Get @splatter $result.Username | Should -Be 'rick' } It 'responds with simple route parameter long' { - if ($UseCurl) { - $result = (curl -s -X GET "$($Endpoint)/data/param/rick/messages" -k) | ConvertFrom-Json - } - else { - $result = Invoke-RestMethod -Uri "$($Endpoint)/data/param/rick/messages" -Method Get @splatter - } + # test curl + $result = (curl -s -X GET "$($Endpoint)/data/param/rick/messages" -k) | ConvertFrom-Json + $result.Messages[0] | Should -Be 'Hello, world!' + $result.Messages[1] | Should -Be 'Greetings' + $result.Messages[2] | Should -Be 'Wubba Lub' + + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/data/param/rick/messages" -Method Get @splatter $result.Messages[0] | Should -Be 'Hello, world!' $result.Messages[1] | Should -Be 'Greetings' $result.Messages[2] | Should -Be 'Wubba Lub' } It 'responds ok to remove account' { - if ($UseCurl) { - $result = (curl -s -X DELETE "$($Endpoint)/api/rick/remove" -k) | ConvertFrom-Json - } - else { - $result = Invoke-RestMethod -Uri "$($Endpoint)/api/rick/remove" -Method Delete @splatter - } + # test curl + $result = (curl -s -X DELETE "$($Endpoint)/api/rick/remove" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' + + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/api/rick/remove" -Method Delete @splatter $result.Result | Should -Be 'OK' } It 'responds ok to replace account' { - if ($UseCurl) { - $result = (curl -s -X PUT "$($Endpoint)/api/rick/replace" -k) | ConvertFrom-Json - } - else { - $result = Invoke-RestMethod -Uri "$($Endpoint)/api/rick/replace" -Method Put @splatter - } + # test curl + $result = (curl -s -X PUT "$($Endpoint)/api/rick/replace" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' + + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/api/rick/replace" -Method Put @splatter $result.Result | Should -Be 'OK' } It 'responds ok to update account' { - if ($UseCurl) { - $result = (curl -s -X PATCH "$($Endpoint)/api/rick/update" -k) | ConvertFrom-Json - } - else { - $result = Invoke-RestMethod -Uri "$($Endpoint)/api/rick/update" -Method Patch @splatter - } + # test curl + $result = (curl -s -X PATCH "$($Endpoint)/api/rick/update" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' + + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/api/rick/update" -Method Patch @splatter $result.Result | Should -Be 'OK' } It 'decodes encoded payload parameter - gzip' { + # test curl $data = @{ username = 'rick' } $message = ($data | ConvertTo-Json) @@ -279,27 +257,29 @@ public bool CheckValidationResult( $gzip.Write($bytes, 0, $bytes.Length) $gzip.Close() - if ($UseCurl) { + try { + # get the compressed data + $ms.Position = 0 $compressedData = $ms.ToArray() - $ms.Dispose() + # Save the compressed data to a temporary file $tempFile = [System.IO.Path]::GetTempFileName() [System.IO.File]::WriteAllBytes($tempFile, $compressedData) + # make the request $result = curl -s -X POST "$Endpoint/encoding/transfer" -H 'Transfer-Encoding: gzip' -H 'Content-Type: application/json' --data-binary "@$tempFile" -k | ConvertFrom-Json # Cleanup the temporary file Remove-Item -Path $tempFile - } - else { + $result.Username | Should -Be 'rick' + # make the request - $ms.Position = 0 - $result = Invoke-RestMethod -Uri "$($Endpoint)/encoding/transfer" -Method Post -Body $ms.ToArray() -Headers @{ 'Transfer-Encoding' = 'gzip' } -ContentType 'application/json' @splatter + $result = Invoke-RestMethod -Uri "$($Endpoint)/encoding/transfer" -Method Post -Body $compressedData -Headers @{ 'Transfer-Encoding' = 'gzip' } -ContentType 'application/json' @splatter + $result.Username | Should -Be 'rick' + } + finally { $ms.Dispose() } - - $result.Username | Should -Be 'rick' - } It 'decodes encoded payload parameter - deflate' { @@ -309,13 +289,16 @@ public bool CheckValidationResult( # compress the message using deflate $bytes = [System.Text.Encoding]::UTF8.GetBytes($message) $ms = New-Object -TypeName System.IO.MemoryStream - $gzip = New-Object System.IO.Compression.DeflateStream($ms, [IO.Compression.CompressionMode]::Compress, $true) - $gzip.Write($bytes, 0, $bytes.Length) - $gzip.Close() - if ($UseCurl) { + $deflate = New-Object System.IO.Compression.DeflateStream($ms, [IO.Compression.CompressionMode]::Compress, $true) + $deflate.Write($bytes, 0, $bytes.Length) + $deflate.Close() + + try { + # get the compressed data + $ms.Position = 0 $compressedData = $ms.ToArray() - $ms.Dispose() + # test curl # Save the compressed data to a temporary file $tempFile = [System.IO.Path]::GetTempFileName() [System.IO.File]::WriteAllBytes($tempFile, $compressedData) @@ -325,15 +308,15 @@ public bool CheckValidationResult( # Cleanup the temporary file Remove-Item -Path $tempFile + $result.Username | Should -Be 'rick' + + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/encoding/transfer" -Method Post -Body $compressedData -Headers @{ 'Transfer-Encoding' = 'deflate' } -ContentType 'application/json' @splatter + $result.Username | Should -Be 'rick' } - else { - # make the request - $ms.Position = 0 - $result = Invoke-RestMethod -Uri "$($Endpoint)/encoding/transfer" -Method Post -Body $ms.ToArray() -Headers @{ 'Transfer-Encoding' = 'deflate' } -ContentType 'application/json' @splatter + finally { $ms.Dispose() } - - $result.Username | Should -Be 'rick' } It 'decodes encoded payload parameter forced to gzip' { @@ -346,93 +329,94 @@ public bool CheckValidationResult( $gzip = New-Object System.IO.Compression.GZipStream($ms, [IO.Compression.CompressionMode]::Compress, $true) $gzip.Write($bytes, 0, $bytes.Length) $gzip.Close() - if ($UseCurl) { + try { + # get the compressed data + $ms.Position = 0 $compressedData = $ms.ToArray() - $ms.Dispose() + # test curl # Save the compressed data to a temporary file $tempFile = [System.IO.Path]::GetTempFileName() [System.IO.File]::WriteAllBytes($tempFile, $compressedData) + # make the request $result = curl -s -X POST "$Endpoint/encoding/transfer-forced-type" -H 'Content-Type: application/json' --data-binary "@$tempFile" -k | ConvertFrom-Json # Cleanup the temporary file Remove-Item -Path $tempFile + $result.Username | Should -Be 'rick' + + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/encoding/transfer-forced-type" -Method Post -Body $compressedData -ContentType 'application/json' @splatter + $result.Username | Should -Be 'rick' } - else { - # make the request - $ms.Position = 0 - $result = Invoke-RestMethod -Uri "$($Endpoint)/encoding/transfer-forced-type" -Method Post -Body $ms.ToArray() -ContentType 'application/json' @splatter + finally { $ms.Dispose() } - - $result.Username | Should -Be 'rick' } It 'works with any method' { - if ($UseCurl) { - $result = (curl -s -X GET "$($Endpoint)/all" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' + # test curl + $result = (curl -s -X GET "$($Endpoint)/all" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' - $result = (curl -s -X PUT "$($Endpoint)/all" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' + $result = (curl -s -X PUT "$($Endpoint)/all" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' - $result = (curl -s -X PATCH "$($Endpoint)/all" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' - } - else { - $result = Invoke-RestMethod -Uri "$($Endpoint)/all" -Method Get @splatter - $result.Result | Should -Be 'OK' + $result = (curl -s -X PATCH "$($Endpoint)/all" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' - $result = Invoke-RestMethod -Uri "$($Endpoint)/all" -Method Put @splatter - $result.Result | Should -Be 'OK' + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/all" -Method Get @splatter + $result.Result | Should -Be 'OK' - $result = Invoke-RestMethod -Uri "$($Endpoint)/all" -Method Patch @splatter - $result.Result | Should -Be 'OK' - } + $result = Invoke-RestMethod -Uri "$($Endpoint)/all" -Method Put @splatter + $result.Result | Should -Be 'OK' + + $result = Invoke-RestMethod -Uri "$($Endpoint)/all" -Method Patch @splatter + $result.Result | Should -Be 'OK' } It 'route with a wild card' { - if ($UseCurl) { - $result = (curl -s -X GET "$($Endpoint)/api/stuff/hello" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' + # test curl + $result = (curl -s -X GET "$($Endpoint)/api/stuff/hello" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' - $result = (curl -s -X GET "$($Endpoint)/api/random/hello" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' + $result = (curl -s -X GET "$($Endpoint)/api/random/hello" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' - $result = (curl -s -X GET "$($Endpoint)/api/123/hello" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' - } - else { - $result = Invoke-RestMethod -Uri "$($Endpoint)/api/stuff/hello" -Method Get @splatter - $result.Result | Should -Be 'OK' + $result = (curl -s -X GET "$($Endpoint)/api/123/hello" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' - $result = Invoke-RestMethod -Uri "$($Endpoint)/api/random/hello" -Method Get @splatter - $result.Result | Should -Be 'OK' + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/api/stuff/hello" -Method Get @splatter + $result.Result | Should -Be 'OK' - $result = Invoke-RestMethod -Uri "$($Endpoint)/api/123/hello" -Method Get @splatter - $result.Result | Should -Be 'OK' - } + $result = Invoke-RestMethod -Uri "$($Endpoint)/api/random/hello" -Method Get @splatter + $result.Result | Should -Be 'OK' + + $result = Invoke-RestMethod -Uri "$($Endpoint)/api/123/hello" -Method Get @splatter + $result.Result | Should -Be 'OK' } It 'route importing outer function' { - if ($UseCurl) { - $result = (curl -s -X GET "$($Endpoint)/imported/func/outer" -k) | ConvertFrom-Json - } - else { - $result = Invoke-RestMethod -Uri "$($Endpoint)/imported/func/outer" -Method Get @splatter - } + # test curl + $result = (curl -s -X GET "$($Endpoint)/imported/func/outer" -k) | ConvertFrom-Json + $result.Message | Should -Be 'Outer Hello' + + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/imported/func/outer" -Method Get @splatter $result.Message | Should -Be 'Outer Hello' } It 'route importing outer function' { - if ($UseCurl) { - $result = (curl -s -X GET "$($Endpoint)/imported/func/inner" -k) | ConvertFrom-Json - } - else { - $result = Invoke-RestMethod -Uri "$($Endpoint)/imported/func/inner" -Method Get @splatter - } + # test curl + $result = (curl -s -X GET "$($Endpoint)/imported/func/inner" -k) | ConvertFrom-Json + $result.Message | Should -Be 'Inner Hello' + + # test Invoke-RestMethod + $result = Invoke-RestMethod -Uri "$($Endpoint)/imported/func/inner" -Method Get @splatter $result.Message | Should -Be 'Inner Hello' } } \ No newline at end of file From 22e7d94a3fc6b14e204c5f04a994dbbb5caab8ee Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Thu, 29 Aug 2024 09:52:52 +0100 Subject: [PATCH 136/177] #1291: only use curl on PS7.4+ --- tests/integration/RestApi.Https.Tests.ps1 | 177 +++++++++++++--------- 1 file changed, 109 insertions(+), 68 deletions(-) diff --git a/tests/integration/RestApi.Https.Tests.ps1 b/tests/integration/RestApi.Https.Tests.ps1 index 17dea15fe..0e9184124 100644 --- a/tests/integration/RestApi.Https.Tests.ps1 +++ b/tests/integration/RestApi.Https.Tests.ps1 @@ -6,6 +6,7 @@ Describe 'REST API Requests' { BeforeAll { $splatter = @{} $version = $PSVersionTable.PSVersion + $useCurl = $false if ($version.Major -eq 5) { # Ignore SSL certificate validation errors @@ -20,10 +21,13 @@ Describe 'REST API Requests' { } } '@ - [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy } else { + if ($version -ge [version]'7.4.0') { + $useCurl = $true + } + $splatter.SkipCertificateCheck = $true } @@ -125,8 +129,10 @@ Describe 'REST API Requests' { It 'responds back with pong' { # test curl - $result = (curl -s -X GET "$($Endpoint)/ping" -k) | ConvertFrom-Json - $result.Result | Should -Be 'Pong' + if ($useCurl) { + $result = (curl -s -X GET "$($Endpoint)/ping" -k) | ConvertFrom-Json + $result.Result | Should -Be 'Pong' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/ping" -Method Get @splatter @@ -135,8 +141,10 @@ Describe 'REST API Requests' { It 'responds back with 404 for invalid route' { # test curl - $status_code = (curl -s -o /dev/null -w '%{http_code}' "$Endpoint/eek" -k) - $status_code | Should -be 404 + if ($useCurl) { + $status_code = (curl -s -o /dev/null -w '%{http_code}' "$Endpoint/eek" -k) + $status_code | Should -be 404 + } # test Invoke-RestMethod { Invoke-RestMethod -Uri "$($Endpoint)/eek" -Method Get -ErrorAction Stop @splatter } | Should -Throw -ExpectedMessage '*404*' @@ -144,8 +152,10 @@ Describe 'REST API Requests' { It 'responds back with 405 for incorrect method' { # test curl - $status_code = (curl -X POST -s -o /dev/null -w '%{http_code}' "$Endpoint/ping" -k) - $status_code | Should -be 405 + if ($useCurl) { + $status_code = (curl -X POST -s -o /dev/null -w '%{http_code}' "$Endpoint/ping" -k) + $status_code | Should -be 405 + } # test Invoke-RestMethod { Invoke-RestMethod -Uri "$($Endpoint)/ping" -Method Post -ErrorAction Stop @splatter } | Should -Throw -ExpectedMessage '*405*' @@ -153,8 +163,10 @@ Describe 'REST API Requests' { It 'responds with simple query parameter' { # test curl - $result = (curl -s -X GET "$($Endpoint)/data/query?username=rick" -k) | ConvertFrom-Json - $result.Username | Should -Be 'rick' + if ($useCurl) { + $result = (curl -s -X GET "$($Endpoint)/data/query?username=rick" -k) | ConvertFrom-Json + $result.Username | Should -Be 'rick' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/data/query?username=rick" -Method Get @splatter @@ -163,8 +175,10 @@ Describe 'REST API Requests' { It 'responds with simple payload parameter - json' { # test curl - $result = curl -s -X POST "$($Endpoint)/data/payload" -H 'Content-Type: application/json' -d '{"username":"rick"}' -k | ConvertFrom-Json - $result.Username | Should -Be 'rick' + if ($useCurl) { + $result = curl -s -X POST "$($Endpoint)/data/payload" -H 'Content-Type: application/json' -d '{"username":"rick"}' -k | ConvertFrom-Json + $result.Username | Should -Be 'rick' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/data/payload" -Method Post -Body '{"username":"rick"}' -ContentType 'application/json' @splatter @@ -173,8 +187,10 @@ Describe 'REST API Requests' { It 'responds with simple payload parameter - xml' { # test curl - $result = curl -s -X POST "$($Endpoint)/data/payload" -H 'Content-Type: application/xml' -d 'rick' -k | ConvertFrom-Json - $result.Username | Should -Be 'rick' + if ($useCurl) { + $result = curl -s -X POST "$($Endpoint)/data/payload" -H 'Content-Type: application/xml' -d 'rick' -k | ConvertFrom-Json + $result.Username | Should -Be 'rick' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/data/payload" -Method Post -Body 'rick' -ContentType 'application/xml' @splatter @@ -183,8 +199,10 @@ Describe 'REST API Requests' { It 'responds with simple payload parameter forced to json' { # test curl - $result = curl -s -X POST "$($Endpoint)/data/payload-forced-type" -d '{"username":"rick"}' -k | ConvertFrom-Json - $result.Username | Should -Be 'rick' + if ($useCurl) { + $result = curl -s -X POST "$($Endpoint)/data/payload-forced-type" -d '{"username":"rick"}' -k | ConvertFrom-Json + $result.Username | Should -Be 'rick' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/data/payload-forced-type" -Method Post -Body '{"username":"rick"}' @splatter @@ -193,8 +211,10 @@ Describe 'REST API Requests' { It 'responds with simple route parameter' { # test curl - $result = (curl -s -X GET "$($Endpoint)/data/param/rick" -k) | ConvertFrom-Json - $result.Username | Should -Be 'rick' + if ($useCurl) { + $result = (curl -s -X GET "$($Endpoint)/data/param/rick" -k) | ConvertFrom-Json + $result.Username | Should -Be 'rick' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/data/param/rick" -Method Get @splatter @@ -203,10 +223,12 @@ Describe 'REST API Requests' { It 'responds with simple route parameter long' { # test curl - $result = (curl -s -X GET "$($Endpoint)/data/param/rick/messages" -k) | ConvertFrom-Json - $result.Messages[0] | Should -Be 'Hello, world!' - $result.Messages[1] | Should -Be 'Greetings' - $result.Messages[2] | Should -Be 'Wubba Lub' + if ($useCurl) { + $result = (curl -s -X GET "$($Endpoint)/data/param/rick/messages" -k) | ConvertFrom-Json + $result.Messages[0] | Should -Be 'Hello, world!' + $result.Messages[1] | Should -Be 'Greetings' + $result.Messages[2] | Should -Be 'Wubba Lub' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/data/param/rick/messages" -Method Get @splatter @@ -217,8 +239,10 @@ Describe 'REST API Requests' { It 'responds ok to remove account' { # test curl - $result = (curl -s -X DELETE "$($Endpoint)/api/rick/remove" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' + if ($useCurl) { + $result = (curl -s -X DELETE "$($Endpoint)/api/rick/remove" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/api/rick/remove" -Method Delete @splatter @@ -227,8 +251,10 @@ Describe 'REST API Requests' { It 'responds ok to replace account' { # test curl - $result = (curl -s -X PUT "$($Endpoint)/api/rick/replace" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' + if ($useCurl) { + $result = (curl -s -X PUT "$($Endpoint)/api/rick/replace" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/api/rick/replace" -Method Put @splatter @@ -237,8 +263,10 @@ Describe 'REST API Requests' { It 'responds ok to update account' { # test curl - $result = (curl -s -X PATCH "$($Endpoint)/api/rick/update" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' + if ($useCurl) { + $result = (curl -s -X PATCH "$($Endpoint)/api/rick/update" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/api/rick/update" -Method Patch @splatter @@ -246,7 +274,6 @@ Describe 'REST API Requests' { } It 'decodes encoded payload parameter - gzip' { - # test curl $data = @{ username = 'rick' } $message = ($data | ConvertTo-Json) @@ -262,16 +289,18 @@ Describe 'REST API Requests' { $ms.Position = 0 $compressedData = $ms.ToArray() - # Save the compressed data to a temporary file - $tempFile = [System.IO.Path]::GetTempFileName() - [System.IO.File]::WriteAllBytes($tempFile, $compressedData) + if ($useCurl) { + # Save the compressed data to a temporary file + $tempFile = [System.IO.Path]::GetTempFileName() + [System.IO.File]::WriteAllBytes($tempFile, $compressedData) - # make the request - $result = curl -s -X POST "$Endpoint/encoding/transfer" -H 'Transfer-Encoding: gzip' -H 'Content-Type: application/json' --data-binary "@$tempFile" -k | ConvertFrom-Json + # make the request + $result = curl -s -X POST "$Endpoint/encoding/transfer" -H 'Transfer-Encoding: gzip' -H 'Content-Type: application/json' --data-binary "@$tempFile" -k | ConvertFrom-Json - # Cleanup the temporary file - Remove-Item -Path $tempFile - $result.Username | Should -Be 'rick' + # Cleanup the temporary file + Remove-Item -Path $tempFile + $result.Username | Should -Be 'rick' + } # make the request $result = Invoke-RestMethod -Uri "$($Endpoint)/encoding/transfer" -Method Post -Body $compressedData -Headers @{ 'Transfer-Encoding' = 'gzip' } -ContentType 'application/json' @splatter @@ -299,16 +328,18 @@ Describe 'REST API Requests' { $compressedData = $ms.ToArray() # test curl - # Save the compressed data to a temporary file - $tempFile = [System.IO.Path]::GetTempFileName() - [System.IO.File]::WriteAllBytes($tempFile, $compressedData) + if ($useCurl) { + # Save the compressed data to a temporary file + $tempFile = [System.IO.Path]::GetTempFileName() + [System.IO.File]::WriteAllBytes($tempFile, $compressedData) - # make the request - $result = curl -s -X POST "$Endpoint/encoding/transfer" -H 'Transfer-Encoding: deflate' -H 'Content-Type: application/json' --data-binary "@$tempFile" -k | ConvertFrom-Json + # make the request + $result = curl -s -X POST "$Endpoint/encoding/transfer" -H 'Transfer-Encoding: deflate' -H 'Content-Type: application/json' --data-binary "@$tempFile" -k | ConvertFrom-Json - # Cleanup the temporary file - Remove-Item -Path $tempFile - $result.Username | Should -Be 'rick' + # Cleanup the temporary file + Remove-Item -Path $tempFile + $result.Username | Should -Be 'rick' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/encoding/transfer" -Method Post -Body $compressedData -Headers @{ 'Transfer-Encoding' = 'deflate' } -ContentType 'application/json' @splatter @@ -336,16 +367,18 @@ Describe 'REST API Requests' { $compressedData = $ms.ToArray() # test curl - # Save the compressed data to a temporary file - $tempFile = [System.IO.Path]::GetTempFileName() - [System.IO.File]::WriteAllBytes($tempFile, $compressedData) + if ($useCurl) { + # Save the compressed data to a temporary file + $tempFile = [System.IO.Path]::GetTempFileName() + [System.IO.File]::WriteAllBytes($tempFile, $compressedData) - # make the request - $result = curl -s -X POST "$Endpoint/encoding/transfer-forced-type" -H 'Content-Type: application/json' --data-binary "@$tempFile" -k | ConvertFrom-Json + # make the request + $result = curl -s -X POST "$Endpoint/encoding/transfer-forced-type" -H 'Content-Type: application/json' --data-binary "@$tempFile" -k | ConvertFrom-Json - # Cleanup the temporary file - Remove-Item -Path $tempFile - $result.Username | Should -Be 'rick' + # Cleanup the temporary file + Remove-Item -Path $tempFile + $result.Username | Should -Be 'rick' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/encoding/transfer-forced-type" -Method Post -Body $compressedData -ContentType 'application/json' @splatter @@ -358,14 +391,16 @@ Describe 'REST API Requests' { It 'works with any method' { # test curl - $result = (curl -s -X GET "$($Endpoint)/all" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' + if ($useCurl) { + $result = (curl -s -X GET "$($Endpoint)/all" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' - $result = (curl -s -X PUT "$($Endpoint)/all" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' + $result = (curl -s -X PUT "$($Endpoint)/all" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' - $result = (curl -s -X PATCH "$($Endpoint)/all" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' + $result = (curl -s -X PATCH "$($Endpoint)/all" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/all" -Method Get @splatter @@ -380,14 +415,16 @@ Describe 'REST API Requests' { It 'route with a wild card' { # test curl - $result = (curl -s -X GET "$($Endpoint)/api/stuff/hello" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' + if ($useCurl) { + $result = (curl -s -X GET "$($Endpoint)/api/stuff/hello" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' - $result = (curl -s -X GET "$($Endpoint)/api/random/hello" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' + $result = (curl -s -X GET "$($Endpoint)/api/random/hello" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' - $result = (curl -s -X GET "$($Endpoint)/api/123/hello" -k) | ConvertFrom-Json - $result.Result | Should -Be 'OK' + $result = (curl -s -X GET "$($Endpoint)/api/123/hello" -k) | ConvertFrom-Json + $result.Result | Should -Be 'OK' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/api/stuff/hello" -Method Get @splatter @@ -402,8 +439,10 @@ Describe 'REST API Requests' { It 'route importing outer function' { # test curl - $result = (curl -s -X GET "$($Endpoint)/imported/func/outer" -k) | ConvertFrom-Json - $result.Message | Should -Be 'Outer Hello' + if ($useCurl) { + $result = (curl -s -X GET "$($Endpoint)/imported/func/outer" -k) | ConvertFrom-Json + $result.Message | Should -Be 'Outer Hello' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/imported/func/outer" -Method Get @splatter @@ -412,8 +451,10 @@ Describe 'REST API Requests' { It 'route importing outer function' { # test curl - $result = (curl -s -X GET "$($Endpoint)/imported/func/inner" -k) | ConvertFrom-Json - $result.Message | Should -Be 'Inner Hello' + if ($useCurl) { + $result = (curl -s -X GET "$($Endpoint)/imported/func/inner" -k) | ConvertFrom-Json + $result.Message | Should -Be 'Inner Hello' + } # test Invoke-RestMethod $result = Invoke-RestMethod -Uri "$($Endpoint)/imported/func/inner" -Method Get @splatter From ac6a57cffd214abce51533c03582ae418d42578a Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 30 Aug 2024 08:34:46 -0700 Subject: [PATCH 137/177] fix sse --- examples/sse.ps1 | 48 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/examples/sse.ps1 b/examples/sse.ps1 index 564e97696..58129dae0 100644 --- a/examples/sse.ps1 +++ b/examples/sse.ps1 @@ -1,13 +1,47 @@ -$path = Split-Path -Parent -Path (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) -Import-Module "$($path)/src/Pode.psm1" -Force -ErrorAction Stop +<# +.SYNOPSIS + A sample PowerShell script to set up a Pode server with Server-Sent Events (SSE) and logging. + +.DESCRIPTION + This script sets up a Pode server that listens on port 8081, logs errors to the terminal, and handles Server-Sent Events (SSE) connections. The server sends periodic SSE events and provides routes to interact with SSE connections. + +.EXAMPLE + To run the sample: ./Sse.ps1 + + Invoke-RestMethod -Uri http://localhost:8081/data -Method Get + Invoke-RestMethod -Uri http://localhost:8081/ -Method Get + Invoke-RestMethod -Uri http://localhost:8081/sse -Method Get + +.LINK + https://github.com/Badgerati/Pode/blob/develop/examples/Sse.ps1 + +.NOTES + Author: Pode Team + License: MIT License +#> + +try { + # Determine the script path and Pode module path + $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) + $podePath = Split-Path -Parent -Path $ScriptPath + + # Import the Pode module from the source path if it exists, otherwise from installed modules + if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { + Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop + } + else { + Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop + } +} +catch { throw } # or just: # Import-Module Pode -# create a server, and start listening on port 8085 +# create a server, and start listening on port 8081 Start-PodeServer -Threads 3 { - # listen on localhost:8085 - Add-PodeEndpoint -Address * -Port 8090 -Protocol Http + # listen on localhost:8081 + Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http # log errors New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging -Levels * @@ -15,9 +49,9 @@ Start-PodeServer -Threads 3 { # open local sse connection, and send back data Add-PodeRoute -Method Get -Path '/data' -ScriptBlock { ConvertTo-PodeSseConnection -Name 'Data' -Scope Local - Send-PodeSseEvent -Id 1234 -EventType Action -Data 'hello, there!' -FromEvent + Send-PodeSseEvent -Id 1234 -EventType Action -Data 'hello, there!' Start-Sleep -Seconds 3 - Send-PodeSseEvent -Id 1337 -EventType BoldOne -Data 'general kenobi' -FromEvent + Send-PodeSseEvent -Id 1337 -EventType BoldOne -Data 'general kenobi' } # home page to get sse events From 98e2dd5e2c524d2b0654fc93a636cffaf99db300 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Fri, 30 Aug 2024 21:01:53 +0100 Subject: [PATCH 138/177] #1291: quickfix to set C# language version to 7.3, which is officially supported by .NET --- src/Listener/Pode.csproj | 2 +- src/Listener/PodeContext.cs | 2 +- src/Listener/PodeHttpRequest.cs | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Listener/Pode.csproj b/src/Listener/Pode.csproj index ee7d5af90..3932c1dc7 100644 --- a/src/Listener/Pode.csproj +++ b/src/Listener/Pode.csproj @@ -2,6 +2,6 @@ netstandard2.0;net6.0;net8.0 $(NoWarn);SYSLIB0001 - 9.0 + 7.3 diff --git a/src/Listener/PodeContext.cs b/src/Listener/PodeContext.cs index 66ed462a7..52af8cd66 100644 --- a/src/Listener/PodeContext.cs +++ b/src/Listener/PodeContext.cs @@ -21,7 +21,7 @@ public class PodeContext : PodeProtocol, IDisposable public Hashtable Data { get; private set; } public string EndpointName => PodeSocket.Name; - private object _lockable = new(); + private object _lockable = new object(); private PodeContextState _state; public PodeContextState State diff --git a/src/Listener/PodeHttpRequest.cs b/src/Listener/PodeHttpRequest.cs index 2d713eb67..1f1f42875 100644 --- a/src/Listener/PodeHttpRequest.cs +++ b/src/Listener/PodeHttpRequest.cs @@ -314,7 +314,10 @@ private int ParseHeaders(string[] reqLines) private async Task ParseBody(byte[] bytes, string newline, int start, CancellationToken cancellationToken) { // set the body stream - BodyStream ??= new MemoryStream(); + if (BodyStream == default(MemoryStream)) + { + BodyStream = new MemoryStream(); + } // are we chunked? var isChunked = !string.IsNullOrWhiteSpace(TransferEncoding) && TransferEncoding.Contains("chunked"); From 2489cee349686923e1b9844fcccafac5d59ad9f0 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 30 Aug 2024 17:35:15 -0700 Subject: [PATCH 139/177] Update ci-pwsh_preview.yml --- .github/workflows/ci-pwsh_preview.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci-pwsh_preview.yml b/.github/workflows/ci-pwsh_preview.yml index 4e82924ac..81bb80c3d 100644 --- a/.github/workflows/ci-pwsh_preview.yml +++ b/.github/workflows/ci-pwsh_preview.yml @@ -66,7 +66,6 @@ jobs: - name: Install Invoke-Build shell: pwsh run: | - $ProgressPreference = 'SilentlyContinue' Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force - name: Run Pester Tests From f5d7bfb3d637ba16dfacdacd77d7c7afff7af77b Mon Sep 17 00:00:00 2001 From: mdaneri Date: Mon, 2 Sep 2024 09:06:26 -0700 Subject: [PATCH 140/177] Review 1 --- examples/{Casching.ps1 => Caching.ps1} | 4 +- examples/Dockerfile | 4 +- examples/Sse.ps1 | 69 ----------- ...{TcpServer-Auth.ps1 => Tcp-ServerAuth.ps1} | 4 +- ...{TcpServer-Http.ps1 => Tcp-ServerHttp.ps1} | 4 +- ...dpoint.ps1 => Tcp-ServerMultiEndpoint.ps1} | 4 +- ...Web-Auth-Digest.ps1 => Web-AuthDigest.ps1} | 4 +- examples/{Rest-Api.ps1 => Web-RestApi.ps1} | 2 +- examples/Web-Signal.ps1 | 3 +- examples/{sse.ps1 => Web-Sse.ps1} | 4 +- ...Nunit-RestApi.ps1 => WebNunit-RestApi.ps1} | 2 +- examples/package.json | 4 +- pode.build.ps1 | 116 +++++------------- tests/unit/_.Tests.ps1 | 33 +++-- 14 files changed, 65 insertions(+), 192 deletions(-) rename examples/{Casching.ps1 => Caching.ps1} (96%) delete mode 100644 examples/Sse.ps1 rename examples/{TcpServer-Auth.ps1 => Tcp-ServerAuth.ps1} (94%) rename examples/{TcpServer-Http.ps1 => Tcp-ServerHttp.ps1} (92%) rename examples/{TcpServer-MultiEndpoint.ps1 => Tcp-ServerMultiEndpoint.ps1} (94%) rename examples/{Web-Auth-Digest.ps1 => Web-AuthDigest.ps1} (97%) rename examples/{Rest-Api.ps1 => Web-RestApi.ps1} (97%) rename examples/{sse.ps1 => Web-Sse.ps1} (95%) rename examples/{Nunit-RestApi.ps1 => WebNunit-RestApi.ps1} (97%) diff --git a/examples/Casching.ps1 b/examples/Caching.ps1 similarity index 96% rename from examples/Casching.ps1 rename to examples/Caching.ps1 index da4a4539c..a0dff16ca 100644 --- a/examples/Casching.ps1 +++ b/examples/Caching.ps1 @@ -8,10 +8,10 @@ that demonstrate caching with Redis. .EXAMPLE - To run the sample: ./Casching.ps1 + To run the sample: ./Caching.ps1 .LINK - https://github.com/Badgerati/Pode/blob/develop/examples/Casching.ps1 + https://github.com/Badgerati/Pode/blob/develop/examples/Caching.ps1 .NOTES Author: Pode Team diff --git a/examples/Dockerfile b/examples/Dockerfile index 65ff8c543..67cb0d221 100644 --- a/examples/Dockerfile +++ b/examples/Dockerfile @@ -1,4 +1,4 @@ FROM badgerati/pode:test COPY . /usr/src/app/ -EXPOSE 8085 -CMD [ "pwsh", "-c", "cd /usr/src/app; ./web-pages-docker.ps1" ] +EXPOSE 8081 +CMD [ "pwsh", "-c", "cd /usr/src/app; ./Web-PagesDocker.ps1" ] diff --git a/examples/Sse.ps1 b/examples/Sse.ps1 deleted file mode 100644 index 58129dae0..000000000 --- a/examples/Sse.ps1 +++ /dev/null @@ -1,69 +0,0 @@ -<# -.SYNOPSIS - A sample PowerShell script to set up a Pode server with Server-Sent Events (SSE) and logging. - -.DESCRIPTION - This script sets up a Pode server that listens on port 8081, logs errors to the terminal, and handles Server-Sent Events (SSE) connections. The server sends periodic SSE events and provides routes to interact with SSE connections. - -.EXAMPLE - To run the sample: ./Sse.ps1 - - Invoke-RestMethod -Uri http://localhost:8081/data -Method Get - Invoke-RestMethod -Uri http://localhost:8081/ -Method Get - Invoke-RestMethod -Uri http://localhost:8081/sse -Method Get - -.LINK - https://github.com/Badgerati/Pode/blob/develop/examples/Sse.ps1 - -.NOTES - Author: Pode Team - License: MIT License -#> - -try { - # Determine the script path and Pode module path - $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) - $podePath = Split-Path -Parent -Path $ScriptPath - - # Import the Pode module from the source path if it exists, otherwise from installed modules - if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { - Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop - } - else { - Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop - } -} -catch { throw } - -# or just: -# Import-Module Pode - -# create a server, and start listening on port 8081 -Start-PodeServer -Threads 3 { - # listen on localhost:8081 - Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http - - # log errors - New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging -Levels * - - # open local sse connection, and send back data - Add-PodeRoute -Method Get -Path '/data' -ScriptBlock { - ConvertTo-PodeSseConnection -Name 'Data' -Scope Local - Send-PodeSseEvent -Id 1234 -EventType Action -Data 'hello, there!' - Start-Sleep -Seconds 3 - Send-PodeSseEvent -Id 1337 -EventType BoldOne -Data 'general kenobi' - } - - # home page to get sse events - Add-PodeRoute -Method Get -Path '/' -ScriptBlock { - Write-PodeViewResponse -Path 'sse-home' - } - - Add-PodeRoute -Method Get -Path '/sse' -ScriptBlock { - ConvertTo-PodeSseConnection -Name 'Test' - } - - Add-PodeTimer -Name 'SendEvent' -Interval 10 -ScriptBlock { - Send-PodeSseEvent -Name 'Test' -Data "An Event! $(Get-Random -Minimum 1 -Maximum 100)" - } -} \ No newline at end of file diff --git a/examples/TcpServer-Auth.ps1 b/examples/Tcp-ServerAuth.ps1 similarity index 94% rename from examples/TcpServer-Auth.ps1 rename to examples/Tcp-ServerAuth.ps1 index f9cac1d4b..4d3733e21 100644 --- a/examples/TcpServer-Auth.ps1 +++ b/examples/Tcp-ServerAuth.ps1 @@ -6,10 +6,10 @@ This script sets up a Pode TCP server that listens on port 8081, logs errors to the terminal, and implements role-based access control. The server provides an endpoint that restricts access based on user roles retrieved from a database. .EXAMPLE - To run the sample: ./TcpServer-Auth.ps1 + To run the sample: ./Tcp-ServerAuth.ps1 .LINK - https://github.com/Badgerati/Pode/blob/develop/examples/TcpServer-Auth.ps1 + https://github.com/Badgerati/Pode/blob/develop/examples/Tcp-ServerAuth.ps1 .NOTES Author: Pode Team diff --git a/examples/TcpServer-Http.ps1 b/examples/Tcp-ServerHttp.ps1 similarity index 92% rename from examples/TcpServer-Http.ps1 rename to examples/Tcp-ServerHttp.ps1 index f90770261..4e99f537e 100644 --- a/examples/TcpServer-Http.ps1 +++ b/examples/Tcp-ServerHttp.ps1 @@ -6,10 +6,10 @@ This script sets up a Pode TCP server that listens on port 8081, logs errors to the terminal, and handles incoming HTTP requests. The server provides a catch-all handler for HTTP requests and returns a basic HTML response. .EXAMPLE - To run the sample: ./TcpServer-Http.ps1 + To run the sample: ./Tcp-ServerHttp.ps1 .LINK - https://github.com/Badgerati/Pode/blob/develop/examples/TcpServer-Http.ps1 + https://github.com/Badgerati/Pode/blob/develop/examples/Tcp-ServerHttp.ps1 .NOTES Author: Pode Team diff --git a/examples/TcpServer-MultiEndpoint.ps1 b/examples/Tcp-ServerMultiEndpoint.ps1 similarity index 94% rename from examples/TcpServer-MultiEndpoint.ps1 rename to examples/Tcp-ServerMultiEndpoint.ps1 index 5d8d014c9..f624a74dd 100644 --- a/examples/TcpServer-MultiEndpoint.ps1 +++ b/examples/Tcp-ServerMultiEndpoint.ps1 @@ -6,10 +6,10 @@ This script sets up a Pode TCP server that listens on multiple endpoints, logs errors to the terminal, and handles incoming TCP requests with specific verbs. The server provides handlers for 'HELLO' and 'Quit' verbs and a catch-all handler for unrecognized verbs. .EXAMPLE - To run the sample: ./TcpServer-MultiEndpoint.ps1 + To run the sample: ./Tcp-ServerMultiEndpoint.ps1 .LINK - https://github.com/Badgerati/Pode/blob/develop/examples/TcpServer-MultiEndpoint.ps1 + https://github.com/Badgerati/Pode/blob/develop/examples/Tcp-ServerMultiEndpoint.ps1 .NOTES Author: Pode Team diff --git a/examples/Web-Auth-Digest.ps1 b/examples/Web-AuthDigest.ps1 similarity index 97% rename from examples/Web-Auth-Digest.ps1 rename to examples/Web-AuthDigest.ps1 index 6cdf581dc..7c26eef53 100644 --- a/examples/Web-Auth-Digest.ps1 +++ b/examples/Web-AuthDigest.ps1 @@ -7,12 +7,12 @@ for securing access to the server. The authentication details are checked against predefined user data. .EXAMPLE - To run the sample: ./Web-Auth-Digest.ps1 + To run the sample: ./Web-AuthDigest.ps1 Invoke-RestMethod -Uri http://localhost:8081/users -Method Get .LINK - https://github.com/Badgerati/Pode/blob/develop/examples/Web-Auth-Digest.ps1 + https://github.com/Badgerati/Pode/blob/develop/examples/Web-AuthDigest.ps1 .NOTES Author: Pode Team diff --git a/examples/Rest-Api.ps1 b/examples/Web-RestApi.ps1 similarity index 97% rename from examples/Rest-Api.ps1 rename to examples/Web-RestApi.ps1 index d4a82ea12..bcc7f1311 100644 --- a/examples/Rest-Api.ps1 +++ b/examples/Web-RestApi.ps1 @@ -15,7 +15,7 @@ Invoke-RestMethod -Uri http://localhost:8081/api/users/usertest/message -Method Get .LINK - https://github.com/Badgerati/Pode/blob/develop/examples/Rest-Api.ps1 + https://github.com/Badgerati/Pode/blob/develop/examples/Web-RestApi.ps1 .NOTES Author: Pode Team diff --git a/examples/Web-Signal.ps1 b/examples/Web-Signal.ps1 index a5e874a40..8ecc63401 100644 --- a/examples/Web-Signal.ps1 +++ b/examples/Web-Signal.ps1 @@ -4,7 +4,8 @@ .DESCRIPTION This script sets up a Pode server that listens on a specified port and provides both HTTP and WebSocket - endpoints. It also logs errors and other request details to the terminal. + endpoints. It demonstrates how to set up WebSockets in Pode and logs errors and other request details + to the terminal. .PARAMETER Port The port number on which the server will listen. Default is 8091. diff --git a/examples/sse.ps1 b/examples/Web-Sse.ps1 similarity index 95% rename from examples/sse.ps1 rename to examples/Web-Sse.ps1 index 58129dae0..d676ff4e9 100644 --- a/examples/sse.ps1 +++ b/examples/Web-Sse.ps1 @@ -6,14 +6,14 @@ This script sets up a Pode server that listens on port 8081, logs errors to the terminal, and handles Server-Sent Events (SSE) connections. The server sends periodic SSE events and provides routes to interact with SSE connections. .EXAMPLE - To run the sample: ./Sse.ps1 + To run the sample: ./Web-Sse.ps1 Invoke-RestMethod -Uri http://localhost:8081/data -Method Get Invoke-RestMethod -Uri http://localhost:8081/ -Method Get Invoke-RestMethod -Uri http://localhost:8081/sse -Method Get .LINK - https://github.com/Badgerati/Pode/blob/develop/examples/Sse.ps1 + https://github.com/Badgerati/Pode/blob/develop/examples/Web-Sse.ps1 .NOTES Author: Pode Team diff --git a/examples/Nunit-RestApi.ps1 b/examples/WebNunit-RestApi.ps1 similarity index 97% rename from examples/Nunit-RestApi.ps1 rename to examples/WebNunit-RestApi.ps1 index 53d0736bc..06614204a 100644 --- a/examples/Nunit-RestApi.ps1 +++ b/examples/WebNunit-RestApi.ps1 @@ -21,7 +21,7 @@ } .LINK - https://github.com/Badgerati/Pode/blob/develop/examples/Nunit-RestApi.ps1 + https://github.com/Badgerati/Pode/blob/develop/examples/WebNunit-RestApi.ps1 .NOTES Author: Pode Team License: MIT License diff --git a/examples/package.json b/examples/package.json index e8f86a06e..ced2eeb7c 100644 --- a/examples/package.json +++ b/examples/package.json @@ -1,9 +1,9 @@ { "name": "pode", "version": "0.0.0", - "main": "./web-pages.ps1", + "main": "./Web-Pages.ps1", "scripts": { - "start": "./web-pages.ps1", + "start": "./Web-Pages.ps1", "install": "", "test": "", "build": "" diff --git a/pode.build.ps1 b/pode.build.ps1 index 85348280e..cb31576f9 100644 --- a/pode.build.ps1 +++ b/pode.build.ps1 @@ -346,94 +346,40 @@ Task DocsDeps ChocoDeps, { Task IndexSamples { $examplesPath = './examples' - $sampleMarkDownPath = './docs/Getting-Started/Samples.md' - if ((Test-Path -PathType Container -Path $examplesPath) ) { - - $excludeDirs = @('scripts', 'views', 'static', 'public', 'assets', 'timers', 'modules', - 'Authentication', 'certs', 'logs', 'relative', 'routes' ) # List of directories to exclude - - # Filter out non-existing directories - $existingExcludeDirs = @() - foreach ($dir in $excludeDirs) { - if (Test-Path -Path (Join-Path -Path $examplesPath -ChildPath $dir)) { - $existingExcludeDirs += $dir - } - } - $ps1Files = (Get-ChildItem -Path $examplesPath -Filter *.ps1 -Recurse | - Where-Object { - $exclude = $false - foreach ($dir in $existingExcludeDirs) { - if ($_.FullName -like "*$([IO.Path]::DirectorySeparatorChar)$dir$([IO.Path]::DirectorySeparatorChar)*") { - $exclude = $true - break - } - } - -not $exclude - }) - $title = "# Pode's Sample Scripts List" - $indexContent = "## Index`n" - foreach ($file in $ps1Files) { - write-host $file - $content = Get-Content -Path $file.FullName -ErrorAction Stop - $synopsis = @() - $description = $() - $inSynopsis = $false - $inDescription = $false - $inBlockComment = $false - foreach ($line in $content) { - $line = $line.Trim() - if (! [string]::IsNullOrWhiteSpace($line)) { - if ($inBlockComment) { - if ($line -match '#>') { - $inBlockComment = $false - $inSynopsis = $false - $inDescription = $false - break - } - else { - if ( $line -match '\.SYNOPSIS') { - $inSynopsis = $true - $inDescription = $false - } - elseif ( $line -match '\.DESCRIPTION') { - $inSynopsis = $false - $inDescription = $true - } - elseif ( $line -match '\.PARAMETER' -or $line -match '\.NOTES' -or $line -match '\.EXAMPLE') { - $inSynopsis = $false - $inDescription = $false - } - elseif ( $inDescription) { - $description += $line - } - elseif ( $inSynopsis) { - $synopsis += $line - } - } - } - elseif ($line -match '<#') { - $inBlockComment = $true - } - } - } - - $header = [PSCustomObject]@{ - Path = $file.FullName - Synopsis = ($synopsis -join '`n').Trim() - Description = ($description -join '`n').Trim() - } + if (!(Test-Path -PathType Container -Path $examplesPath)) { + return + } - if ($header.Synopsis -or $header.Description) { - $indexContent += "- [$($file.BaseName)](#$($file.BaseName))`n" - $markdownContent += "## [$($file.BaseName)](https://github.com/Badgerati/Pode/blob/develop/examples/$($file.Name))`n`n" - $markdownContent += "**Synopsis:**`n`n`t$($header.Synopsis)`n`n" - $markdownContent += "**Description:**`n`n`t$($header.Description)`n`n" - } + # List of directories to exclude + $sampleMarkDownPath = './docs/Getting-Started/Samples.md' + $excludeDirs = @('scripts', 'views', 'static', 'public', 'assets', 'timers', 'modules', + 'Authentication', 'certs', 'logs', 'relative', 'routes') + + # Convert exlusion list into single regex pattern for directory matching + $dirSeparator = [IO.Path]::DirectorySeparatorChar + $excludeDirs = "\$($dirSeparator)($($excludeDirs -join '|'))\$($dirSeparator)" + + # build the page content + Get-ChildItem -Path $examplesPath -Filter *.ps1 -Recurse -File -Force | + Where-Object { + $_.FullName -inotmatch $excludeDirs + } | + Sort-Object -Property FullName | + ForEach-Object { + Write-Verbose "Processing Sample: $($_.FullName)" + + # get the script help + $help = Get-Help -Name $_.FullName -ErrorAction Stop + + # add help content + $urlFileName = ($_.FullName -isplit 'examples')[1].Trim('\/') -replace '[\\/]', '/' + $markdownContent += "## [$($_.BaseName)](https://github.com/Badgerati/Pode/blob/develop/examples/$($urlFileName))`n`n" + $markdownContent += "**Synopsis**`n`n$($help.Synopsis)`n`n" + $markdownContent += "**Description**`n`n$($help.Description.Text)`n`n" } - Write-Output "Write Markdown document for the sample files to $sampleMarkDownPath" - Set-Content -Path $sampleMarkDownPath -Value ( $title + "`n" + $indexContent + "`n" + $markdownContent) - } + Write-Output "Write Markdown document for the sample files to $($sampleMarkDownPath)" + Set-Content -Path $sampleMarkDownPath -Value "# Sample Scripts`n`n$($markdownContent)" -Force } <# diff --git a/tests/unit/_.Tests.ps1 b/tests/unit/_.Tests.ps1 index 3b119742c..42b67b2f6 100644 --- a/tests/unit/_.Tests.ps1 +++ b/tests/unit/_.Tests.ps1 @@ -1,30 +1,25 @@ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] param() + BeforeDiscovery { $path = $PSCommandPath $examplesPath = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/examples/' + # List of directories to exclude $excludeDirs = @('scripts', 'views', 'static', 'public', 'assets', 'timers', 'modules', - 'Authentication', 'certs', 'logs', 'relative', 'routes') # List of directories to exclude - # Filter out non-existing directories - $existingExcludeDirs = @() - foreach ($dir in $excludeDirs) { - if (Test-Path -Path (Join-Path -Path $examplesPath -ChildPath $dir)) { - $existingExcludeDirs += $dir - } - } - $ps1Files = (Get-ChildItem -Path $examplesPath -Filter *.ps1 -Recurse | - Where-Object { - $exclude = $false - foreach ($dir in $existingExcludeDirs) { - if ($_.FullName -like "*$([IO.Path]::DirectorySeparatorChar)$dir$([IO.Path]::DirectorySeparatorChar)*") { - $exclude = $true - break - } - } - -not $exclude - }).FullName + 'Authentication', 'certs', 'logs', 'relative', 'routes') + + # Convert exlusion list into single regex pattern for directory matching + $dirSeparator = [IO.Path]::DirectorySeparatorChar + $excludeDirs = "\$($dirSeparator)($($excludeDirs -join '|'))\$($dirSeparator)" + + # get the example scripts + $ps1Files = @(Get-ChildItem -Path $examplesPath -Filter *.ps1 -Recurse -File -Force | + Where-Object { + $_.FullName -inotmatch $excludeDirs + }).FullName } + BeforeAll { $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' From 056572b6bfd620c5e7c65e59bf180ee75f17ecb8 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Mon, 2 Sep 2024 14:31:36 -0700 Subject: [PATCH 141/177] review --- pode.build.ps1 | 43 +++---------------------------------------- src/Pode.psm1 | 30 +++++++++++++++--------------- 2 files changed, 18 insertions(+), 55 deletions(-) diff --git a/pode.build.ps1 b/pode.build.ps1 index 88676a067..4cd21aee6 100644 --- a/pode.build.ps1 +++ b/pode.build.ps1 @@ -545,45 +545,8 @@ Task TestNoBuild TestDeps, { } }, PushCodeCoverage, CheckFailedTests -# Synopsis: Run tests after a build if needed -Task Test { - - # Get the .NET framework description to determine the runtime version - $frameworkDescription = [System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription - $found = $false - - # Match and extract the major version number from the framework description - if ($frameworkDescription -match '(\d+)\.(\d+)\.(\d+)') { - $majorVersion = [int]$matches[1] - - # Loop through the major versions from the detected version down to 6 - for ($version = $majorVersion; $version -ge 6; $version--) { - # Check if the corresponding Pode.dll file exists for the version - if (Test-Path "./src/Libs/net$version.0/Pode.dll") { - $found = $true - break - } - } - } - - # If no specific versioned Pode.dll was found, check for the netstandard2.0 version - if (-not $found) { - $found = Test-Path "./src/Libs/netstandard2.0/Pode.dll" - } - - # If any Pode.dll was found, skip the build task - if ($found) { - Write-Output 'Build Task not needed' - } - else { - # If no Pode.dll was found, invoke the build task - Invoke-Build Build - } - - # Always run the test task, assuming that the build task has already been run if needed - Invoke-Build TestNoBuild -} - +# Synopsis: Run tests after a build +Task Test Build, TestNoBuild # Synopsis: Check if any of the tests failed Task CheckFailedTests { @@ -1023,4 +986,4 @@ task ReleaseNotes { $categories[$category] | Sort-Object | ForEach-Object { Write-Host $_ } Write-Host '' } -} +} \ No newline at end of file diff --git a/src/Pode.psm1 b/src/Pode.psm1 index 992f76a8f..3e2d95553 100644 --- a/src/Pode.psm1 +++ b/src/Pode.psm1 @@ -90,25 +90,25 @@ try { } } else { - $frameworkDescription = [System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription - $loaded = $false - if ($frameworkDescription -match '(\d+)\.(\d+)\.(\d+)') { - $majorVersion = [int]$matches[1] - - for ($version = $majorVersion; $version -ge 6; $version--) { - $dllPath = "$($root)/Libs/net$version.0/Pode.dll" - if (Test-Path $dllPath) { - Add-Type -LiteralPath $dllPath -ErrorAction Stop - $loaded = $true - break - } - } + # fetch the .net version and the libs path + $version = [System.Environment]::Version.Major + $libsPath = "$($root)/Libs" + + # filter .net dll folders based on version above, and get path for latest version found + if (![string]::IsNullOrWhiteSpace($version)) { + $netFolder = Get-ChildItem -Path $libsPath -Directory -Force | + Where-Object { $_.Name -imatch "net[1-$($version)]" } | + Sort-Object -Property Name -Descending | + Select-Object -First 1 -ExpandProperty FullName } - if (-not $loaded) { - Add-Type -LiteralPath "$($root)/Libs/netstandard2.0/Pode.dll" -ErrorAction Stop + # use netstandard if no folder found + if ([string]::IsNullOrWhiteSpace($netFolder)) { + $netFolder = "$($libsPath)/netstandard2.0" } + # append Pode.dll and mount + Add-Type -LiteralPath "$($netFolder)/Pode.dll" -ErrorAction Stop } # load private functions From dbfa67ce707754f7d801959b71b89209dea880fa Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sat, 7 Sep 2024 14:57:50 -0700 Subject: [PATCH 142/177] final code --- docs/Getting-Started/Debug.md | 30 +++++++++++++++++ src/Pode.psd1 | 2 ++ src/Private/FileWatchers.ps1 | 4 +++ src/Private/Gui.ps1 | 3 ++ src/Private/Logging.ps1 | 3 ++ src/Private/PodeServer.ps1 | 10 +++++- src/Private/Schedules.ps1 | 6 ++++ src/Private/ServiceServer.ps1 | 3 ++ src/Private/SmtpServer.ps1 | 4 +++ src/Private/Tasks.ps1 | 2 ++ src/Private/TcpServer.ps1 | 4 +++ src/Private/Timers.ps1 | 3 ++ src/Private/WebSockets.ps1 | 4 +++ src/Public/Core.ps1 | 7 ++++ src/Public/Utilities.ps1 | 61 ++++++++++++++++++++++++++++++++++- 15 files changed, 144 insertions(+), 2 deletions(-) diff --git a/docs/Getting-Started/Debug.md b/docs/Getting-Started/Debug.md index a4647d3c5..fbf8a1d27 100644 --- a/docs/Getting-Started/Debug.md +++ b/docs/Getting-Started/Debug.md @@ -174,3 +174,33 @@ The steps to attach to the Pode process are as follows: 5. You'll also be able to query variables as well, such as `$WebEvent` and other variables you might have created. 6. When you are done debugging the current request, hit the `d` key. + + + +## Customizing and Managing Runspace Names + +### Distinguishing Runspace Names in Pode + +In Pode, internal runspaces are automatically assigned distinct names. This naming convention helps in identifying and managing these runspaces efficiently during debugging and monitoring. However, this is not the case for runspaces created by user tasks and schedules (excluding AsyncTask). These user-created runspaces typically have names in the `Runspace` format, which can make it challenging to distinguish between different runspaces. + +### Customizing Runspace Names + +To provide clarity and better manageability, you can set custom names for runspaces within your Pode tasks or schedules. This can be achieved using the `Set-PodeCurrentRunspaceName` cmdlet. By assigning meaningful names to your runspaces, you can easily identify and work with them, especially during debugging or performance monitoring. + +Another useful cmdlet is `Get-PodeCurrentRunspaceName`, which retrieves the current runspace's name. This can be helpful if you need to log or display the runspace name dynamically. + +### Example + +Here is an example demonstrating how to set a custom name for a runspace in a Pode task: + +```powershell +Add-PodeTask -Name 'Test2' -ScriptBlock { + param($value) + # Set a custom name for the current runspace + Set-PodeCurrentRunspaceName -Name 'Test2' + Start-Sleep -Seconds 10 + "A $($value) is never late, it arrives exactly when it means to" | Out-Default +} +``` + +In this example, the `Set-PodeCurrentRunspaceName` cmdlet is used to assign the name 'Test2' to the runspace executing the task. This makes it easier to identify the runspace in logs or during debugging sessions. diff --git a/src/Pode.psd1 b/src/Pode.psd1 index eae7d8c44..bed2b888e 100644 --- a/src/Pode.psd1 +++ b/src/Pode.psd1 @@ -141,6 +141,8 @@ 'ConvertFrom-PodeXml', 'Set-PodeDefaultFolder', 'Get-PodeDefaultFolder', + 'Get-PodeCurrentRunspaceName', + 'Set-PodeCurrentRunspaceName', # routes 'Add-PodeRoute', diff --git a/src/Private/FileWatchers.ps1 b/src/Private/FileWatchers.ps1 index 7c10fc32c..a0bce00ae 100644 --- a/src/Private/FileWatchers.ps1 +++ b/src/Private/FileWatchers.ps1 @@ -60,6 +60,8 @@ function Start-PodeFileWatcherRunspace { [int] $ThreadId ) + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name "FileWatcher_$ThreadId" try { while ($Watcher.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -142,6 +144,8 @@ function Start-PodeFileWatcherRunspace { [Parameter(Mandatory = $true)] $Watcher ) + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name 'FileWatcher_KeepAlive' try { while ($Watcher.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { diff --git a/src/Private/Gui.ps1 b/src/Private/Gui.ps1 index 30ecd0d45..2caf49612 100644 --- a/src/Private/Gui.ps1 +++ b/src/Private/Gui.ps1 @@ -12,6 +12,9 @@ function Start-PodeGuiRunspace { } $script = { + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name 'PodeGui' + try { # if there are multiple endpoints, flag warning we're only using the first - unless explicitly set if ($null -eq $PodeContext.Server.Gui.Endpoint) { diff --git a/src/Private/Logging.ps1 b/src/Private/Logging.ps1 index 21ad5b56c..013b604bb 100644 --- a/src/Private/Logging.ps1 +++ b/src/Private/Logging.ps1 @@ -375,6 +375,9 @@ function Start-PodeLoggingRunspace { } $script = { + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name 'Logging' + while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { # if there are no logs to process, just sleep for a few seconds - but after checking the batch if ($PodeContext.LogsToProcess.Count -eq 0) { diff --git a/src/Private/PodeServer.ps1 b/src/Private/PodeServer.ps1 index d18adddf2..33ef263c4 100644 --- a/src/Private/PodeServer.ps1 +++ b/src/Private/PodeServer.ps1 @@ -114,6 +114,8 @@ function Start-PodeWebServer { [int] $ThreadId ) + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name "HttpEndpoint_$ThreadId" try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -292,6 +294,8 @@ function Start-PodeWebServer { [Parameter(Mandatory = $true)] $Listener ) + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name 'WsEndpoint' try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -370,6 +374,8 @@ function Start-PodeWebServer { [int] $ThreadId ) + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name "WsEndpoint_$ThreadId" try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -449,6 +455,8 @@ function Start-PodeWebServer { [ValidateNotNull()] $Listener ) + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name "Listener_KeepAlive" try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -473,7 +481,7 @@ function Start-PodeWebServer { $waitType = 'Signals' } - Add-PodeRunspace -Type $waitType -ScriptBlock $waitScript -Parameters @{ 'Listener' = $listener } -NoProfile + Add-PodeRunspace -Type $waitType -ScriptBlock $waitScript -Parameters @{ 'Listener' = $listener} -NoProfile # browse to the first endpoint, if flagged if ($Browse) { diff --git a/src/Private/Schedules.ps1 b/src/Private/Schedules.ps1 index 79b365b92..13d71ff1c 100644 --- a/src/Private/Schedules.ps1 +++ b/src/Private/Schedules.ps1 @@ -19,6 +19,9 @@ function Start-PodeScheduleRunspace { } Add-PodeSchedule -Name '__pode_schedule_housekeeper__' -Cron '@minutely' -ScriptBlock { + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name '__pode_schedule_housekeeper__' + if ($PodeContext.Schedules.Processes.Count -eq 0) { return } @@ -39,6 +42,9 @@ function Start-PodeScheduleRunspace { } $script = { + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name 'Scheduler_Trigger' + # select the schedules that trigger on-start $_now = [DateTime]::Now diff --git a/src/Private/ServiceServer.ps1 b/src/Private/ServiceServer.ps1 index 17d51c864..5c6a8d9f9 100644 --- a/src/Private/ServiceServer.ps1 +++ b/src/Private/ServiceServer.ps1 @@ -11,6 +11,9 @@ function Start-PodeServiceServer { # script for the looping server $serverScript = { + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name 'ServiceServer' + try { while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { # the event object diff --git a/src/Private/SmtpServer.ps1 b/src/Private/SmtpServer.ps1 index e13c4367d..fb9d82df1 100644 --- a/src/Private/SmtpServer.ps1 +++ b/src/Private/SmtpServer.ps1 @@ -88,6 +88,8 @@ function Start-PodeSmtpServer { [int] $ThreadId ) + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name "SMTPEndpoint_$ThreadId" try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -187,6 +189,8 @@ function Start-PodeSmtpServer { [ValidateNotNull()] $Listener ) + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name 'SMTPEndpoint_KeepAlive' try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { diff --git a/src/Private/Tasks.ps1 b/src/Private/Tasks.ps1 index 1a4c1f7d2..cfdc1c4c1 100644 --- a/src/Private/Tasks.ps1 +++ b/src/Private/Tasks.ps1 @@ -11,6 +11,8 @@ function Start-PodeTaskHousekeeper { if ($PodeContext.Tasks.Results.Count -eq 0) { return } + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name '__pode_task_housekeeper__' $now = [datetime]::UtcNow diff --git a/src/Private/TcpServer.ps1 b/src/Private/TcpServer.ps1 index 06797fcf0..719edbd98 100644 --- a/src/Private/TcpServer.ps1 +++ b/src/Private/TcpServer.ps1 @@ -84,6 +84,8 @@ function Start-PodeTcpServer { [int] $ThreadId ) + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name "TCPEndpoint_$ThreadId" try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -205,6 +207,8 @@ function Start-PodeTcpServer { [ValidateNotNull()] $Listener ) + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name 'TCPEndpoint_KeepAlive' try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { diff --git a/src/Private/Timers.ps1 b/src/Private/Timers.ps1 index 3dc1a9db3..21b8ad5b9 100644 --- a/src/Private/Timers.ps1 +++ b/src/Private/Timers.ps1 @@ -19,6 +19,9 @@ function Start-PodeTimerRunspace { } $script = { + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name 'Timer' + while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { $_now = [DateTime]::Now diff --git a/src/Private/WebSockets.ps1 b/src/Private/WebSockets.ps1 index b760702c6..016d5488c 100644 --- a/src/Private/WebSockets.ps1 +++ b/src/Private/WebSockets.ps1 @@ -50,6 +50,8 @@ function Start-PodeWebSocketRunspace { [int] $ThreadId ) + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name "WebSocketEndpoint_$ThreadId" try { while ($Receiver.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -117,6 +119,8 @@ function Start-PodeWebSocketRunspace { [ValidateNotNull()] $Receiver ) + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name 'WebSocketEndpoint__KeepAlive' try { while ($Receiver.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { diff --git a/src/Public/Core.ps1 b/src/Public/Core.ps1 index 51303be3b..5b585f2d5 100644 --- a/src/Public/Core.ps1 +++ b/src/Public/Core.ps1 @@ -130,6 +130,10 @@ function Start-PodeServer { [switch] $EnableBreakpoints ) + # Store the name of the current runspace + $previousRunspaceName = Get-PodeCurrentRunspaceName + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name 'PodeServer' # ensure the session is clean $PodeContext = $null @@ -235,6 +239,9 @@ function Start-PodeServer { # clean the session $PodeContext = $null + + # Restore the name of the current runspace + Set-PodeCurrentRunspaceName -Name $previousRunspaceName } } diff --git a/src/Public/Utilities.ps1 b/src/Public/Utilities.ps1 index dde5ff1bb..e02f2314c 100644 --- a/src/Public/Utilities.ps1 +++ b/src/Public/Utilities.ps1 @@ -1364,4 +1364,63 @@ function ConvertFrom-PodeXml { } return $oHash -} \ No newline at end of file +} + + + +<# +.SYNOPSIS + Sets the name of the current runspace. + +.DESCRIPTION + The Set-PodeCurrentRunspaceName function assigns a specified name to the current runspace. + This can be useful for identifying and managing the runspace in scripts and during debugging. + +.PARAMETER Name + The name to assign to the current runspace. This parameter is mandatory. + +.EXAMPLE + Set-PodeCurrentRunspaceName -Name "MyRunspace" + This command sets the name of the current runspace to "MyRunspace". + +.NOTES + This is an internal function and may change in future releases of Pode. +#> + +function Set-PodeCurrentRunspaceName { + param ( + [Parameter(Mandatory = $true)] + [string] + $Name + ) + + # Get the current runspace + $currentRunspace = [System.Management.Automation.Runspaces.Runspace]::DefaultRunspace + + # Set the name of the current runspace + $currentRunspace.Name = $Name +} + +<# +.SYNOPSIS + Retrieves the name of the current PowerShell runspace. + +.DESCRIPTION + The Get-PodeCurrentRunspaceName function retrieves the name of the current PowerShell runspace. + This can be useful for debugging or logging purposes to identify the runspace in use. + +.EXAMPLE + Get-PodeCurrentRunspaceName + Returns the name of the current runspace. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> + +function Get-PodeCurrentRunspaceName { + # Get the current runspace + $currentRunspace = [System.Management.Automation.Runspaces.Runspace]::DefaultRunspace + + # Get the name of the current runspace + return $currentRunspace.Name +} From b2fdaccdf3a4825d9ea9f81554edb679e611a6e7 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sun, 8 Sep 2024 09:06:40 -0700 Subject: [PATCH 143/177] Update PSScriptAnalyzerSettings.psd1 --- PSScriptAnalyzerSettings.psd1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PSScriptAnalyzerSettings.psd1 b/PSScriptAnalyzerSettings.psd1 index 99840546d..06274e1a1 100644 --- a/PSScriptAnalyzerSettings.psd1 +++ b/PSScriptAnalyzerSettings.psd1 @@ -2,14 +2,14 @@ @{ Severity = @('Error', 'Warning', 'Information') - Rules = @{ + Rules = @{ PSReviewUnusedParameter = @{ CommandsToTraverse = @( - 'Where-Object','Remove-PodeRoute' + 'Where-Object', 'Remove-PodeRoute' ) } } - ExcludeRules = @( 'PSAvoidUsingPlainTextForPassword','PSUseShouldProcessForStateChangingFunctions', - 'PSAvoidUsingUsernameAndPasswordParams','PSUseProcessBlockForPipelineCommand','PSAvoidUsingConvertToSecureStringWithPlainText','PSReviewUnusedParameter' ) + ExcludeRules = @( 'PSAvoidUsingPlainTextForPassword', 'PSUseShouldProcessForStateChangingFunctions', + 'PSAvoidUsingUsernameAndPasswordParams', 'PSAvoidUsingConvertToSecureStringWithPlainText', 'PSReviewUnusedParameter' ) } \ No newline at end of file From e58512009b2fae8b98590c0bac7ede4b7486c356 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sun, 8 Sep 2024 09:31:53 -0700 Subject: [PATCH 144/177] Recovered from #1344 --- src/Locales/ar/Pode.psd1 | 1 + src/Locales/de/Pode.psd1 | 1 + src/Locales/en-us/Pode.psd1 | 1 + src/Locales/en/Pode.psd1 | 1 + src/Locales/es/Pode.psd1 | 1 + src/Locales/fr/Pode.psd1 | 1 + src/Locales/it/Pode.psd1 | 1 + src/Locales/ja/Pode.psd1 | 1 + src/Locales/ko/Pode.psd1 | 1 + src/Locales/nl/Pode.psd1 | 1 + src/Locales/pl/Pode.psd1 | 1 + src/Locales/pt/Pode.psd1 | 1 + src/Locales/zh/Pode.psd1 | 1 + src/Private/Cryptography.ps1 | 67 +-- src/Private/Helpers.ps1 | 272 ++++++---- src/Private/OpenApi.ps1 | 815 +++++++++++++++------------- src/Private/Responses.ps1 | 112 ++-- src/Private/Secrets.ps1 | 290 +++++----- src/Public/Access.ps1 | 63 ++- src/Public/Authentication.ps1 | 995 +++++++++++++++++++--------------- src/Public/Caching.ps1 | 59 +- src/Public/Core.ps1 | 275 +++++----- src/Public/Middleware.ps1 | 134 +++-- src/Public/OAComponents.ps1 | 153 ++++-- src/Public/OAProperties.ps1 | 17 +- src/Public/OpenApi.ps1 | 867 ++++++++++++++++------------- src/Public/Responses.ps1 | 612 ++++++++++++--------- src/Public/Routes.ps1 | 218 ++++---- src/Public/Secrets.ps1 | 116 ++-- src/Public/State.ps1 | 41 +- src/Public/Tasks.ps1 | 125 +++-- src/Public/Threading.ps1 | 174 +++--- src/Public/Timers.ps1 | 77 +-- src/Public/Utilities.ps1 | 314 +++++++---- tests/unit/Helpers.Tests.ps1 | 5 + tests/unit/OpenApi.Tests.ps1 | 104 +++- tests/unit/Routes.Tests.ps1 | 5 + tests/unit/State.Tests.ps1 | 9 + 38 files changed, 3408 insertions(+), 2524 deletions(-) diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index b6cd8b697..dcf744503 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -287,4 +287,5 @@ renamePodeOADefinitionTagExceptionMessage = "لا يمكن استخدام Rename-PodeOADefinitionTag داخل Select-PodeOADefinition 'ScriptBlock'." definitionTagChangeNotAllowedExceptionMessage = 'لا يمكن تغيير علامة التعريف لمسار.' getRequestBodyNotAllowedExceptionMessage = 'لا يمكن أن تحتوي عمليات {0} على محتوى الطلب.' + fnDoesNotAcceptArrayAsPipelineInputExceptionMessage = "الدالة '{0}' لا تقبل مصفوفة كمدخل لأنبوب البيانات." } diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index fb7b0c6ad..c50c03f1d 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -287,4 +287,5 @@ renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag kann nicht innerhalb eines 'ScriptBlock' von Select-PodeOADefinition verwendet werden." definitionTagChangeNotAllowedExceptionMessage = 'Definitionstag für eine Route kann nicht geändert werden.' getRequestBodyNotAllowedExceptionMessage = '{0}-Operationen können keinen Anforderungstext haben.' + fnDoesNotAcceptArrayAsPipelineInputExceptionMessage = "Die Funktion '{0}' akzeptiert kein Array als Pipeline-Eingabe." } \ No newline at end of file diff --git a/src/Locales/en-us/Pode.psd1 b/src/Locales/en-us/Pode.psd1 index 53aba0d1c..365687791 100644 --- a/src/Locales/en-us/Pode.psd1 +++ b/src/Locales/en-us/Pode.psd1 @@ -287,4 +287,5 @@ renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." definitionTagChangeNotAllowedExceptionMessage = 'Definition Tag for a Route cannot be changed.' getRequestBodyNotAllowedExceptionMessage = '{0} operations cannot have a Request Body.' + fnDoesNotAcceptArrayAsPipelineInputExceptionMessage = "The function '{0}' does not accept an array as pipeline input." } \ No newline at end of file diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 8f97eead4..470d17ebd 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -287,5 +287,6 @@ renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." definitionTagChangeNotAllowedExceptionMessage = 'Definition Tag for a Route cannot be changed.' getRequestBodyNotAllowedExceptionMessage = '{0} operations cannot have a Request Body.' + fnDoesNotAcceptArrayAsPipelineInputExceptionMessage = "The function '{0}' does not accept an array as pipeline input." } diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 9ca60ee62..2b9c8d4de 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -287,4 +287,5 @@ renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag no se puede usar dentro de un 'ScriptBlock' de Select-PodeOADefinition." definitionTagChangeNotAllowedExceptionMessage = 'La etiqueta de definición para una Route no se puede cambiar.' getRequestBodyNotAllowedExceptionMessage = 'Las operaciones {0} no pueden tener un cuerpo de solicitud.' + fnDoesNotAcceptArrayAsPipelineInputExceptionMessage = "La función '{0}' no acepta una matriz como entrada de canalización." } \ No newline at end of file diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index 8b9d047d3..e5e1a35c3 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -287,5 +287,6 @@ renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag ne peut pas être utilisé à l'intérieur d'un 'ScriptBlock' de Select-PodeOADefinition." definitionTagChangeNotAllowedExceptionMessage = 'Le tag de définition pour une Route ne peut pas être modifié.' getRequestBodyNotAllowedExceptionMessage = 'Les opérations {0} ne peuvent pas avoir de corps de requête.' + fnDoesNotAcceptArrayAsPipelineInputExceptionMessage = "La fonction '{0}' n'accepte pas un tableau en tant qu'entrée de pipeline." } diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index ff9ccfc73..2a7f2bdba 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -287,4 +287,5 @@ renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag non può essere utilizzato all'interno di un 'ScriptBlock' di Select-PodeOADefinition." definitionTagChangeNotAllowedExceptionMessage = 'Il tag di definizione per una Route non può essere cambiato.' getRequestBodyNotAllowedExceptionMessage = 'Le operazioni {0} non possono avere un corpo della richiesta.' + fnDoesNotAcceptArrayAsPipelineInputExceptionMessage = "La funzione '{0}' non accetta una matrice come input della pipeline." } \ No newline at end of file diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index ffc193a46..42778c84d 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -287,5 +287,6 @@ renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag は Select-PodeOADefinition 'ScriptBlock' 内で使用できません。" definitionTagChangeNotAllowedExceptionMessage = 'Routeの定義タグは変更できません。' getRequestBodyNotAllowedExceptionMessage = '{0}操作にはリクエストボディを含めることはできません。' + fnDoesNotAcceptArrayAsPipelineInputExceptionMessage = "関数 '{0}' は配列をパイプライン入力として受け付けません。" } diff --git a/src/Locales/ko/Pode.psd1 b/src/Locales/ko/Pode.psd1 index 25e3c3d10..2cc33db80 100644 --- a/src/Locales/ko/Pode.psd1 +++ b/src/Locales/ko/Pode.psd1 @@ -287,4 +287,5 @@ renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag은 Select-PodeOADefinition 'ScriptBlock' 내에서 사용할 수 없습니다." definitionTagChangeNotAllowedExceptionMessage = 'Route에 대한 정의 태그는 변경할 수 없습니다.' getRequestBodyNotAllowedExceptionMessage = '{0} 작업에는 요청 본문이 있을 수 없습니다.' + fnDoesNotAcceptArrayAsPipelineInputExceptionMessage = "함수 '{0}'은(는) 배열을 파이프라인 입력으로 받지 않습니다." } diff --git a/src/Locales/nl/Pode.psd1 b/src/Locales/nl/Pode.psd1 index 3f20960a0..a34255846 100644 --- a/src/Locales/nl/Pode.psd1 +++ b/src/Locales/nl/Pode.psd1 @@ -287,5 +287,6 @@ renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag kan niet worden gebruikt binnen een Select-PodeOADefinition 'ScriptBlock'." definitionTagChangeNotAllowedExceptionMessage = 'Definitietag voor een route kan niet worden gewijzigd.' getRequestBodyNotAllowedExceptionMessage = '{0}-operaties kunnen geen Request Body hebben.' + fnDoesNotAcceptArrayAsPipelineInputExceptionMessage = "De functie '{0}' accepteert geen array als pipeline-invoer." } diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index 6c4f2da03..3faea8427 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -287,5 +287,6 @@ renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag nie może być używany wewnątrz 'ScriptBlock' Select-PodeOADefinition." definitionTagChangeNotAllowedExceptionMessage = 'Tag definicji dla Route nie może zostać zmieniony.' getRequestBodyNotAllowedExceptionMessage = 'Operacje {0} nie mogą mieć treści żądania.' + fnDoesNotAcceptArrayAsPipelineInputExceptionMessage = "Funkcja '{0}' nie akceptuje tablicy jako wejścia potoku." } diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index df0073012..c93ea4a78 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -287,4 +287,5 @@ renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag não pode ser usado dentro de um 'ScriptBlock' Select-PodeOADefinition." definitionTagChangeNotAllowedExceptionMessage = 'A Tag de definição para uma Route não pode ser alterada.' getRequestBodyNotAllowedExceptionMessage = 'As operações {0} não podem ter um corpo de solicitação.' + fnDoesNotAcceptArrayAsPipelineInputExceptionMessage = "A função '{0}' não aceita uma matriz como entrada de pipeline." } \ No newline at end of file diff --git a/src/Locales/zh/Pode.psd1 b/src/Locales/zh/Pode.psd1 index daa9ad110..80e70979b 100644 --- a/src/Locales/zh/Pode.psd1 +++ b/src/Locales/zh/Pode.psd1 @@ -287,4 +287,5 @@ renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag 不能在 Select-PodeOADefinition 'ScriptBlock' 内使用。" definitionTagChangeNotAllowedExceptionMessage = 'Route的定义标签无法更改。' getRequestBodyNotAllowedExceptionMessage = '{0} 操作不能包含请求体。' + fnDoesNotAcceptArrayAsPipelineInputExceptionMessage = "函数 '{0}' 不接受数组作为管道输入。" } \ No newline at end of file diff --git a/src/Private/Cryptography.ps1 b/src/Private/Cryptography.ps1 index ff2675621..8ac0b86d0 100644 --- a/src/Private/Cryptography.ps1 +++ b/src/Private/Cryptography.ps1 @@ -23,7 +23,7 @@ $value = "MySecretValue" $secret = "MySecretKey" $hash = Invoke-PodeHMACSHA256Hash -Value $value -Secret $secret - Write-Host "HMAC-SHA256 hash: $hash" + Write-PodeHost "HMAC-SHA256 hash: $hash" This example computes the HMAC-SHA256 hash for the value "MySecretValue" using the secret key "MySecretKey". .NOTES @@ -87,7 +87,7 @@ function Invoke-PodeHMACSHA256Hash { $value = "MySecretValue" $secret = "MySecretKey" $hash = Invoke-PodeHMACSHA384Hash -Value $value -Secret $secret - Write-Host "Private HMAC-SHA384 hash: $hash" + Write-PodeHost "Private HMAC-SHA384 hash: $hash" This example computes the private HMAC-SHA384 hash for the value "MySecretValue" using the secret key "MySecretKey". @@ -152,7 +152,7 @@ function Invoke-PodeHMACSHA384Hash { $value = "MySecretValue" $secret = "MySecretKey" $hash = Invoke-PodeHMACSHA512Hash -Value $value -Secret $secret - Write-Host "Private HMAC-SHA512 hash: $hash" + Write-PodeHost "Private HMAC-SHA512 hash: $hash" This example computes the private HMAC-SHA512 hash for the value "MySecretValue" using the secret key "MySecretKey". @@ -346,12 +346,13 @@ function Invoke-PodeValueSign { [switch] $Strict ) + process { + if ($Strict) { + $Secret = ConvertTo-PodeStrictSecret -Secret $Secret + } - if ($Strict) { - $Secret = ConvertTo-PodeStrictSecret -Secret $Secret + return "s:$($Value).$(Invoke-PodeHMACSHA256Hash -Value $Value -Secret $Secret)" } - - return "s:$($Value).$(Invoke-PodeHMACSHA256Hash -Value $Value -Secret $Secret)" } function Invoke-PodeValueUnsign { @@ -371,32 +372,33 @@ function Invoke-PodeValueUnsign { [switch] $Strict ) + process { + # the signed value must start with "s:" + if (!$Value.StartsWith('s:')) { + return $null + } - # the signed value must start with "s:" - if (!$Value.StartsWith('s:')) { - return $null - } + # the signed value must contain a dot - splitting value and signature + $Value = $Value.Substring(2) + $periodIndex = $Value.LastIndexOf('.') + if ($periodIndex -eq -1) { + return $null + } - # the signed value must contain a dot - splitting value and signature - $Value = $Value.Substring(2) - $periodIndex = $Value.LastIndexOf('.') - if ($periodIndex -eq -1) { - return $null - } + if ($Strict) { + $Secret = ConvertTo-PodeStrictSecret -Secret $Secret + } - if ($Strict) { - $Secret = ConvertTo-PodeStrictSecret -Secret $Secret - } + # get the raw value and signature + $raw = $Value.Substring(0, $periodIndex) + $sig = $Value.Substring($periodIndex + 1) - # get the raw value and signature - $raw = $Value.Substring(0, $periodIndex) - $sig = $Value.Substring($periodIndex + 1) + if ((Invoke-PodeHMACSHA256Hash -Value $raw -Secret $Secret) -ne $sig) { + return $null + } - if ((Invoke-PodeHMACSHA256Hash -Value $raw -Secret $Secret) -ne $sig) { - return $null + return $raw } - - return $raw } function Test-PodeValueSigned { @@ -415,13 +417,14 @@ function Test-PodeValueSigned { [switch] $Strict ) + process { + if ([string]::IsNullOrEmpty($Value)) { + return $false + } - if ([string]::IsNullOrEmpty($Value)) { - return $false + $result = Invoke-PodeValueUnsign -Value $Value -Secret $Secret -Strict:$Strict + return ![string]::IsNullOrEmpty($result) } - - $result = Invoke-PodeValueUnsign -Value $Value -Secret $Secret -Strict:$Strict - return ![string]::IsNullOrEmpty($result) } function ConvertTo-PodeStrictSecret { diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index d9d09ded0..cf71e663b 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -1145,7 +1145,7 @@ function Join-PodeServerRoot { .EXAMPLE $myArray = "apple", "", "banana", "", "cherry" $filteredArray = Remove-PodeEmptyItemsFromArray -Array $myArray - Write-Host "Filtered array: $filteredArray" + Write-PodeHost "Filtered array: $filteredArray" This example removes empty items from the array and displays the filtered array. #> @@ -1157,12 +1157,25 @@ function Remove-PodeEmptyItemsFromArray { [Parameter(ValueFromPipeline = $true)] $Array ) - - if ($null -eq $Array) { - return @() + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() + } + process { + # Add the current piped-in value to the array + $pipelineValue += $_ } + end { + # Set Array to the array of values + if ($pipelineValue.Count -gt 1) { + $Array = $pipelineValue + } + if ($null -eq $Array) { + return @() + } - return @( @($Array -ne ([string]::Empty)) -ne $null ) + return @( @($Array -ne ([string]::Empty)) -ne $null ) + } } function Remove-PodeNullKeysFromHashtable { @@ -1171,36 +1184,48 @@ function Remove-PodeNullKeysFromHashtable { [hashtable] $Hashtable ) + begin { + $pipelineItemCount = 0 + } - foreach ($key in ($Hashtable.Clone()).Keys) { - if ($null -eq $Hashtable[$key]) { - $null = $Hashtable.Remove($key) - continue - } + process { + $pipelineItemCount++ + } - if (($Hashtable[$key] -is [string]) -and [string]::IsNullOrEmpty($Hashtable[$key])) { - $null = $Hashtable.Remove($key) - continue + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) } + foreach ($key in ($Hashtable.Clone()).Keys) { + if ($null -eq $Hashtable[$key]) { + $null = $Hashtable.Remove($key) + continue + } - if ($Hashtable[$key] -is [array]) { - if (($Hashtable[$key].Length -eq 1) -and ($null -eq $Hashtable[$key][0])) { + if (($Hashtable[$key] -is [string]) -and [string]::IsNullOrEmpty($Hashtable[$key])) { $null = $Hashtable.Remove($key) continue } - foreach ($item in $Hashtable[$key]) { - if (($item -is [hashtable]) -or ($item -is [System.Collections.Specialized.OrderedDictionary])) { - $item | Remove-PodeNullKeysFromHashtable + if ($Hashtable[$key] -is [array]) { + if (($Hashtable[$key].Length -eq 1) -and ($null -eq $Hashtable[$key][0])) { + $null = $Hashtable.Remove($key) + continue } - } - continue - } + foreach ($item in $Hashtable[$key]) { + if (($item -is [hashtable]) -or ($item -is [System.Collections.Specialized.OrderedDictionary])) { + $item | Remove-PodeNullKeysFromHashtable + } + } - if (($Hashtable[$key] -is [hashtable]) -or ($Hashtable[$key] -is [System.Collections.Specialized.OrderedDictionary])) { - $Hashtable[$key] | Remove-PodeNullKeysFromHashtable - continue + continue + } + + if (($Hashtable[$key] -is [hashtable]) -or ($Hashtable[$key] -is [System.Collections.Specialized.OrderedDictionary])) { + $Hashtable[$key] | Remove-PodeNullKeysFromHashtable + continue + } } } } @@ -1318,7 +1343,7 @@ function Get-PodeFileName { .EXAMPLE $exception = [System.Exception]::new("The network name is no longer available.") $isNetworkFailure = Test-PodeValidNetworkFailure -Exception $exception - Write-Host "Is network failure: $isNetworkFailure" + Write-PodeHost "Is network failure: $isNetworkFailure" This example tests whether the exception message "The network name is no longer available." indicates a network failure. #> @@ -1353,30 +1378,32 @@ function ConvertFrom-PodeHeaderQValue { $Value ) - $qs = [ordered]@{} + process { + $qs = [ordered]@{} - # return if no value - if ([string]::IsNullOrWhiteSpace($Value)) { - return $qs - } + # return if no value + if ([string]::IsNullOrWhiteSpace($Value)) { + return $qs + } - # split the values up - $parts = @($Value -isplit ',').Trim() + # split the values up + $parts = @($Value -isplit ',').Trim() - # go through each part and check its q-value - foreach ($part in $parts) { - # default of 1 if no q-value - if ($part.IndexOf(';q=') -eq -1) { - $qs[$part] = 1.0 - continue + # go through each part and check its q-value + foreach ($part in $parts) { + # default of 1 if no q-value + if ($part.IndexOf(';q=') -eq -1) { + $qs[$part] = 1.0 + continue + } + + # parse for q-value + $atoms = @($part -isplit ';q=') + $qs[$atoms[0]] = [double]$atoms[1] } - # parse for q-value - $atoms = @($part -isplit ';q=') - $qs[$atoms[0]] = [double]$atoms[1] + return $qs } - - return $qs } function Get-PodeAcceptEncoding { @@ -1645,7 +1672,7 @@ function New-PodeRequestException { function ConvertTo-PodeResponseContent { param( - [Parameter(ValueFromPipeline = $true)] + [Parameter(Position = 0, ValueFromPipeline = $true)] $InputObject, [Parameter()] @@ -1663,100 +1690,101 @@ function ConvertTo-PodeResponseContent { [switch] $AsHtml ) + process { + # split for the main content type + $ContentType = Split-PodeContentType -ContentType $ContentType - # split for the main content type - $ContentType = Split-PodeContentType -ContentType $ContentType - - # if there is no content-type then convert straight to string - if ([string]::IsNullOrWhiteSpace($ContentType)) { - return ([string]$InputObject) - } + # if there is no content-type then convert straight to string + if ([string]::IsNullOrWhiteSpace($ContentType)) { + return ([string]$InputObject) + } - # run action for the content type - switch ($ContentType) { - { $_ -match '^(.*\/)?(.*\+)?json$' } { - if ($InputObject -isnot [string]) { - if ($Depth -le 0) { - return (ConvertTo-Json -InputObject $InputObject -Compress) - } - else { - return (ConvertTo-Json -InputObject $InputObject -Depth $Depth -Compress) + # run action for the content type + switch ($ContentType) { + { $_ -match '^(.*\/)?(.*\+)?json$' } { + if ($InputObject -isnot [string]) { + if ($Depth -le 0) { + return (ConvertTo-Json -InputObject $InputObject -Compress) + } + else { + return (ConvertTo-Json -InputObject $InputObject -Depth $Depth -Compress) + } } - } - if ([string]::IsNullOrWhiteSpace($InputObject)) { - return '{}' + if ([string]::IsNullOrWhiteSpace($InputObject)) { + return '{}' + } } - } - { $_ -match '^(.*\/)?(.*\+)?yaml$' } { - if ($InputObject -isnot [string]) { - if ($Depth -le 0) { - return (ConvertTo-PodeYamlInternal -InputObject $InputObject ) + { $_ -match '^(.*\/)?(.*\+)?yaml$' } { + if ($InputObject -isnot [string]) { + if ($Depth -le 0) { + return (ConvertTo-PodeYamlInternal -InputObject $InputObject ) + } + else { + return (ConvertTo-PodeYamlInternal -InputObject $InputObject -Depth $Depth ) + } } - else { - return (ConvertTo-PodeYamlInternal -InputObject $InputObject -Depth $Depth ) + + if ([string]::IsNullOrWhiteSpace($InputObject)) { + return '[]' } } - if ([string]::IsNullOrWhiteSpace($InputObject)) { - return '[]' - } - } + { $_ -match '^(.*\/)?(.*\+)?xml$' } { + if ($InputObject -isnot [string]) { + $temp = @(foreach ($item in $InputObject) { + New-Object psobject -Property $item + }) - { $_ -match '^(.*\/)?(.*\+)?xml$' } { - if ($InputObject -isnot [string]) { - $temp = @(foreach ($item in $InputObject) { - New-Object psobject -Property $item - }) + return ($temp | ConvertTo-Xml -Depth $Depth -As String -NoTypeInformation) + } - return ($temp | ConvertTo-Xml -Depth $Depth -As String -NoTypeInformation) + if ([string]::IsNullOrWhiteSpace($InputObject)) { + return [string]::Empty + } } - if ([string]::IsNullOrWhiteSpace($InputObject)) { - return [string]::Empty - } - } + { $_ -ilike '*/csv' } { + if ($InputObject -isnot [string]) { + $temp = @(foreach ($item in $InputObject) { + New-Object psobject -Property $item + }) - { $_ -ilike '*/csv' } { - if ($InputObject -isnot [string]) { - $temp = @(foreach ($item in $InputObject) { - New-Object psobject -Property $item - }) + if (Test-PodeIsPSCore) { + $temp = ($temp | ConvertTo-Csv -Delimiter $Delimiter -IncludeTypeInformation:$false) + } + else { + $temp = ($temp | ConvertTo-Csv -Delimiter $Delimiter -NoTypeInformation) + } - if (Test-PodeIsPSCore) { - $temp = ($temp | ConvertTo-Csv -Delimiter $Delimiter -IncludeTypeInformation:$false) - } - else { - $temp = ($temp | ConvertTo-Csv -Delimiter $Delimiter -NoTypeInformation) + return ($temp -join ([environment]::NewLine)) } - return ($temp -join ([environment]::NewLine)) + if ([string]::IsNullOrWhiteSpace($InputObject)) { + return [string]::Empty + } } - if ([string]::IsNullOrWhiteSpace($InputObject)) { - return [string]::Empty - } - } + { $_ -ilike '*/html' } { + if ($InputObject -isnot [string]) { + return (($InputObject | ConvertTo-Html) -join ([environment]::NewLine)) + } - { $_ -ilike '*/html' } { - if ($InputObject -isnot [string]) { - return (($InputObject | ConvertTo-Html) -join ([environment]::NewLine)) + if ([string]::IsNullOrWhiteSpace($InputObject)) { + return [string]::Empty + } } - if ([string]::IsNullOrWhiteSpace($InputObject)) { - return [string]::Empty + { $_ -ilike '*/markdown' } { + if ($AsHtml -and ($PSVersionTable.PSVersion.Major -ge 7)) { + return ($InputObject | ConvertFrom-Markdown).Html + } } } - { $_ -ilike '*/markdown' } { - if ($AsHtml -and ($PSVersionTable.PSVersion.Major -ge 7)) { - return ($InputObject | ConvertFrom-Markdown).Html - } - } + return ([string]$InputObject) } - - return ([string]$InputObject) } function ConvertFrom-PodeRequestContent { @@ -3291,13 +3319,25 @@ function Clear-PodeHashtableInnerKey { [hashtable] $InputObject ) + begin { + $pipelineItemCount = 0 + } - if (Test-PodeIsEmpty $InputObject) { - return + process { + $pipelineItemCount++ } - $InputObject.Keys.Clone() | ForEach-Object { - $InputObject[$_].Clear() + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + if (Test-PodeIsEmpty $InputObject) { + return + } + + $InputObject.Keys.Clone() | ForEach-Object { + $InputObject[$_].Clear() + } } } @@ -3723,7 +3763,7 @@ function ConvertTo-PodeYamlInternal { [CmdletBinding()] [OutputType([string])] param ( - [parameter(Mandatory = $true, ValueFromPipeline = $false)] + [parameter(Mandatory = $true)] [AllowNull()] $InputObject, diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index 81be1e4e0..c0b9437ea 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -1,36 +1,36 @@ <# .SYNOPSIS -Converts content into an OpenAPI schema object format. + Converts content into an OpenAPI schema object format. .DESCRIPTION -The ConvertTo-PodeOAObjectSchema function takes a hashtable representing content and converts it into a format suitable for OpenAPI schema objects. -It validates the content types, processes array structures, and converts each property or reference into the appropriate OpenAPI schema format. -The function is designed to handle complex content structures for OpenAPI documentation within the Pode framework. + The ConvertTo-PodeOAObjectSchema function takes a hashtable representing content and converts it into a format suitable for OpenAPI schema objects. + It validates the content types, processes array structures, and converts each property or reference into the appropriate OpenAPI schema format. + The function is designed to handle complex content structures for OpenAPI documentation within the Pode framework. .PARAMETER Content -A hashtable representing the content to be converted into an OpenAPI schema object. The content can include various types and structures. + A hashtable representing the content to be converted into an OpenAPI schema object. The content can include various types and structures. .PARAMETER Properties -A switch to indicate if the content represents properties of an object schema. + A switch to indicate if the content represents properties of an object schema. .PARAMETER DefinitionTag -A string representing the definition tag to be used in the conversion process. This tag is essential for correctly formatting the content according to OpenAPI specifications. + A string representing the definition tag to be used in the conversion process. This tag is essential for correctly formatting the content according to OpenAPI specifications. .EXAMPLE -$schemaObject = ConvertTo-PodeOAObjectSchema -Content $myContent -DefinitionTag 'myTag' + $schemaObject = ConvertTo-PodeOAObjectSchema -Content $myContent -DefinitionTag 'myTag' -Converts a hashtable of content into an OpenAPI schema object using the definition tag 'myTag'. + Converts a hashtable of content into an OpenAPI schema object using the definition tag 'myTag'. .NOTES -This is an internal function and may change in future releases of Pode. + This is an internal function and may change in future releases of Pode. #> function ConvertTo-PodeOAObjectSchema { param( - [Parameter(ValueFromPipeline = $true)] + [Parameter( Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [hashtable] $Content, - [Parameter(ValueFromPipeline = $false)] + [Parameter()] [switch] $Properties, @@ -39,164 +39,178 @@ function ConvertTo-PodeOAObjectSchema { $DefinitionTag ) - - # Ensure all content types are valid MIME types - foreach ($type in $Content.Keys) { - if ($type -inotmatch '^(application|audio|image|message|model|multipart|text|video|\*)\/[\w\.\-\*]+(;[\s]*(charset|boundary)=[\w\.\-\*]+)*$|^"\*\/\*"$') { - throw ($PodeLocale.invalidContentTypeForSchemaExceptionMessage -f $type) #"Invalid content-type found for schema: $($type)" - } - } - # manage generic schema json conversion issue - if ( $Content.ContainsKey('*/*')) { - $Content['"*/*"'] = $Content['*/*'] - $Content.Remove('*/*') + begin { + $pipelineItemCount = 0 } - # convert each schema to OpenAPI format - # Initialize an empty hashtable for the schema - $obj = @{} - # Process each content type - $types = [string[]]$Content.Keys - foreach ($type in $types) { - # Initialize schema structure for the type - $obj[$type] = @{ } + process { - # Handle upload content, array structures, and shared component schema references - if ($Content[$type].__upload) { - if ($Content[$type].__array) { - $upload = $Content[$type].__content.__upload - } - else { - $upload = $Content[$type].__upload - } + $pipelineItemCount++ + } - if ($type -ieq 'multipart/form-data' -and $upload.content ) { - if ((Test-PodeOAVersion -Version 3.1 -DefinitionTag $DefinitionTag ) -and $upload.partContentMediaType) { - foreach ($key in $upload.content.Properties ) { - if ($key.type -eq 'string' -and $key.format -and $key.format -ieq 'binary' -or $key.format -ieq 'base64') { - $key.ContentMediaType = $PartContentMediaType - $key.remove('format') - break - } - } + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # Ensure all content types are valid MIME types + foreach ($type in $Content.Keys) { + if ($type -inotmatch '^(application|audio|image|message|model|multipart|text|video|\*)\/[\w\.\-\*]+(;[\s]*(charset|boundary)=[\w\.\-\*]+)*$|^"\*\/\*"$') { + # Invalid content-type found for schema: $($type) + throw ($PodeLocale.invalidContentTypeForSchemaExceptionMessage -f $type) + } + } + # manage generic schema json conversion issue + if ( $Content.ContainsKey('*/*')) { + $Content['"*/*"'] = $Content['*/*'] + $Content.Remove('*/*') + } + # convert each schema to OpenAPI format + # Initialize an empty hashtable for the schema + $obj = @{} + + # Process each content type + $types = [string[]]$Content.Keys + foreach ($type in $types) { + # Initialize schema structure for the type + $obj[$type] = @{ } + + # Handle upload content, array structures, and shared component schema references + if ($Content[$type].__upload) { + if ($Content[$type].__array) { + $upload = $Content[$type].__content.__upload } - $newContent = $upload.content - } - else { - if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag) { - $newContent = [ordered]@{ - 'type' = 'string' - 'format' = $upload.contentEncoding + else { + $upload = $Content[$type].__upload + } + + if ($type -ieq 'multipart/form-data' -and $upload.content ) { + if ((Test-PodeOAVersion -Version 3.1 -DefinitionTag $DefinitionTag ) -and $upload.partContentMediaType) { + foreach ($key in $upload.content.Properties ) { + if ($key.type -eq 'string' -and $key.format -and $key.format -ieq 'binary' -or $key.format -ieq 'base64') { + $key.ContentMediaType = $PartContentMediaType + $key.remove('format') + break + } + } } + $newContent = $upload.content } else { - if ($ContentEncoding -ieq 'Base64') { + if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag) { $newContent = [ordered]@{ - 'type' = 'string' - 'contentEncoding' = $upload.contentEncoding + 'type' = 'string' + 'format' = $upload.contentEncoding } } + else { + if ($ContentEncoding -ieq 'Base64') { + $newContent = [ordered]@{ + 'type' = 'string' + 'contentEncoding' = $upload.contentEncoding + } + } + } + } + if ($Content[$type].__array) { + $Content[$type].__content = $newContent + } + else { + $Content[$type] = $newContent } } + if ($Content[$type].__array) { - $Content[$type].__content = $newContent + $isArray = $true + $item = $Content[$type].__content + $obj[$type].schema = [ordered]@{ + 'type' = 'array' + 'items' = $null + } + if ( $Content[$type].__title) { + $obj[$type].schema.title = $Content[$type].__title + } + if ( $Content[$type].__uniqueItems) { + $obj[$type].schema.uniqueItems = $Content[$type].__uniqueItems + } + if ( $Content[$type].__maxItems) { + $obj[$type].schema.__maxItems = $Content[$type].__maxItems + } + if ( $Content[$type].minItems) { + $obj[$type].schema.minItems = $Content[$type].__minItems + } } else { - $Content[$type] = $newContent - } - } - - if ($Content[$type].__array) { - $isArray = $true - $item = $Content[$type].__content - $obj[$type].schema = [ordered]@{ - 'type' = 'array' - 'items' = $null - } - if ( $Content[$type].__title) { - $obj[$type].schema.title = $Content[$type].__title - } - if ( $Content[$type].__uniqueItems) { - $obj[$type].schema.uniqueItems = $Content[$type].__uniqueItems - } - if ( $Content[$type].__maxItems) { - $obj[$type].schema.__maxItems = $Content[$type].__maxItems - } - if ( $Content[$type].minItems) { - $obj[$type].schema.minItems = $Content[$type].__minItems - } - } - else { - $item = $Content[$type] - $isArray = $false - } - # Add set schema objects or empty content - if ($item -is [string]) { - if (![string]::IsNullOrEmpty($item )) { - #Check for empty reference - if (@('string', 'integer' , 'number', 'boolean' ) -icontains $item) { - if ($isArray) { - $obj[$type].schema.items = @{ - 'type' = $item.ToLower() + $item = $Content[$type] + $isArray = $false + } + # Add set schema objects or empty content + if ($item -is [string]) { + if (![string]::IsNullOrEmpty($item )) { + #Check for empty reference + if (@('string', 'integer' , 'number', 'boolean' ) -icontains $item) { + if ($isArray) { + $obj[$type].schema.items = @{ + 'type' = $item.ToLower() + } + } + else { + $obj[$type].schema = @{ + 'type' = $item.ToLower() + } } } else { - $obj[$type].schema = @{ - 'type' = $item.ToLower() + Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $item -PostValidation + if ($isArray) { + $obj[$type].schema.items = @{ + '$ref' = "#/components/schemas/$($item)" + } + } + else { + $obj[$type].schema = @{ + '$ref' = "#/components/schemas/$($item)" + } } } } else { - Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $item -PostValidation - if ($isArray) { - $obj[$type].schema.items = @{ - '$ref' = "#/components/schemas/$($item)" - } - } - else { - $obj[$type].schema = @{ - '$ref' = "#/components/schemas/$($item)" - } - } + # Create an empty content + $obj[$type] = @{} } } else { - # Create an empty content - $obj[$type] = @{} - } - } - else { - if ($item.Count -eq 0) { - $result = @{} - } - else { - $result = ($item | ConvertTo-PodeOASchemaProperty -DefinitionTag $DefinitionTag) - } - if ($Properties) { - if ($item.Name) { - $obj[$type].schema = @{ - 'properties' = @{ - $item.Name = $result - } - } + if ($item.Count -eq 0) { + $result = @{} } else { - # The Properties parameters cannot be used if the Property has no name - throw ($PodeLocale.propertiesParameterWithoutNameExceptionMessage) + $result = ($item | ConvertTo-PodeOASchemaProperty -DefinitionTag $DefinitionTag) } - } - else { - if ($isArray) { - $obj[$type].schema.items = $result + if ($Properties) { + if ($item.Name) { + $obj[$type].schema = @{ + 'properties' = @{ + $item.Name = $result + } + } + } + else { + # The Properties parameters cannot be used if the Property has no name + throw ($PodeLocale.propertiesParameterWithoutNameExceptionMessage) + } } else { - $obj[$type].schema = $result + if ($isArray) { + $obj[$type].schema.items = $result + } + else { + $obj[$type].schema = $result + } } } } - } - return $obj + return $obj + } } <# @@ -237,26 +251,26 @@ function Test-PodeOAComponentSchemaJson { <# .SYNOPSIS -Tests if a given name exists in the external path keys of OpenAPI definitions for specified definition tags. + Tests if a given name exists in the external path keys of OpenAPI definitions for specified definition tags. .DESCRIPTION -The Test-PodeOAComponentExternalPath function iterates over a list of definition tags and checks if a given name -is present in the external path keys of OpenAPI definitions within the Pode server context. This function is typically -used to validate if a specific component name is already defined in the external paths of the OpenAPI documentation. + The Test-PodeOAComponentExternalPath function iterates over a list of definition tags and checks if a given name + is present in the external path keys of OpenAPI definitions within the Pode server context. This function is typically + used to validate if a specific component name is already defined in the external paths of the OpenAPI documentation. .PARAMETER Name -The name of the external path component to be checked within the OpenAPI definitions. + The name of the external path component to be checked within the OpenAPI definitions. .PARAMETER DefinitionTag -An array of definition tags against which the existence of the name will be checked in the OpenAPI definitions. + An array of definition tags against which the existence of the name will be checked in the OpenAPI definitions. .EXAMPLE -$exists = Test-PodeOAComponentExternalPath -Name 'MyComponentName' -DefinitionTag @('tag1', 'tag2') + $exists = Test-PodeOAComponentExternalPath -Name 'MyComponentName' -DefinitionTag @('tag1', 'tag2') -Checks if 'MyComponentName' exists in the external path keys of OpenAPI definitions for 'tag1' and 'tag2'. + Checks if 'MyComponentName' exists in the external path keys of OpenAPI definitions for 'tag1' and 'tag2'. .NOTES -This is an internal function and may change in future releases of Pode. + This is an internal function and may change in future releases of Pode. #> function Test-PodeOAComponentExternalPath { param( @@ -285,27 +299,27 @@ function Test-PodeOAComponentExternalPath { <# .SYNOPSIS -Converts a property into an OpenAPI 'Of' property structure based on a given definition tag. + Converts a property into an OpenAPI 'Of' property structure based on a given definition tag. .DESCRIPTION -The ConvertTo-PodeOAOfProperty function is used to convert a given property into one of the OpenAPI 'Of' properties: -allOf, oneOf, or anyOf. These structures are used in OpenAPI documentation to define complex types. The function -constructs the appropriate structure based on the type of the property and the definition tag provided. + The ConvertTo-PodeOAOfProperty function is used to convert a given property into one of the OpenAPI 'Of' properties: + allOf, oneOf, or anyOf. These structures are used in OpenAPI documentation to define complex types. The function + constructs the appropriate structure based on the type of the property and the definition tag provided. .PARAMETER Property -A hashtable representing the property to be converted. It should contain the type (allOf, oneOf, or anyOf) and -potentially a list of schemas. + A hashtable representing the property to be converted. It should contain the type (allOf, oneOf, or anyOf) and + potentially a list of schemas. .PARAMETER DefinitionTag -A mandatory string parameter specifying the definition tag in OpenAPI documentation, used for validating components. + A mandatory string parameter specifying the definition tag in OpenAPI documentation, used for validating components. .EXAMPLE -$ofProperty = ConvertTo-PodeOAOfProperty -Property $myProperty -DefinitionTag 'myTag' + $ofProperty = ConvertTo-PodeOAOfProperty -Property $myProperty -DefinitionTag 'myTag' -Converts a given property into an OpenAPI 'Of' structure using the specified definition tag. + Converts a given property into an OpenAPI 'Of' structure using the specified definition tag. .NOTES -This is an internal function and may change in future releases of Pode. + This is an internal function and may change in future releases of Pode. #> function ConvertTo-PodeOAOfProperty { param ( @@ -400,7 +414,7 @@ function ConvertTo-PodeOAOfProperty { #> function ConvertTo-PodeOASchemaProperty { param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [hashtable] $Property, @@ -411,54 +425,67 @@ function ConvertTo-PodeOASchemaProperty { [string] $DefinitionTag ) + begin { + $pipelineItemCount = 0 + } - if ( @('allof', 'oneof', 'anyof') -icontains $Property.type) { - $schema = ConvertTo-PodeOAofProperty -DefinitionTag $DefinitionTag -Property $Property + process { + + $pipelineItemCount++ } - else { - # base schema type - $schema = [ordered]@{ } - if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag ) { - if ($Property.type -is [string[]]) { - # Multi type properties requeired OpenApi Version 3.1 or above - throw ($PodeLocale.multiTypePropertiesRequireOpenApi31ExceptionMessage) - } - $schema['type'] = $Property.type.ToLower() + + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + + if ( @('allof', 'oneof', 'anyof') -icontains $Property.type) { + $schema = ConvertTo-PodeOAofProperty -DefinitionTag $DefinitionTag -Property $Property } else { - $schema.type = @($Property.type.ToLower()) - if ($Property.nullable) { - $schema.type += 'null' + # base schema type + $schema = [ordered]@{ } + if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag ) { + if ($Property.type -is [string[]]) { + # Multi type properties requeired OpenApi Version 3.1 or above + throw ($PodeLocale.multiTypePropertiesRequireOpenApi31ExceptionMessage) + } + $schema['type'] = $Property.type.ToLower() + } + else { + $schema.type = @($Property.type.ToLower()) + if ($Property.nullable) { + $schema.type += 'null' + } } } - } - if ($Property.externalDocs) { - $schema['externalDocs'] = $Property.externalDocs - } + if ($Property.externalDocs) { + $schema['externalDocs'] = $Property.externalDocs + } - if (!$NoDescription -and $Property.description) { - $schema['description'] = $Property.description - } + if (!$NoDescription -and $Property.description) { + $schema['description'] = $Property.description + } - if ($Property.default) { - $schema['default'] = $Property.default - } + if ($Property.default) { + $schema['default'] = $Property.default + } - if ($Property.deprecated) { - $schema['deprecated'] = $Property.deprecated - } - if ($Property.nullable -and (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag )) { - $schema['nullable'] = $Property.nullable - } + if ($Property.deprecated) { + $schema['deprecated'] = $Property.deprecated + } + if ($Property.nullable -and (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag )) { + $schema['nullable'] = $Property.nullable + } - if ($Property.writeOnly) { - $schema['writeOnly'] = $Property.writeOnly - } + if ($Property.writeOnly) { + $schema['writeOnly'] = $Property.writeOnly + } - if ($Property.readOnly) { - $schema['readOnly'] = $Property.readOnly - } + if ($Property.readOnly) { + $schema['readOnly'] = $Property.readOnly + } if ($Property.example) { if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag ) { @@ -482,9 +509,9 @@ function ConvertTo-PodeOASchemaProperty { $schema['maximum'] = $Property.maximum } - if ($Property.exclusiveMaximum) { - $schema['exclusiveMaximum'] = $Property.exclusiveMaximum - } + if ($Property.exclusiveMaximum) { + $schema['exclusiveMaximum'] = $Property.exclusiveMaximum + } if ($Property.exclusiveMinimum) { $schema['exclusiveMinimum'] = $Property.exclusiveMinimum @@ -512,9 +539,9 @@ function ConvertTo-PodeOASchemaProperty { $schema['multipleOf'] = $Property.multipleOf } - if ($Property.pattern) { - $schema['pattern'] = $Property.pattern - } + if ($Property.pattern) { + $schema['pattern'] = $Property.pattern + } if ($Property.ContainsKey('minLength')) { $schema['minLength'] = $Property.minLength @@ -524,18 +551,18 @@ function ConvertTo-PodeOASchemaProperty { $schema['maxLength'] = $Property.maxLength } - if ($Property.xml ) { - $schema['xml'] = $Property.xml - } - - if (Test-PodeOAVersion -Version 3.1 -DefinitionTag $DefinitionTag ) { - if ($Property.ContentMediaType) { - $schema['contentMediaType'] = $Property.ContentMediaType + if ($Property.xml ) { + $schema['xml'] = $Property.xml } - if ($Property.ContentEncoding) { - $schema['contentEncoding'] = $Property.ContentEncoding + + if (Test-PodeOAVersion -Version 3.1 -DefinitionTag $DefinitionTag ) { + if ($Property.ContentMediaType) { + $schema['contentMediaType'] = $Property.ContentMediaType + } + if ($Property.ContentEncoding) { + $schema['contentEncoding'] = $Property.ContentEncoding + } } - } # are we using an array? if ($Property.array) { @@ -547,65 +574,65 @@ function ConvertTo-PodeOASchemaProperty { $schema['minItems'] = $Property.minItems } - if ($Property.uniqueItems ) { - $schema['uniqueItems'] = $Property.uniqueItems - } - - $schema['type'] = 'array' - if ($Property.type -ieq 'schema') { - Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $Property['schema'] -PostValidation - $schema['items'] = @{ '$ref' = "#/components/schemas/$($Property['schema'])" } - } - else { - $Property.array = $false - if ($Property.xml) { - $xmlFromProperties = $Property.xml - $Property.Remove('xml') + if ($Property.uniqueItems ) { + $schema['uniqueItems'] = $Property.uniqueItems } - $schema['items'] = ($Property | ConvertTo-PodeOASchemaProperty -DefinitionTag $DefinitionTag) - $Property.array = $true - if ($xmlFromProperties) { - $Property.xml = $xmlFromProperties + + $schema['type'] = 'array' + if ($Property.type -ieq 'schema') { + Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $Property['schema'] -PostValidation + $schema['items'] = @{ '$ref' = "#/components/schemas/$($Property['schema'])" } } + else { + $Property.array = $false + if ($Property.xml) { + $xmlFromProperties = $Property.xml + $Property.Remove('xml') + } + $schema['items'] = ($Property | ConvertTo-PodeOASchemaProperty -DefinitionTag $DefinitionTag) + $Property.array = $true + if ($xmlFromProperties) { + $Property.xml = $xmlFromProperties + } - if ($Property.xmlItemName) { - $schema.items.xml = @{'name' = $Property.xmlItemName } + if ($Property.xmlItemName) { + $schema.items.xml = @{'name' = $Property.xmlItemName } + } } + return $schema } - return $schema - } - else { - #format is not applicable to array - if ($Property.format) { - $schema['format'] = $Property.format - } + else { + #format is not applicable to array + if ($Property.format) { + $schema['format'] = $Property.format + } - # schema refs - if ($Property.type -ieq 'schema') { - Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $Property['schema'] -PostValidation - $schema = @{ - '$ref' = "#/components/schemas/$($Property['schema'])" + # schema refs + if ($Property.type -ieq 'schema') { + Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $Property['schema'] -PostValidation + $schema = @{ + '$ref' = "#/components/schemas/$($Property['schema'])" + } + } + #only if it's not an array + if ($Property.enum ) { + $schema['enum'] = $Property.enum } } - #only if it's not an array - if ($Property.enum ) { - $schema['enum'] = $Property.enum - } - } - if ($Property.object) { - # are we using an object? - $Property.object = $false + if ($Property.object) { + # are we using an object? + $Property.object = $false - $schema = @{ - type = 'object' - properties = (ConvertTo-PodeOASchemaObjectProperty -DefinitionTag $DefinitionTag -Properties $Property) - } - $Property.object = $true - if ($Property.required) { - $schema['required'] = @($Property.name) + $schema = @{ + type = 'object' + properties = (ConvertTo-PodeOASchemaObjectProperty -DefinitionTag $DefinitionTag -Properties $Property) + } + $Property.object = $true + if ($Property.required) { + $schema['required'] = @($Property.name) + } } - } if ($Property.type -ieq 'object') { $schema['properties'] = @{} @@ -623,19 +650,26 @@ function ConvertTo-PodeOASchemaProperty { $schema += ConvertTo-PodeOAofProperty -DefinitionTag $DefinitionTag -Property $prop } + } } - } - if ($Property.properties) { - $schema['properties'] += (ConvertTo-PodeOASchemaObjectProperty -DefinitionTag $DefinitionTag -Properties $Property.properties) - $RequiredList = @(($Property.properties | Where-Object { $_.required }) ) - if ( $RequiredList.Count -gt 0) { - $schema['required'] = @($RequiredList.name) + if ($Property.properties) { + $schema['properties'] = (ConvertTo-PodeOASchemaObjectProperty -DefinitionTag $DefinitionTag -Properties $Property.properties) + $RequiredList = @(($Property.properties | Where-Object { $_.required }) ) + if ( $RequiredList.Count -gt 0) { + $schema['required'] = @($RequiredList.name) + } + } + else { + #if noproperties parameter create an empty properties + if ( $Property.properties.Count -eq 1 -and $null -eq $Property.properties[0]) { + $schema['properties'] = @{} + } } - } - if ($Property.minProperties) { - $schema['minProperties'] = $Property.minProperties - } + + if ($Property.minProperties) { + $schema['minProperties'] = $Property.minProperties + } if ($Property.maxProperties) { $schema['maxProperties'] = $Property.maxProperties @@ -651,13 +685,13 @@ function ConvertTo-PodeOASchemaProperty { } } - if ($Property.discriminator) { - $schema['discriminator'] = $Property.discriminator + if ($Property.discriminator) { + $schema['discriminator'] = $Property.discriminator + } } - } - - return $schema + return $schema + } } <# @@ -1198,46 +1232,47 @@ function ConvertTo-PodeOAPropertyFromCmdletParameter { [System.Management.Automation.ParameterMetadata] $Parameter ) + process { + if ($Parameter.SwitchParameter -or ($Parameter.ParameterType.Name -ieq 'boolean')) { + New-PodeOABoolProperty -Name $Parameter.Name + } + else { + switch ($Parameter.ParameterType.Name) { + { @('int32', 'int64') -icontains $_ } { + New-PodeOAIntProperty -Name $Parameter.Name -Format $_ + } - if ($Parameter.SwitchParameter -or ($Parameter.ParameterType.Name -ieq 'boolean')) { - New-PodeOABoolProperty -Name $Parameter.Name - } - else { - switch ($Parameter.ParameterType.Name) { - { @('int32', 'int64') -icontains $_ } { - New-PodeOAIntProperty -Name $Parameter.Name -Format $_ - } - - { @('double', 'float') -icontains $_ } { - New-PodeOANumberProperty -Name $Parameter.Name -Format $_ + { @('double', 'float') -icontains $_ } { + New-PodeOANumberProperty -Name $Parameter.Name -Format $_ + } } } - } - New-PodeOAStringProperty -Name $Parameter.Name + New-PodeOAStringProperty -Name $Parameter.Name + } } <# .SYNOPSIS -Creates a base OpenAPI object structure. + Creates a base OpenAPI object structure. .DESCRIPTION -The Get-PodeOABaseObject function generates a foundational structure for an OpenAPI object. -This structure includes empty ordered dictionaries for info, paths, webhooks, components, and other OpenAPI elements. -It is used as a base template for building OpenAPI documentation in the Pode framework. + The Get-PodeOABaseObject function generates a foundational structure for an OpenAPI object. + This structure includes empty ordered dictionaries for info, paths, webhooks, components, and other OpenAPI elements. + It is used as a base template for building OpenAPI documentation in the Pode framework. .OUTPUTS -Hashtable -Returns a hashtable representing the base structure of an OpenAPI object. + Hashtable + Returns a hashtable representing the base structure of an OpenAPI object. .EXAMPLE -$baseObject = Get-PodeOABaseObject + $baseObject = Get-PodeOABaseObject -This example creates a base OpenAPI object structure. + This example creates a base OpenAPI object structure. .NOTES -This is an internal function and may change in future releases of Pode. + This is an internal function and may change in future releases of Pode. #> function Get-PodeOABaseObject { # Returns a base template for an OpenAPI object @@ -1622,30 +1657,30 @@ function Resolve-PodeOAReference { <# .SYNOPSIS -Creates a new OpenAPI property object based on provided parameters. + Creates a new OpenAPI property object based on provided parameters. .DESCRIPTION -The New-PodeOAPropertyInternal function constructs an OpenAPI property object using parameters like type, name, -description, and various other attributes. It is used internally for building OpenAPI documentation elements in the Pode framework. + The New-PodeOAPropertyInternal function constructs an OpenAPI property object using parameters like type, name, + description, and various other attributes. It is used internally for building OpenAPI documentation elements in the Pode framework. .PARAMETER Type -The type of the property. This parameter is optional if the type is specified in the Params hashtable. + The type of the property. This parameter is optional if the type is specified in the Params hashtable. .PARAMETER Params -A hashtable containing various attributes of the property such as name, description, format, and constraints like -required, readOnly, writeOnly, etc. + A hashtable containing various attributes of the property such as name, description, format, and constraints like + required, readOnly, writeOnly, etc. .OUTPUTS -System.Collections.Specialized.OrderedDictionary -An ordered dictionary representing the constructed OpenAPI property object. + System.Collections.Specialized.OrderedDictionary + An ordered dictionary representing the constructed OpenAPI property object. .EXAMPLE -$property = New-PodeOAPropertyInternal -Type 'string' -Params $myParams + $property = New-PodeOAPropertyInternal -Type 'string' -Params $myParams -Demonstrates how to create an OpenAPI property object of type 'string' using the specified parameters. + Demonstrates how to create an OpenAPI property object of type 'string' using the specified parameters. .NOTES -This is an internal function and may change in future releases of Pode. + This is an internal function and may change in future releases of Pode. #> function New-PodeOAPropertyInternal { [OutputType([System.Collections.Specialized.OrderedDictionary])] @@ -1769,23 +1804,23 @@ function New-PodeOAPropertyInternal { <# .SYNOPSIS -Converts header properties to a format compliant with OpenAPI specifications. + Converts header properties to a format compliant with OpenAPI specifications. .DESCRIPTION -The ConvertTo-PodeOAHeaderProperty function is designed to take an array of hashtables representing header properties and -convert them into a structure suitable for OpenAPI documentation. It ensures that each header property includes a name and -schema definition and can handle additional attributes like description. + The ConvertTo-PodeOAHeaderProperty function is designed to take an array of hashtables representing header properties and + convert them into a structure suitable for OpenAPI documentation. It ensures that each header property includes a name and + schema definition and can handle additional attributes like description. .PARAMETER Headers -An array of hashtables, where each hashtable represents a header property with attributes like name, type, description, etc. + An array of hashtables, where each hashtable represents a header property with attributes like name, type, description, etc. .EXAMPLE -$headerProperties = ConvertTo-PodeOAHeaderProperty -Headers $myHeaders + $headerProperties = ConvertTo-PodeOAHeaderProperty -Headers $myHeaders -This example demonstrates how to convert an array of header properties into a format suitable for OpenAPI documentation. + This example demonstrates how to convert an array of header properties into a format suitable for OpenAPI documentation. .NOTES -This is an internal function and may change in future releases of Pode. + This is an internal function and may change in future releases of Pode. #> function ConvertTo-PodeOAHeaderProperty { param ( @@ -1794,59 +1829,76 @@ function ConvertTo-PodeOAHeaderProperty { $Headers ) - $elems = @{} + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() - foreach ($e in $Headers) { - # Ensure each header has a name - if ($e.name) { - $elems.$($e.name) = @{} - # Add description if present - if ($e.description) { - $elems.$($e.name).description = $e.description - } - # Define the schema, including the type and any additional properties - $elems.$($e.name).schema = @{ - type = $($e.type) - } - foreach ($k in $e.keys) { - if (@('name', 'description') -notcontains $k) { - $elems.$($e.name).schema.$k = $e.$k + $elems = @{} + } + + process { + # Add the current piped-in value to the array + $pipelineValue += $_ + } + + end { + # Set Headers to the array of values + if ($pipelineValue.Count -gt 1) { + $Headers = $pipelineValue + } + foreach ($e in $Headers) { + # Ensure each header has a name + if ($e.name) { + $elems.$($e.name) = @{} + # Add description if present + if ($e.description) { + $elems.$($e.name).description = $e.description + } + # Define the schema, including the type and any additional properties + $elems.$($e.name).schema = @{ + type = $($e.type) + } + foreach ($k in $e.keys) { + if (@('name', 'description') -notcontains $k) { + $elems.$($e.name).schema.$k = $e.$k + } } } + else { + # Header requires a name when used in an encoding context + throw ($PodeLocale.headerMustHaveNameInEncodingContextExceptionMessage) + + } } - else { - # Header requires a name when used in an encoding context - throw ($PodeLocale.headerMustHaveNameInEncodingContextExceptionMessage) - } - } - return $elems + return $elems + } } <# .SYNOPSIS -Creates a new OpenAPI callback component for a given definition tag. + Creates a new OpenAPI callback component for a given definition tag. .DESCRIPTION -The New-PodeOAComponentCallBackInternal function constructs an OpenAPI callback component based on provided parameters. -This function is designed for internal use within the Pode framework to define callbacks in OpenAPI documentation. -It handles the creation of callback structures including the path, HTTP method, request bodies, and responses -based on the given definition tag. + The New-PodeOAComponentCallBackInternal function constructs an OpenAPI callback component based on provided parameters. + This function is designed for internal use within the Pode framework to define callbacks in OpenAPI documentation. + It handles the creation of callback structures including the path, HTTP method, request bodies, and responses + based on the given definition tag. .PARAMETER Params -A hashtable containing parameters for the callback component, such as Method, Path, RequestBody, and Responses. + A hashtable containing parameters for the callback component, such as Method, Path, RequestBody, and Responses. .PARAMETER DefinitionTag -A mandatory string parameter that specifies the definition tag in OpenAPI documentation. + A mandatory string parameter that specifies the definition tag in OpenAPI documentation. .EXAMPLE -$callback = New-PodeOAComponentCallBackInternal -Params $myParams -DefinitionTag 'myTag' + $callback = New-PodeOAComponentCallBackInternal -Params $myParams -DefinitionTag 'myTag' -This example demonstrates how to create an OpenAPI callback component for 'myTag' using the provided parameters. + This example demonstrates how to create an OpenAPI callback component for 'myTag' using the provided parameters. .NOTES -This is an internal function and may change in future releases of Pode. + This is an internal function and may change in future releases of Pode. #> function New-PodeOAComponentCallBackInternal { param( @@ -1884,33 +1936,30 @@ function New-PodeOAComponentCallBackInternal { } - - - <# .SYNOPSIS -Creates a new OpenAPI response object based on provided parameters and a definition tag. + Creates a new OpenAPI response object based on provided parameters and a definition tag. -.DESCRIPTION -The New-PodeOResponseInternal function constructs an OpenAPI response object using provided parameters. -It sets a description for the status code, references existing components if specified, -and builds content-type and header schemas. This function is intended for internal use within the -Pode framework for API documentation purposes. + .DESCRIPTION + The New-PodeOResponseInternal function constructs an OpenAPI response object using provided parameters. + It sets a description for the status code, references existing components if specified, + and builds content-type and header schemas. This function is intended for internal use within the + Pode framework for API documentation purposes. -.PARAMETER Params -A hashtable containing parameters for building the OpenAPI response object, including description, -status code, content, headers, links, and reference to existing components. + .PARAMETER Params + A hashtable containing parameters for building the OpenAPI response object, including description, + status code, content, headers, links, and reference to existing components. -.PARAMETER DefinitionTag -A mandatory string parameter that specifies the definition tag in OpenAPI documentation. + .PARAMETER DefinitionTag + A mandatory string parameter that specifies the definition tag in OpenAPI documentation. -.EXAMPLE -$response = New-PodeOResponseInternal -Params $myParams -DefinitionTag 'myTag' + .EXAMPLE + $response = New-PodeOResponseInternal -Params $myParams -DefinitionTag 'myTag' -This example demonstrates how to create an OpenAPI response object for 'myTag' using the provided parameters. + This example demonstrates how to create an OpenAPI response object for 'myTag' using the provided parameters. -.NOTES -This is an internal function and may change in future releases of Pode. + .NOTES + This is an internal function and may change in future releases of Pode. #> function New-PodeOResponseInternal { param( @@ -1996,24 +2045,24 @@ function New-PodeOResponseInternal { <# .SYNOPSIS -Creates a new OpenAPI response link object. + Creates a new OpenAPI response link object. .DESCRIPTION -The New-PodeOAResponseLinkInternal function generates an OpenAPI response link object from provided parameters. -This includes setting up descriptions, operation IDs, references, parameters, and request bodies for the link. -This function is designed for internal use within the Pode framework to facilitate the creation of response -link objects in OpenAPI documentation. + The New-PodeOAResponseLinkInternal function generates an OpenAPI response link object from provided parameters. + This includes setting up descriptions, operation IDs, references, parameters, and request bodies for the link. + This function is designed for internal use within the Pode framework to facilitate the creation of response + link objects in OpenAPI documentation. .PARAMETER Params -A hashtable of parameters for the OpenAPI response link. + A hashtable of parameters for the OpenAPI response link. .EXAMPLE -$link = New-PodeOAResponseLinkInternal -Params $myParams + $link = New-PodeOAResponseLinkInternal -Params $myParams -Generates a new OpenAPI response link object using the provided parameters in $myParams. + Generates a new OpenAPI response link object using the provided parameters in $myParams. .NOTES -This is an internal function and may change in future releases of Pode. + This is an internal function and may change in future releases of Pode. #> function New-PodeOAResponseLinkInternal { param( @@ -2115,33 +2164,33 @@ function Test-PodeOADefinitionInternal { <# .SYNOPSIS -Check the OpenAPI component exist (Internal Function) + Check the OpenAPI component exist (Internal Function) .DESCRIPTION -Check the OpenAPI component exist (Internal Function) + Check the OpenAPI component exist (Internal Function) .PARAMETER Field -The component type + The component type .PARAMETER Name -The component Name + The component Name .PARAMETER DefinitionTag -An Array of strings representing the unique tag for the API specification. -This tag helps in distinguishing between different versions or types of API specifications within the application. -You can use this tag to reference the specific API documentation, schema, or version that your function interacts with. + An Array of strings representing the unique tag for the API specification. + This tag helps in distinguishing between different versions or types of API specifications within the application. + You can use this tag to reference the specific API documentation, schema, or version that your function interacts with. .PARAMETER ThrowException -Generate an exception if the component doesn't exist + Generate an exception if the component doesn't exist .PARAMETER PostValidation -Postpone the check before the server start + Postpone the check before the server start .EXAMPLE -Test-PodeOAComponentInternal -Field 'responses' -Name 'myresponse' -DefinitionTag 'default' + Test-PodeOAComponentInternal -Field 'responses' -Name 'myresponse' -DefinitionTag 'default' .NOTES -This is an internal function and may change in future releases of Pode. + This is an internal function and may change in future releases of Pode. #> function Test-PodeOAComponentInternal { param( @@ -2192,4 +2241,4 @@ function Test-PodeOAComponentInternal { return $true } } -} +} \ No newline at end of file diff --git a/src/Private/Responses.ps1 b/src/Private/Responses.ps1 index 920230003..075daa0c0 100644 --- a/src/Private/Responses.ps1 +++ b/src/Private/Responses.ps1 @@ -133,7 +133,7 @@ This is an internal function and may change in future releases of Pode. function Write-PodeFileResponseInternal { [CmdletBinding()] param ( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [ValidateNotNull()] [string] $Path, @@ -159,68 +159,80 @@ function Write-PodeFileResponseInternal { [switch] $FileBrowser ) - - # Attempt to retrieve information about the path - $pathInfo = Test-PodePath -Path $Path -Force -ReturnItem -FailOnDirectory:(!$FileBrowser) - - if (!$pathinfo) { - return + begin { + $pipelineItemCount = 0 } - # Check if the path is a directory - if ( $pathInfo.PSIsContainer) { - # If directory browsing is enabled, use the directory response function - Write-PodeDirectoryResponseInternal -Path $Path + process { + $pipelineItemCount++ } - else { - # are we dealing with a dynamic file for the view engine? (ignore html) - # Determine if the file is dynamic and should be processed by the view engine - $mainExt = $pathInfo.Extension.TrimStart('.') - # generate dynamic content - if (![string]::IsNullOrWhiteSpace($mainExt) -and ( + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # Attempt to retrieve information about the path + $pathInfo = Test-PodePath -Path $Path -Force -ReturnItem -FailOnDirectory:(!$FileBrowser) + + if (!$pathinfo) { + return + } + + # Check if the path is a directory + if ( $pathInfo.PSIsContainer) { + # If directory browsing is enabled, use the directory response function + Write-PodeDirectoryResponseInternal -Path $Path + } + else { + # are we dealing with a dynamic file for the view engine? (ignore html) + # Determine if the file is dynamic and should be processed by the view engine + $mainExt = $pathInfo.Extension.TrimStart('.') + + # generate dynamic content + if (![string]::IsNullOrWhiteSpace($mainExt) -and ( ($mainExt -ieq 'pode') -or ($mainExt -ieq $PodeContext.Server.ViewEngine.Extension -and $PodeContext.Server.ViewEngine.IsDynamic) - ) - ) { - # Process dynamic content with the view engine - $content = Get-PodeFileContentUsingViewEngine -Path $Path -Data $Data + ) + ) { + # Process dynamic content with the view engine + $content = Get-PodeFileContentUsingViewEngine -Path $Path -Data $Data - # Determine the correct content type for the response - # get the sub-file extension, if empty, use original - $subExt = [System.IO.Path]::GetExtension($pathInfo.BaseName).TrimStart('.') + # Determine the correct content type for the response + # get the sub-file extension, if empty, use original + $subExt = [System.IO.Path]::GetExtension($pathInfo.BaseName).TrimStart('.') - $subExt = (Protect-PodeValue -Value $subExt -Default $mainExt) + $subExt = (Protect-PodeValue -Value $subExt -Default $mainExt) - $ContentType = (Protect-PodeValue -Value $ContentType -Default (Get-PodeContentType -Extension $subExt)) + $ContentType = (Protect-PodeValue -Value $ContentType -Default (Get-PodeContentType -Extension $subExt)) - # Write the processed content as the HTTP response - Write-PodeTextResponse -Value $content -ContentType $ContentType -StatusCode $StatusCode - } - # this is a static file - else { - try { - if (Test-PodeIsPSCore) { - $content = (Get-Content -Path $Path -Raw -AsByteStream) + # Write the processed content as the HTTP response + Write-PodeTextResponse -Value $content -ContentType $ContentType -StatusCode $StatusCode + } + # this is a static file + else { + try { + if (Test-PodeIsPSCore) { + $content = (Get-Content -Path $Path -Raw -AsByteStream) + } + else { + $content = (Get-Content -Path $Path -Raw -Encoding byte) + } + # Determine and set the content type for static files + $ContentType = Protect-PodeValue -Value $ContentType -Default (Get-PodeContentType -Extension $mainExt) + # Write the file content as the HTTP response + Write-PodeTextResponse -Bytes $content -ContentType $ContentType -MaxAge $MaxAge -StatusCode $StatusCode -Cache:$Cache + return } - else { - $content = (Get-Content -Path $Path -Raw -Encoding byte) + catch [System.UnauthorizedAccessException] { + $statusCode = 401 } - # Determine and set the content type for static files - $ContentType = Protect-PodeValue -Value $ContentType -Default (Get-PodeContentType -Extension $mainExt) - # Write the file content as the HTTP response - Write-PodeTextResponse -Bytes $content -ContentType $ContentType -MaxAge $MaxAge -StatusCode $StatusCode -Cache:$Cache - return - } - catch [System.UnauthorizedAccessException] { - $statusCode = 401 - } - catch { - $statusCode = 400 - } - # If the file does not exist, set the HTTP response status code appropriately - Set-PodeResponseStatus -Code $StatusCode + catch { + $statusCode = 400 + } + # If the file does not exist, set the HTTP response status code appropriately + Set-PodeResponseStatus -Code $StatusCode + } } } } diff --git a/src/Private/Secrets.ps1 b/src/Private/Secrets.ps1 index 75c579908..b3248d6c7 100644 --- a/src/Private/Secrets.ps1 +++ b/src/Private/Secrets.ps1 @@ -1,6 +1,6 @@ function Initialize-PodeSecretVault { param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [hashtable] $VaultConfig, @@ -8,13 +8,14 @@ function Initialize-PodeSecretVault { [scriptblock] $ScriptBlock ) - - $null = Invoke-PodeScriptBlock -ScriptBlock $ScriptBlock -Splat -Arguments @($VaultConfig.Parameters) + process { + $null = Invoke-PodeScriptBlock -ScriptBlock $ScriptBlock -Splat -Arguments @($VaultConfig.Parameters) + } } function Register-PodeSecretManagementVault { param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [hashtable] $VaultConfig, @@ -26,100 +27,112 @@ function Register-PodeSecretManagementVault { [string] $ModuleName ) + begin { + $pipelineItemCount = 0 + } - # use the Name for VaultName if not passed - if ([string]::IsNullOrWhiteSpace($VaultName)) { - $VaultName = $VaultConfig.Name + process { + $pipelineItemCount++ } - # import the modules - $null = Import-Module -Name Microsoft.PowerShell.SecretManagement -Force -DisableNameChecking -Scope Global -ErrorAction Stop -Verbose:$false - $null = Import-Module -Name $ModuleName -Force -DisableNameChecking -Scope Global -ErrorAction Stop -Verbose:$false + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # use the Name for VaultName if not passed + if ([string]::IsNullOrWhiteSpace($VaultName)) { + $VaultName = $VaultConfig.Name + } - # export the modules for pode - Export-PodeModule -Name @('Microsoft.PowerShell.SecretManagement', $ModuleName) + # import the modules + $null = Import-Module -Name Microsoft.PowerShell.SecretManagement -Force -DisableNameChecking -Scope Global -ErrorAction Stop -Verbose:$false + $null = Import-Module -Name $ModuleName -Force -DisableNameChecking -Scope Global -ErrorAction Stop -Verbose:$false - # is this the local SecretStore provider? - $isSecretStore = ($ModuleName -ieq 'Microsoft.PowerShell.SecretStore') + # export the modules for pode + Export-PodeModule -Name @('Microsoft.PowerShell.SecretManagement', $ModuleName) - # check if we have an unlock password for local secret store - if ($isSecretStore) { - if ([string]::IsNullOrEmpty($VaultConfig.Unlock.Secret)) { - # An 'UnlockSecret' is required when using Microsoft.PowerShell.SecretStore - throw ($PodeLocale.unlockSecretRequiredExceptionMessage) - } - } + # is this the local SecretStore provider? + $isSecretStore = ($ModuleName -ieq 'Microsoft.PowerShell.SecretStore') - # does the local secret store already exist? - $secretStoreExists = ($isSecretStore -and (Test-PodeSecretVaultInternal -Name $VaultName)) + # check if we have an unlock password for local secret store + if ($isSecretStore) { + if ([string]::IsNullOrEmpty($VaultConfig.Unlock.Secret)) { + # An 'UnlockSecret' is required when using Microsoft.PowerShell.SecretStore + throw ($PodeLocale.unlockSecretRequiredExceptionMessage) + } + } - # do we have vault params? - $hasVaultParams = ($null -ne $VaultConfig.Parameters) + # does the local secret store already exist? + $secretStoreExists = ($isSecretStore -and (Test-PodeSecretVaultInternal -Name $VaultName)) - # attempt to register the vault - $registerParams = @{ - Name = $VaultName - ModuleName = $ModuleName - Confirm = $false - AllowClobber = $true - ErrorAction = 'Stop' - } + # do we have vault params? + $hasVaultParams = ($null -ne $VaultConfig.Parameters) - if (!$isSecretStore -and $hasVaultParams) { - $registerParams['VaultParameters'] = $VaultConfig.Parameters - } + # attempt to register the vault + $registerParams = @{ + Name = $VaultName + ModuleName = $ModuleName + Confirm = $false + AllowClobber = $true + ErrorAction = 'Stop' + } - $null = Register-SecretVault @registerParams + if (!$isSecretStore -and $hasVaultParams) { + $registerParams['VaultParameters'] = $VaultConfig.Parameters + } - # all is good, so set the config - $VaultConfig['SecretManagement'] = @{ - VaultName = $VaultName - ModuleName = $ModuleName - } + $null = Register-SecretVault @registerParams - # set local secret store config - if ($isSecretStore) { - if (!$hasVaultParams) { - $VaultConfig.Parameters = @{} + # all is good, so set the config + $VaultConfig['SecretManagement'] = @{ + VaultName = $VaultName + ModuleName = $ModuleName } - $vaultParams = $VaultConfig.Parameters + # set local secret store config + if ($isSecretStore) { + if (!$hasVaultParams) { + $VaultConfig.Parameters = @{} + } - # remove the password - $vaultParams.Remove('Password') + $vaultParams = $VaultConfig.Parameters - # set default authentication and interaction flags - if ([string]::IsNullOrEmpty($vaultParams.Authentication)) { - $vaultParams['Authentication'] = 'Password' - } + # remove the password + $vaultParams.Remove('Password') - if ([string]::IsNullOrEmpty($vaultParams.Interaction)) { - $vaultParams['Interaction'] = 'None' - } + # set default authentication and interaction flags + if ([string]::IsNullOrEmpty($vaultParams.Authentication)) { + $vaultParams['Authentication'] = 'Password' + } - # set default password timeout and unlock interval to 1 minute - if ($VaultConfig.Unlock.Interval -le 0) { - $VaultConfig.Unlock.Interval = 1 - } + if ([string]::IsNullOrEmpty($vaultParams.Interaction)) { + $vaultParams['Interaction'] = 'None' + } + + # set default password timeout and unlock interval to 1 minute + if ($VaultConfig.Unlock.Interval -le 0) { + $VaultConfig.Unlock.Interval = 1 + } - # unlock the vault, and set password - $VaultConfig | Unlock-PodeSecretManagementVault + # unlock the vault, and set password + $VaultConfig | Unlock-PodeSecretManagementVault - # set the password timeout for the vault - if (!$secretStoreExists) { - if ($VaultConfig.Parameters.PasswordTimeout -le 0) { - $vaultParams['PasswordTimeout'] = ($VaultConfig.Unlock.Interval * 60) + 10 + # set the password timeout for the vault + if (!$secretStoreExists) { + if ($VaultConfig.Parameters.PasswordTimeout -le 0) { + $vaultParams['PasswordTimeout'] = ($VaultConfig.Unlock.Interval * 60) + 10 + } } - } - # set config - $null = Set-SecretStoreConfiguration @vaultParams -Confirm:$false -ErrorAction Stop + # set config + $null = Set-SecretStoreConfiguration @vaultParams -Confirm:$false -ErrorAction Stop + } } } function Register-PodeSecretCustomVault { param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [hashtable] $VaultConfig, @@ -143,79 +156,84 @@ function Register-PodeSecretCustomVault { [scriptblock] $UnregisterScriptBlock ) + process { + # unlock secret with no script? + if ($VaultConfig.Unlock.Enabled -and (Test-PodeIsEmpty $UnlockScriptBlock)) { + # Unlock secret supplied for custom Secret Vault type, but not Unlock ScriptBlock supplied + throw ($PodeLocale.unlockSecretButNoScriptBlockExceptionMessage) + } - # unlock secret with no script? - if ($VaultConfig.Unlock.Enabled -and (Test-PodeIsEmpty $UnlockScriptBlock)) { - # Unlock secret supplied for custom Secret Vault type, but not Unlock ScriptBlock supplied - throw ($PodeLocale.unlockSecretButNoScriptBlockExceptionMessage) - } - - # all is good, so set the config - $VaultConfig['Custom'] = @{ - Read = $ScriptBlock - Unlock = $UnlockScriptBlock - Remove = $RemoveScriptBlock - Set = $SetScriptBlock - Unregister = $UnregisterScriptBlock + # all is good, so set the config + $VaultConfig['Custom'] = @{ + Read = $ScriptBlock + Unlock = $UnlockScriptBlock + Remove = $RemoveScriptBlock + Set = $SetScriptBlock + Unregister = $UnregisterScriptBlock + } } } function Unlock-PodeSecretManagementVault { param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [hashtable] $VaultConfig ) - # do we need to unlock the vault? - if (!$VaultConfig.Unlock.Enabled) { - return $null - } + process { + # do we need to unlock the vault? + if (!$VaultConfig.Unlock.Enabled) { + return $null + } - # unlock the vault - $null = Unlock-SecretVault -Name $VaultConfig.SecretManagement.VaultName -Password $VaultConfig.Unlock.Secret -ErrorAction Stop + # unlock the vault + $null = Unlock-SecretVault -Name $VaultConfig.SecretManagement.VaultName -Password $VaultConfig.Unlock.Secret -ErrorAction Stop - # interval? - if ($VaultConfig.Unlock.Interval -gt 0) { - return ([datetime]::UtcNow.AddMinutes($VaultConfig.Unlock.Interval)) - } + # interval? + if ($VaultConfig.Unlock.Interval -gt 0) { + return ([datetime]::UtcNow.AddMinutes($VaultConfig.Unlock.Interval)) + } - return $null + return $null + } } function Unlock-PodeSecretCustomVault { param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [hashtable] $VaultConfig ) + process { + # do we need to unlock the vault? + if (!$VaultConfig.Unlock.Enabled) { + return + } - # do we need to unlock the vault? - if (!$VaultConfig.Unlock.Enabled) { - return - } - - # do we have an unlock scriptblock - if ($null -eq $VaultConfig.Custom.Unlock) { - throw ($PodeLocale.noUnlockScriptBlockForVaultExceptionMessage -f $VaultConfig.Name) #"No Unlock ScriptBlock supplied for unlocking the vault '$($VaultConfig.Name)'" - } + # do we have an unlock scriptblock + if ($null -eq $VaultConfig.Custom.Unlock) { + # No Unlock ScriptBlock supplied for unlocking the vault '$($VaultConfig.Name)' + throw ($PodeLocale.noUnlockScriptBlockForVaultExceptionMessage -f $VaultConfig.Name) + } - # unlock the vault, and get back an expiry - $expiry = Invoke-PodeScriptBlock -ScriptBlock $VaultConfig.Custom.Unlock -Splat -Return -Arguments @( - $VaultConfig.Parameters, + # unlock the vault, and get back an expiry + $expiry = Invoke-PodeScriptBlock -ScriptBlock $VaultConfig.Custom.Unlock -Splat -Return -Arguments @( + $VaultConfig.Parameters, (ConvertFrom-SecureString -SecureString $VaultConfig.Unlock.Secret -AsPlainText) - ) + ) - # return expiry if given, otherwise check interval - if ($null -ne $expiry) { - return $expiry - } + # return expiry if given, otherwise check interval + if ($null -ne $expiry) { + return $expiry + } - if ($VaultConfig.Unlock.Interval -gt 0) { - return ([datetime]::UtcNow.AddMinutes($VaultConfig.Unlock.Interval)) - } + if ($VaultConfig.Unlock.Interval -gt 0) { + return ([datetime]::UtcNow.AddMinutes($VaultConfig.Unlock.Interval)) + } - return $null + return $null + } } function Unregister-PodeSecretManagementVault { @@ -224,14 +242,15 @@ function Unregister-PodeSecretManagementVault { [hashtable] $VaultConfig ) + process { + # do we need to unregister the vault? + if ($VaultConfig.AutoImported) { + return + } - # do we need to unregister the vault? - if ($VaultConfig.AutoImported) { - return + # unregister the vault + $null = Unregister-SecretVault -Name $VaultConfig.SecretManagement.VaultName -Confirm:$false -ErrorAction Stop } - - # unregister the vault - $null = Unregister-SecretVault -Name $VaultConfig.SecretManagement.VaultName -Confirm:$false -ErrorAction Stop } function Unregister-PodeSecretCustomVault { @@ -240,21 +259,22 @@ function Unregister-PodeSecretCustomVault { [hashtable] $VaultConfig ) + process { + # do we need to unregister the vault? + if ($VaultConfig.AutoImported) { + return + } - # do we need to unregister the vault? - if ($VaultConfig.AutoImported) { - return - } + # do we have an unregister scriptblock? if not, just do nothing + if ($null -eq $VaultConfig.Custom.Unregister) { + return + } - # do we have an unregister scriptblock? if not, just do nothing - if ($null -eq $VaultConfig.Custom.Unregister) { - return + # unregister the vault + $null = Invoke-PodeScriptBlock -ScriptBlock $VaultConfig.Custom.Unregister -Splat -Arguments @( + $VaultConfig.Parameters + ) } - - # unregister the vault - $null = Invoke-PodeScriptBlock -ScriptBlock $VaultConfig.Custom.Unregister -Splat -Arguments @( - $VaultConfig.Parameters - ) } function Get-PodeSecretManagementKey { diff --git a/src/Public/Access.ps1 b/src/Public/Access.ps1 index 51febb3f1..c1a1a920d 100644 --- a/src/Public/Access.ps1 +++ b/src/Public/Access.ps1 @@ -172,33 +172,46 @@ function Add-PodeAccess { [string] $Match = 'One' ) + begin { + $pipelineItemCount = 0 + } - # check name unique - if (Test-PodeAccessExists -Name $Name) { - throw ($PodeLocale.accessMethodAlreadyDefinedExceptionMessage -f $Name) #"Access method already defined: $($Name)" + process { + $pipelineItemCount++ } - # parse using variables in validator scriptblock - $scriptObj = $null - if (!(Test-PodeIsEmpty $ScriptBlock)) { - $ScriptBlock, $usingScriptVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState - $scriptObj = @{ - Script = $ScriptBlock - UsingVariables = $usingScriptVars + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # check name unique + if (Test-PodeAccessExists -Name $Name) { + # Access method already defined: $($Name) + throw ($PodeLocale.accessMethodAlreadyDefinedExceptionMessage -f $Name) } - } - # add access object - $PodeContext.Server.Authorisations.Methods[$Name] = @{ - Name = $Name - Description = $Description - Scheme = $Scheme - ScriptBlock = $scriptObj - Arguments = $ArgumentList - Match = $Match.ToLowerInvariant() - Cache = @{} - Merged = $false - Parent = $null + # parse using variables in validator scriptblock + $scriptObj = $null + if (!(Test-PodeIsEmpty $ScriptBlock)) { + $ScriptBlock, $usingScriptVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState + $scriptObj = @{ + Script = $ScriptBlock + UsingVariables = $usingScriptVars + } + } + + # add access object + $PodeContext.Server.Authorisations.Methods[$Name] = @{ + Name = $Name + Description = $Description + Scheme = $Scheme + ScriptBlock = $scriptObj + Arguments = $ArgumentList + Match = $Match.ToLowerInvariant() + Cache = @{} + Merged = $false + Parent = $null + } } } @@ -381,7 +394,6 @@ function Test-PodeAccessExists { [string] $Name ) - return $PodeContext.Server.Authorisations.Methods.ContainsKey($Name) } @@ -604,8 +616,9 @@ function Remove-PodeAccess { [string] $Name ) - - $null = $PodeContext.Server.Authorisations.Methods.Remove($Name) + process { + $null = $PodeContext.Server.Authorisations.Methods.Remove($Name) + } } <# diff --git a/src/Public/Authentication.ps1 b/src/Public/Authentication.ps1 index ab9ff04c5..a007e1153 100644 --- a/src/Public/Authentication.ps1 +++ b/src/Public/Authentication.ps1 @@ -287,241 +287,253 @@ function New-PodeAuthScheme { [string] $Secret ) + begin { + $pipelineItemCount = 0 + } - # default realm - $_realm = 'User' - - # convert any middleware into valid hashtables - $Middleware = @(ConvertTo-PodeMiddleware -Middleware $Middleware -PSSession $PSCmdlet.SessionState) + process { + $pipelineItemCount++ + } - # configure the auth scheme - switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { - 'basic' { - return @{ - Name = (Protect-PodeValue -Value $HeaderTag -Default 'Basic') - Realm = (Protect-PodeValue -Value $Realm -Default $_realm) - ScriptBlock = @{ - Script = (Get-PodeAuthBasicType) - UsingVariables = $null - } - PostValidator = $null - Middleware = $Middleware - InnerScheme = $InnerScheme - Scheme = 'http' - Arguments = @{ - Description = $Description - HeaderTag = (Protect-PodeValue -Value $HeaderTag -Default 'Basic') - Encoding = (Protect-PodeValue -Value $Encoding -Default 'ISO-8859-1') - AsCredential = $AsCredential - } - } + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) } - - 'clientcertificate' { - return @{ - Name = 'Mutual' - Realm = (Protect-PodeValue -Value $Realm -Default $_realm) - ScriptBlock = @{ - Script = (Get-PodeAuthClientCertificateType) - UsingVariables = $null + # default realm + $_realm = 'User' + + # convert any middleware into valid hashtables + $Middleware = @(ConvertTo-PodeMiddleware -Middleware $Middleware -PSSession $PSCmdlet.SessionState) + + # configure the auth scheme + switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { + 'basic' { + return @{ + Name = (Protect-PodeValue -Value $HeaderTag -Default 'Basic') + Realm = (Protect-PodeValue -Value $Realm -Default $_realm) + ScriptBlock = @{ + Script = (Get-PodeAuthBasicType) + UsingVariables = $null + } + PostValidator = $null + Middleware = $Middleware + InnerScheme = $InnerScheme + Scheme = 'http' + Arguments = @{ + Description = $Description + HeaderTag = (Protect-PodeValue -Value $HeaderTag -Default 'Basic') + Encoding = (Protect-PodeValue -Value $Encoding -Default 'ISO-8859-1') + AsCredential = $AsCredential + } } - PostValidator = $null - Middleware = $Middleware - InnerScheme = $InnerScheme - Scheme = 'http' - Arguments = @{} } - } - 'digest' { - return @{ - Name = 'Digest' - Realm = (Protect-PodeValue -Value $Realm -Default $_realm) - ScriptBlock = @{ - Script = (Get-PodeAuthDigestType) - UsingVariables = $null - } - PostValidator = @{ - Script = (Get-PodeAuthDigestPostValidator) - UsingVariables = $null - } - Middleware = $Middleware - InnerScheme = $InnerScheme - Scheme = 'http' - Arguments = @{ - HeaderTag = (Protect-PodeValue -Value $HeaderTag -Default 'Digest') + 'clientcertificate' { + return @{ + Name = 'Mutual' + Realm = (Protect-PodeValue -Value $Realm -Default $_realm) + ScriptBlock = @{ + Script = (Get-PodeAuthClientCertificateType) + UsingVariables = $null + } + PostValidator = $null + Middleware = $Middleware + InnerScheme = $InnerScheme + Scheme = 'http' + Arguments = @{} } } - } - 'bearer' { - $secretBytes = $null - if (![string]::IsNullOrWhiteSpace($Secret)) { - $secretBytes = [System.Text.Encoding]::UTF8.GetBytes($Secret) + 'digest' { + return @{ + Name = 'Digest' + Realm = (Protect-PodeValue -Value $Realm -Default $_realm) + ScriptBlock = @{ + Script = (Get-PodeAuthDigestType) + UsingVariables = $null + } + PostValidator = @{ + Script = (Get-PodeAuthDigestPostValidator) + UsingVariables = $null + } + Middleware = $Middleware + InnerScheme = $InnerScheme + Scheme = 'http' + Arguments = @{ + HeaderTag = (Protect-PodeValue -Value $HeaderTag -Default 'Digest') + } + } } - return @{ - Name = 'Bearer' - Realm = (Protect-PodeValue -Value $Realm -Default $_realm) - ScriptBlock = @{ - Script = (Get-PodeAuthBearerType) - UsingVariables = $null + 'bearer' { + $secretBytes = $null + if (![string]::IsNullOrWhiteSpace($Secret)) { + $secretBytes = [System.Text.Encoding]::UTF8.GetBytes($Secret) } - PostValidator = @{ - Script = (Get-PodeAuthBearerPostValidator) - UsingVariables = $null - } - Middleware = $Middleware - Scheme = 'http' - InnerScheme = $InnerScheme - Arguments = @{ - Description = $Description - HeaderTag = (Protect-PodeValue -Value $HeaderTag -Default 'Bearer') - Scopes = $Scope - AsJWT = $AsJWT - Secret = $secretBytes + + return @{ + Name = 'Bearer' + Realm = (Protect-PodeValue -Value $Realm -Default $_realm) + ScriptBlock = @{ + Script = (Get-PodeAuthBearerType) + UsingVariables = $null + } + PostValidator = @{ + Script = (Get-PodeAuthBearerPostValidator) + UsingVariables = $null + } + Middleware = $Middleware + Scheme = 'http' + InnerScheme = $InnerScheme + Arguments = @{ + Description = $Description + HeaderTag = (Protect-PodeValue -Value $HeaderTag -Default 'Bearer') + Scopes = $Scope + AsJWT = $AsJWT + Secret = $secretBytes + } } } - } - 'form' { - return @{ - Name = 'Form' - Realm = (Protect-PodeValue -Value $Realm -Default $_realm) - ScriptBlock = @{ - Script = (Get-PodeAuthFormType) - UsingVariables = $null - } - PostValidator = $null - Middleware = $Middleware - InnerScheme = $InnerScheme - Scheme = 'http' - Arguments = @{ - Description = $Description - Fields = @{ - Username = (Protect-PodeValue -Value $UsernameField -Default 'username') - Password = (Protect-PodeValue -Value $PasswordField -Default 'password') + 'form' { + return @{ + Name = 'Form' + Realm = (Protect-PodeValue -Value $Realm -Default $_realm) + ScriptBlock = @{ + Script = (Get-PodeAuthFormType) + UsingVariables = $null + } + PostValidator = $null + Middleware = $Middleware + InnerScheme = $InnerScheme + Scheme = 'http' + Arguments = @{ + Description = $Description + Fields = @{ + Username = (Protect-PodeValue -Value $UsernameField -Default 'username') + Password = (Protect-PodeValue -Value $PasswordField -Default 'password') + } + AsCredential = $AsCredential } - AsCredential = $AsCredential } } - } - 'oauth2' { - if (($null -ne $InnerScheme) -and ($InnerScheme.Name -inotin @('basic', 'form'))) { - # OAuth2 InnerScheme can only be one of either Basic or Form authentication, but got: {0} - throw ($PodeLocale.oauth2InnerSchemeInvalidExceptionMessage -f $InnerScheme.Name) - } + 'oauth2' { + if (($null -ne $InnerScheme) -and ($InnerScheme.Name -inotin @('basic', 'form'))) { + # OAuth2 InnerScheme can only be one of either Basic or Form authentication, but got: {0} + throw ($PodeLocale.oauth2InnerSchemeInvalidExceptionMessage -f $InnerScheme.Name) + } - if (($null -eq $InnerScheme) -and [string]::IsNullOrWhiteSpace($AuthoriseUrl)) { - # OAuth2 requires an Authorise URL to be supplied - throw ($PodeLocale.oauth2RequiresAuthorizeUrlExceptionMessage) - } + if (($null -eq $InnerScheme) -and [string]::IsNullOrWhiteSpace($AuthoriseUrl)) { + # OAuth2 requires an Authorise URL to be supplied + throw ($PodeLocale.oauth2RequiresAuthorizeUrlExceptionMessage) + } - if ($UsePKCE -and !(Test-PodeSessionsEnabled)) { - # Sessions are required to use OAuth2 with PKCE - throw ($PodeLocale.sessionsRequiredForOAuth2WithPKCEExceptionMessage) - } + if ($UsePKCE -and !(Test-PodeSessionsEnabled)) { + # Sessions are required to use OAuth2 with PKCE + throw ($PodeLocale.sessionsRequiredForOAuth2WithPKCEExceptionMessage) + } - if (!$UsePKCE -and [string]::IsNullOrEmpty($ClientSecret)) { - # OAuth2 requires a Client Secret when not using PKCE - throw ($PodeLocale.oauth2ClientSecretRequiredExceptionMessage) - } - return @{ - Name = 'OAuth2' - Realm = (Protect-PodeValue -Value $Realm -Default $_realm) - ScriptBlock = @{ - Script = (Get-PodeAuthOAuth2Type) - UsingVariables = $null + if (!$UsePKCE -and [string]::IsNullOrEmpty($ClientSecret)) { + # OAuth2 requires a Client Secret when not using PKCE + throw ($PodeLocale.oauth2ClientSecretRequiredExceptionMessage) } - PostValidator = $null - Middleware = $Middleware - Scheme = 'oauth2' - InnerScheme = $InnerScheme - Arguments = @{ - Description = $Description - Scopes = $Scope - PKCE = @{ - Enabled = $UsePKCE - CodeChallenge = @{ - Method = $CodeChallengeMethod - } - } - Client = @{ - ID = $ClientId - Secret = $ClientSecret + return @{ + Name = 'OAuth2' + Realm = (Protect-PodeValue -Value $Realm -Default $_realm) + ScriptBlock = @{ + Script = (Get-PodeAuthOAuth2Type) + UsingVariables = $null } - Urls = @{ - Redirect = $RedirectUrl - Authorise = $AuthoriseUrl - Token = $TokenUrl - User = @{ - Url = $UserUrl - Method = (Protect-PodeValue -Value $UserUrlMethod -Default 'Post') + PostValidator = $null + Middleware = $Middleware + Scheme = 'oauth2' + InnerScheme = $InnerScheme + Arguments = @{ + Description = $Description + Scopes = $Scope + PKCE = @{ + Enabled = $UsePKCE + CodeChallenge = @{ + Method = $CodeChallengeMethod + } + } + Client = @{ + ID = $ClientId + Secret = $ClientSecret + } + Urls = @{ + Redirect = $RedirectUrl + Authorise = $AuthoriseUrl + Token = $TokenUrl + User = @{ + Url = $UserUrl + Method = (Protect-PodeValue -Value $UserUrlMethod -Default 'Post') + } } } } } - } - - 'apikey' { - # set default location name - if ([string]::IsNullOrWhiteSpace($LocationName)) { - $LocationName = (@{ - Header = 'X-API-KEY' - Query = 'api_key' - Cookie = 'X-API-KEY' - })[$Location] - } - $secretBytes = $null - if (![string]::IsNullOrWhiteSpace($Secret)) { - $secretBytes = [System.Text.Encoding]::UTF8.GetBytes($Secret) - } + 'apikey' { + # set default location name + if ([string]::IsNullOrWhiteSpace($LocationName)) { + $LocationName = (@{ + Header = 'X-API-KEY' + Query = 'api_key' + Cookie = 'X-API-KEY' + })[$Location] + } - return @{ - Name = 'ApiKey' - Realm = (Protect-PodeValue -Value $Realm -Default $_realm) - ScriptBlock = @{ - Script = (Get-PodeAuthApiKeyType) - UsingVariables = $null + $secretBytes = $null + if (![string]::IsNullOrWhiteSpace($Secret)) { + $secretBytes = [System.Text.Encoding]::UTF8.GetBytes($Secret) } - PostValidator = $null - Middleware = $Middleware - InnerScheme = $InnerScheme - Scheme = 'apiKey' - Arguments = @{ - Description = $Description - Location = $Location - LocationName = $LocationName - AsJWT = $AsJWT - Secret = $secretBytes + + return @{ + Name = 'ApiKey' + Realm = (Protect-PodeValue -Value $Realm -Default $_realm) + ScriptBlock = @{ + Script = (Get-PodeAuthApiKeyType) + UsingVariables = $null + } + PostValidator = $null + Middleware = $Middleware + InnerScheme = $InnerScheme + Scheme = 'apiKey' + Arguments = @{ + Description = $Description + Location = $Location + LocationName = $LocationName + AsJWT = $AsJWT + Secret = $secretBytes + } } } - } - - 'custom' { - $ScriptBlock, $usingScriptVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState - if ($null -ne $PostValidator) { - $PostValidator, $usingPostVars = Convert-PodeScopedVariables -ScriptBlock $PostValidator -PSSession $PSCmdlet.SessionState - } + 'custom' { + $ScriptBlock, $usingScriptVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState - return @{ - Name = $Name - Realm = (Protect-PodeValue -Value $Realm -Default $_realm) - InnerScheme = $InnerScheme - Scheme = $Type.ToLowerInvariant() - ScriptBlock = @{ - Script = $ScriptBlock - UsingVariables = $usingScriptVars + if ($null -ne $PostValidator) { + $PostValidator, $usingPostVars = Convert-PodeScopedVariables -ScriptBlock $PostValidator -PSSession $PSCmdlet.SessionState } - PostValidator = @{ - Script = $PostValidator - UsingVariables = $usingPostVars + + return @{ + Name = $Name + Realm = (Protect-PodeValue -Value $Realm -Default $_realm) + InnerScheme = $InnerScheme + Scheme = $Type.ToLowerInvariant() + ScriptBlock = @{ + Script = $ScriptBlock + UsingVariables = $usingScriptVars + } + PostValidator = @{ + Script = $PostValidator + UsingVariables = $usingPostVars + } + Middleware = $Middleware + Arguments = $ArgumentList } - Middleware = $Middleware - Arguments = $ArgumentList } } } @@ -593,18 +605,31 @@ function New-PodeAuthAzureADScheme { [switch] $UsePKCE ) + begin { + $pipelineItemCount = 0 + } - return New-PodeAuthScheme ` - -OAuth2 ` - -ClientId $ClientId ` - -ClientSecret $ClientSecret ` - -AuthoriseUrl "https://login.microsoftonline.com/$($Tenant)/oauth2/v2.0/authorize" ` - -TokenUrl "https://login.microsoftonline.com/$($Tenant)/oauth2/v2.0/token" ` - -UserUrl 'https://graph.microsoft.com/oidc/userinfo' ` - -RedirectUrl $RedirectUrl ` - -InnerScheme $InnerScheme ` - -Middleware $Middleware ` - -UsePKCE:$UsePKCE + process { + + $pipelineItemCount++ + } + + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + return New-PodeAuthScheme ` + -OAuth2 ` + -ClientId $ClientId ` + -ClientSecret $ClientSecret ` + -AuthoriseUrl "https://login.microsoftonline.com/$($Tenant)/oauth2/v2.0/authorize" ` + -TokenUrl "https://login.microsoftonline.com/$($Tenant)/oauth2/v2.0/token" ` + -UserUrl 'https://graph.microsoft.com/oidc/userinfo' ` + -RedirectUrl $RedirectUrl ` + -InnerScheme $InnerScheme ` + -Middleware $Middleware ` + -UsePKCE:$UsePKCE + } } <# @@ -755,54 +780,67 @@ function Add-PodeAuth { [switch] $SuccessUseOrigin ) - - # ensure the name doesn't already exist - if (Test-PodeAuthExists -Name $Name) { - # Authentication method already defined: {0} - throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) + begin { + $pipelineItemCount = 0 } - # ensure the Scheme contains a scriptblock - if (Test-PodeIsEmpty $Scheme.ScriptBlock) { - # The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock - throw ($PodeLocale.schemeRequiresValidScriptBlockExceptionMessage -f $Name) - } + process { - # if we're using sessions, ensure sessions have been setup - if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { - # Sessions are required to use session persistent authentication - throw ($PodeLocale.sessionsRequiredForSessionPersistentAuthExceptionMessage) + $pipelineItemCount++ } - # check for scoped vars - $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # ensure the name doesn't already exist + if (Test-PodeAuthExists -Name $Name) { + # Authentication method already defined: {0} + throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) + } - # add auth method to server - $PodeContext.Server.Authentications.Methods[$Name] = @{ - Name = $Name - Scheme = $Scheme - ScriptBlock = $ScriptBlock - UsingVariables = $usingVars - Arguments = $ArgumentList - Sessionless = $Sessionless.IsPresent - Failure = @{ - Url = $FailureUrl - Message = $FailureMessage + # ensure the Scheme contains a scriptblock + if (Test-PodeIsEmpty $Scheme.ScriptBlock) { + # The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock + throw ($PodeLocale.schemeRequiresValidScriptBlockExceptionMessage -f $Name) } - Success = @{ - Url = $SuccessUrl - UseOrigin = $SuccessUseOrigin.IsPresent + + # if we're using sessions, ensure sessions have been setup + if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { + # Sessions are required to use session persistent authentication + throw ($PodeLocale.sessionsRequiredForSessionPersistentAuthExceptionMessage) } - Cache = @{} - Merged = $false - Parent = $null - } - # if the scheme is oauth2, and there's no redirect, set up a default one - if (($Scheme.Name -ieq 'oauth2') -and ($null -eq $Scheme.InnerScheme) -and [string]::IsNullOrWhiteSpace($Scheme.Arguments.Urls.Redirect)) { - $path = '/oauth2/callback' - $Scheme.Arguments.Urls.Redirect = $path - Add-PodeRoute -Method Get -Path $path -Authentication $Name + # check for scoped vars + $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState + + # add auth method to server + $PodeContext.Server.Authentications.Methods[$Name] = @{ + Name = $Name + Scheme = $Scheme + ScriptBlock = $ScriptBlock + UsingVariables = $usingVars + Arguments = $ArgumentList + Sessionless = $Sessionless.IsPresent + Failure = @{ + Url = $FailureUrl + Message = $FailureMessage + } + Success = @{ + Url = $SuccessUrl + UseOrigin = $SuccessUseOrigin.IsPresent + } + Cache = @{} + Merged = $false + Parent = $null + } + + # if the scheme is oauth2, and there's no redirect, set up a default one + if (($Scheme.Name -ieq 'oauth2') -and ($null -eq $Scheme.InnerScheme) -and [string]::IsNullOrWhiteSpace($Scheme.Arguments.Urls.Redirect)) { + $path = '/oauth2/callback' + $Scheme.Arguments.Urls.Redirect = $path + Add-PodeRoute -Method Get -Path $path -Authentication $Name + } } } @@ -1278,82 +1316,95 @@ function Add-PodeAuthWindowsAd { [switch] $KeepCredential ) - - # ensure the name doesn't already exist - if (Test-PodeAuthExists -Name $Name) { - # Authentication method already defined: {0} - throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) + begin { + $pipelineItemCount = 0 } - # ensure the Scheme contains a scriptblock - if (Test-PodeIsEmpty $Scheme.ScriptBlock) { - # The supplied Scheme for the '$($Name)' Windows AD authentication validator requires a valid ScriptBlock - throw ($PodeLocale.schemeRequiresValidScriptBlockExceptionMessage -f $Name) - } + process { - # if we're using sessions, ensure sessions have been setup - if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { - # Sessions are required to use session persistent authentication - throw ($PodeLocale.sessionsRequiredForSessionPersistentAuthExceptionMessage) + $pipelineItemCount++ } - # if AD module set, ensure we're on windows and the module is available, then import/export it - if ($ADModule) { - Import-PodeAuthADModule - } + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # ensure the name doesn't already exist + if (Test-PodeAuthExists -Name $Name) { + # Authentication method already defined: {0} + throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) + } - # set server name if not passed - if ([string]::IsNullOrWhiteSpace($Fqdn)) { - $Fqdn = Get-PodeAuthDomainName + # ensure the Scheme contains a scriptblock + if (Test-PodeIsEmpty $Scheme.ScriptBlock) { + # The supplied Scheme for the '$($Name)' Windows AD authentication validator requires a valid ScriptBlock + throw ($PodeLocale.schemeRequiresValidScriptBlockExceptionMessage -f $Name) + } - if ([string]::IsNullOrWhiteSpace($Fqdn)) { - # No domain server name has been supplied for Windows AD authentication - throw ($PodeLocale.noDomainServerNameForWindowsAdAuthExceptionMessage) + # if we're using sessions, ensure sessions have been setup + if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { + # Sessions are required to use session persistent authentication + throw ($PodeLocale.sessionsRequiredForSessionPersistentAuthExceptionMessage) } - } - # set the domain if not passed - if ([string]::IsNullOrWhiteSpace($Domain)) { - $Domain = ($Fqdn -split '\.')[0] - } + # if AD module set, ensure we're on windows and the module is available, then import/export it + if ($ADModule) { + Import-PodeAuthADModule + } - # if we have a scriptblock, deal with using vars - if ($null -ne $ScriptBlock) { - $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState - } + # set server name if not passed + if ([string]::IsNullOrWhiteSpace($Fqdn)) { + $Fqdn = Get-PodeAuthDomainName - # add Windows AD auth method to server - $PodeContext.Server.Authentications.Methods[$Name] = @{ - Name = $Name - Scheme = $Scheme - ScriptBlock = (Get-PodeAuthWindowsADMethod) - Arguments = @{ - Server = $Fqdn - Domain = $Domain - SearchBase = $SearchBase - Users = $Users - Groups = $Groups - NoGroups = $NoGroups - DirectGroups = $DirectGroups - KeepCredential = $KeepCredential - Provider = (Get-PodeAuthADProvider -OpenLDAP:$OpenLDAP -ADModule:$ADModule) - ScriptBlock = @{ - Script = $ScriptBlock - UsingVariables = $usingVars + if ([string]::IsNullOrWhiteSpace($Fqdn)) { + # No domain server name has been supplied for Windows AD authentication + throw ($PodeLocale.noDomainServerNameForWindowsAdAuthExceptionMessage) } } - Sessionless = $Sessionless - Failure = @{ - Url = $FailureUrl - Message = $FailureMessage + + # set the domain if not passed + if ([string]::IsNullOrWhiteSpace($Domain)) { + $Domain = ($Fqdn -split '\.')[0] } - Success = @{ - Url = $SuccessUrl - UseOrigin = $SuccessUseOrigin + + # if we have a scriptblock, deal with using vars + if ($null -ne $ScriptBlock) { + $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState + } + + # add Windows AD auth method to server + $PodeContext.Server.Authentications.Methods[$Name] = @{ + Name = $Name + Scheme = $Scheme + ScriptBlock = (Get-PodeAuthWindowsADMethod) + Arguments = @{ + Server = $Fqdn + Domain = $Domain + SearchBase = $SearchBase + Users = $Users + Groups = $Groups + NoGroups = $NoGroups + DirectGroups = $DirectGroups + KeepCredential = $KeepCredential + Provider = (Get-PodeAuthADProvider -OpenLDAP:$OpenLDAP -ADModule:$ADModule) + ScriptBlock = @{ + Script = $ScriptBlock + UsingVariables = $usingVars + } + } + Sessionless = $Sessionless + Failure = @{ + Url = $FailureUrl + Message = $FailureMessage + } + Success = @{ + Url = $SuccessUrl + UseOrigin = $SuccessUseOrigin + } + Cache = @{} + Merged = $false + Parent = $null } - Cache = @{} - Merged = $false - Parent = $null } } @@ -1511,8 +1562,9 @@ function Remove-PodeAuth { [string] $Name ) - - $null = $PodeContext.Server.Authentications.Methods.Remove($Name) + process { + $null = $PodeContext.Server.Authentications.Methods.Remove($Name) + } } <# @@ -1870,71 +1922,84 @@ function Add-PodeAuthUserFile { [switch] $SuccessUseOrigin ) - - # ensure the name doesn't already exist - if (Test-PodeAuthExists -Name $Name) { - # Authentication method already defined: {0} - throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) + begin { + $pipelineItemCount = 0 } - # ensure the Scheme contains a scriptblock - if (Test-PodeIsEmpty $Scheme.ScriptBlock) { - # The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock. - throw ($PodeLocale.schemeRequiresValidScriptBlockExceptionMessage -f $Name) - } + process { - # if we're using sessions, ensure sessions have been setup - if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { - # Sessions are required to use session persistent authentication - throw ($PodeLocale.sessionsRequiredForSessionPersistentAuthExceptionMessage) + $pipelineItemCount++ } - # set the file path if not passed - if ([string]::IsNullOrWhiteSpace($FilePath)) { - $FilePath = Join-PodeServerRoot -Folder '.' -FilePath 'users.json' - } - else { - $FilePath = Get-PodeRelativePath -Path $FilePath -JoinRoot -Resolve - } + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # ensure the name doesn't already exist + if (Test-PodeAuthExists -Name $Name) { + # Authentication method already defined: {0} + throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) + } - # ensure the user file exists - if (!(Test-PodePath -Path $FilePath -NoStatus -FailOnDirectory)) { - # The user file does not exist: {0} - throw ($PodeLocale.userFileDoesNotExistExceptionMessage -f $FilePath) - } + # ensure the Scheme contains a scriptblock + if (Test-PodeIsEmpty $Scheme.ScriptBlock) { + # The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock. + throw ($PodeLocale.schemeRequiresValidScriptBlockExceptionMessage -f $Name) + } - # if we have a scriptblock, deal with using vars - if ($null -ne $ScriptBlock) { - $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState - } + # if we're using sessions, ensure sessions have been setup + if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { + # Sessions are required to use session persistent authentication + throw ($PodeLocale.sessionsRequiredForSessionPersistentAuthExceptionMessage) + } - # add Windows AD auth method to server - $PodeContext.Server.Authentications.Methods[$Name] = @{ - Name = $Name - Scheme = $Scheme - ScriptBlock = (Get-PodeAuthUserFileMethod) - Arguments = @{ - FilePath = $FilePath - Users = $Users - Groups = $Groups - HmacSecret = $HmacSecret - ScriptBlock = @{ - Script = $ScriptBlock - UsingVariables = $usingVars - } + # set the file path if not passed + if ([string]::IsNullOrWhiteSpace($FilePath)) { + $FilePath = Join-PodeServerRoot -Folder '.' -FilePath 'users.json' } - Sessionless = $Sessionless - Failure = @{ - Url = $FailureUrl - Message = $FailureMessage + else { + $FilePath = Get-PodeRelativePath -Path $FilePath -JoinRoot -Resolve } - Success = @{ - Url = $SuccessUrl - UseOrigin = $SuccessUseOrigin + + # ensure the user file exists + if (!(Test-PodePath -Path $FilePath -NoStatus -FailOnDirectory)) { + # The user file does not exist: {0} + throw ($PodeLocale.userFileDoesNotExistExceptionMessage -f $FilePath) + } + + # if we have a scriptblock, deal with using vars + if ($null -ne $ScriptBlock) { + $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState + } + + # add Windows AD auth method to server + $PodeContext.Server.Authentications.Methods[$Name] = @{ + Name = $Name + Scheme = $Scheme + ScriptBlock = (Get-PodeAuthUserFileMethod) + Arguments = @{ + FilePath = $FilePath + Users = $Users + Groups = $Groups + HmacSecret = $HmacSecret + ScriptBlock = @{ + Script = $ScriptBlock + UsingVariables = $usingVars + } + } + Sessionless = $Sessionless + Failure = @{ + Url = $FailureUrl + Message = $FailureMessage + } + Success = @{ + Url = $SuccessUrl + UseOrigin = $SuccessUseOrigin + } + Cache = @{} + Merged = $false + Parent = $null } - Cache = @{} - Merged = $false - Parent = $null } } @@ -2032,62 +2097,75 @@ function Add-PodeAuthWindowsLocal { [switch] $SuccessUseOrigin ) - - # ensure we're on Windows! - if (!(Test-PodeIsWindows)) { - # Windows Local Authentication support is for Windows only - throw ($PodeLocale.windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage) + begin { + $pipelineItemCount = 0 } - # ensure the name doesn't already exist - if (Test-PodeAuthExists -Name $Name) { - # Authentication method already defined: {0} - throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) - } + process { - # ensure the Scheme contains a scriptblock - if (Test-PodeIsEmpty $Scheme.ScriptBlock) { - # The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock. - throw ($PodeLocale.schemeRequiresValidScriptBlockExceptionMessage -f $Name) + $pipelineItemCount++ } - # if we're using sessions, ensure sessions have been setup - if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { - # Sessions are required to use session persistent authentication - throw ($PodeLocale.sessionsRequiredForSessionPersistentAuthExceptionMessage) - } + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # ensure we're on Windows! + if (!(Test-PodeIsWindows)) { + # Windows Local Authentication support is for Windows only + throw ($PodeLocale.windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage) + } - # if we have a scriptblock, deal with using vars - if ($null -ne $ScriptBlock) { - $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState - } + # ensure the name doesn't already exist + if (Test-PodeAuthExists -Name $Name) { + # Authentication method already defined: {0} + throw ($PodeLocale.authMethodAlreadyDefinedExceptionMessage -f $Name) + } - # add Windows Local auth method to server - $PodeContext.Server.Authentications.Methods[$Name] = @{ - Name = $Name - Scheme = $Scheme - ScriptBlock = (Get-PodeAuthWindowsLocalMethod) - Arguments = @{ - Users = $Users - Groups = $Groups - NoGroups = $NoGroups - ScriptBlock = @{ - Script = $ScriptBlock - UsingVariables = $usingVars - } + # ensure the Scheme contains a scriptblock + if (Test-PodeIsEmpty $Scheme.ScriptBlock) { + # The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock. + throw ($PodeLocale.schemeRequiresValidScriptBlockExceptionMessage -f $Name) } - Sessionless = $Sessionless - Failure = @{ - Url = $FailureUrl - Message = $FailureMessage + + # if we're using sessions, ensure sessions have been setup + if (!$Sessionless -and !(Test-PodeSessionsEnabled)) { + # Sessions are required to use session persistent authentication + throw ($PodeLocale.sessionsRequiredForSessionPersistentAuthExceptionMessage) } - Success = @{ - Url = $SuccessUrl - UseOrigin = $SuccessUseOrigin + + # if we have a scriptblock, deal with using vars + if ($null -ne $ScriptBlock) { + $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState + } + + # add Windows Local auth method to server + $PodeContext.Server.Authentications.Methods[$Name] = @{ + Name = $Name + Scheme = $Scheme + ScriptBlock = (Get-PodeAuthWindowsLocalMethod) + Arguments = @{ + Users = $Users + Groups = $Groups + NoGroups = $NoGroups + ScriptBlock = @{ + Script = $ScriptBlock + UsingVariables = $usingVars + } + } + Sessionless = $Sessionless + Failure = @{ + Url = $FailureUrl + Message = $FailureMessage + } + Success = @{ + Url = $SuccessUrl + UseOrigin = $SuccessUseOrigin + } + Cache = @{} + Merged = $false + Parent = $null } - Cache = @{} - Merged = $false - Parent = $null } } @@ -2401,56 +2479,69 @@ function ConvertFrom-PodeOIDCDiscovery { [switch] $UsePKCE ) - - # get the discovery doc - if (!$Url.EndsWith('/.well-known/openid-configuration')) { - $Url += '/.well-known/openid-configuration' + begin { + $pipelineItemCount = 0 } - $config = Invoke-RestMethod -Method Get -Uri $Url + process { - # check it supports the code response_type - if ($config.response_types_supported -inotcontains 'code') { - # The OAuth2 provider does not support the 'code' response_type - throw ($PodeLocale.oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage) + $pipelineItemCount++ } - # can we have an InnerScheme? - if (($null -ne $InnerScheme) -and ($config.grant_types_supported -inotcontains 'password')) { - # The OAuth2 provider does not support the 'password' grant_type required by using an InnerScheme - throw ($PodeLocale.oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage) - } + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # get the discovery doc + if (!$Url.EndsWith('/.well-known/openid-configuration')) { + $Url += '/.well-known/openid-configuration' + } - # scopes - $scopes = $config.scopes_supported + $config = Invoke-RestMethod -Method Get -Uri $Url - if (($null -ne $Scope) -and ($Scope.Length -gt 0)) { - $scopes = @(foreach ($s in $Scope) { - if ($s -iin $config.scopes_supported) { - $s - } - }) - } + # check it supports the code response_type + if ($config.response_types_supported -inotcontains 'code') { + # The OAuth2 provider does not support the 'code' response_type + throw ($PodeLocale.oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage) + } - # pkce code challenge method - $codeMethod = 'S256' - if ($config.code_challenge_methods_supported -inotcontains $codeMethod) { - $codeMethod = 'plain' - } + # can we have an InnerScheme? + if (($null -ne $InnerScheme) -and ($config.grant_types_supported -inotcontains 'password')) { + # The OAuth2 provider does not support the 'password' grant_type required by using an InnerScheme + throw ($PodeLocale.oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage) + } - return New-PodeAuthScheme ` - -OAuth2 ` - -ClientId $ClientId ` - -ClientSecret $ClientSecret ` - -AuthoriseUrl $config.authorization_endpoint ` - -TokenUrl $config.token_endpoint ` - -UserUrl $config.userinfo_endpoint ` - -RedirectUrl $RedirectUrl ` - -Scope $scopes ` - -InnerScheme $InnerScheme ` - -Middleware $Middleware ` - -CodeChallengeMethod $codeMethod ` - -UsePKCE:$UsePKCE + # scopes + $scopes = $config.scopes_supported + + if (($null -ne $Scope) -and ($Scope.Length -gt 0)) { + $scopes = @(foreach ($s in $Scope) { + if ($s -iin $config.scopes_supported) { + $s + } + }) + } + + # pkce code challenge method + $codeMethod = 'S256' + if ($config.code_challenge_methods_supported -inotcontains $codeMethod) { + $codeMethod = 'plain' + } + + return New-PodeAuthScheme ` + -OAuth2 ` + -ClientId $ClientId ` + -ClientSecret $ClientSecret ` + -AuthoriseUrl $config.authorization_endpoint ` + -TokenUrl $config.token_endpoint ` + -UserUrl $config.userinfo_endpoint ` + -RedirectUrl $RedirectUrl ` + -Scope $scopes ` + -InnerScheme $InnerScheme ` + -Middleware $Middleware ` + -CodeChallengeMethod $codeMethod ` + -UsePKCE:$UsePKCE + } } <# diff --git a/src/Public/Caching.ps1 b/src/Public/Caching.ps1 index acddbfde1..3be0951d8 100644 --- a/src/Public/Caching.ps1 +++ b/src/Public/Caching.ps1 @@ -105,7 +105,7 @@ function Set-PodeCache { [string] $Key, - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [object] $InputObject, @@ -118,30 +118,47 @@ function Set-PodeCache { $Storage = $null ) - # use the global settable default here - if ($Ttl -le 0) { - $Ttl = $PodeContext.Server.Cache.DefaultTtl + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() } - # inmem or custom storage? - if ([string]::IsNullOrEmpty($Storage)) { - $Storage = $PodeContext.Server.Cache.DefaultStorage - } - - # use inmem cache - if ([string]::IsNullOrEmpty($Storage)) { - Set-PodeCacheInternal -Key $Key -InputObject $InputObject -Ttl $Ttl + process { + # Add the current piped-in value to the array + $pipelineValue += $_ } - # used custom storage - elseif (Test-PodeCacheStorage -Key $Storage) { - $null = Invoke-PodeScriptBlock -ScriptBlock $PodeContext.Server.Cache.Storage[$Storage].Set -Arguments @($Key, $InputObject, $Ttl) -Splat - } - - # storage not found! - else { - # Cache storage with name not found when attempting to set cached item - throw ($PodeLocale.cacheStorageNotFoundForSetExceptionMessage -f $Storage, $Key) + end { + # If there are multiple piped-in values, set InputObject to the array of values + if ($pipelineValue.Count -gt 1) { + $InputObject = $pipelineValue + } + + # use the global settable default here + if ($Ttl -le 0) { + $Ttl = $PodeContext.Server.Cache.DefaultTtl + } + + # inmem or custom storage? + if ([string]::IsNullOrEmpty($Storage)) { + $Storage = $PodeContext.Server.Cache.DefaultStorage + } + + # use inmem cache + if ([string]::IsNullOrEmpty($Storage)) { + Set-PodeCacheInternal -Key $Key -InputObject $InputObject -Ttl $Ttl + } + + # used custom storage + elseif (Test-PodeCacheStorage -Key $Storage) { + $null = Invoke-PodeScriptBlock -ScriptBlock $PodeContext.Server.Cache.Storage[$Storage].Set -Arguments @($Key, $InputObject, $Ttl) -Splat + } + + # storage not found! + else { + # Cache storage with name not found when attempting to set cached item + throw ($PodeLocale.cacheStorageNotFoundForSetExceptionMessage -f $Storage, $Key) + } } } diff --git a/src/Public/Core.ps1 b/src/Public/Core.ps1 index 51303be3b..f07759e63 100644 --- a/src/Public/Core.ps1 +++ b/src/Public/Core.ps1 @@ -130,111 +130,123 @@ function Start-PodeServer { [switch] $EnableBreakpoints ) + begin { + $pipelineItemCount = 0 + } - # ensure the session is clean - $PodeContext = $null - $ShowDoneMessage = $true + process { + $pipelineItemCount++ + } - try { - # if we have a filepath, resolve it - and extract a root path from it - if ($PSCmdlet.ParameterSetName -ieq 'file') { - $FilePath = Get-PodeRelativePath -Path $FilePath -Resolve -TestPath -JoinRoot -RootPath $MyInvocation.PSScriptRoot + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # ensure the session is clean + $PodeContext = $null + $ShowDoneMessage = $true - # if not already supplied, set root path - if ([string]::IsNullOrWhiteSpace($RootPath)) { - if ($CurrentPath) { - $RootPath = $PWD.Path - } - else { - $RootPath = Split-Path -Parent -Path $FilePath + try { + # if we have a filepath, resolve it - and extract a root path from it + if ($PSCmdlet.ParameterSetName -ieq 'file') { + $FilePath = Get-PodeRelativePath -Path $FilePath -Resolve -TestPath -JoinRoot -RootPath $MyInvocation.PSScriptRoot + + # if not already supplied, set root path + if ([string]::IsNullOrWhiteSpace($RootPath)) { + if ($CurrentPath) { + $RootPath = $PWD.Path + } + else { + $RootPath = Split-Path -Parent -Path $FilePath + } } } - } - # configure the server's root path - if (!(Test-PodeIsEmpty $RootPath)) { - $RootPath = Get-PodeRelativePath -Path $RootPath -RootPath $MyInvocation.PSScriptRoot -JoinRoot -Resolve -TestPath - } + # configure the server's root path + if (!(Test-PodeIsEmpty $RootPath)) { + $RootPath = Get-PodeRelativePath -Path $RootPath -RootPath $MyInvocation.PSScriptRoot -JoinRoot -Resolve -TestPath + } - # create main context object - $PodeContext = New-PodeContext ` - -ScriptBlock $ScriptBlock ` - -FilePath $FilePath ` - -Threads $Threads ` - -Interval $Interval ` - -ServerRoot (Protect-PodeValue -Value $RootPath -Default $MyInvocation.PSScriptRoot) ` - -ServerlessType $ServerlessType ` - -ListenerType $ListenerType ` - -EnablePool $EnablePool ` - -StatusPageExceptions $StatusPageExceptions ` - -DisableTermination:$DisableTermination ` - -Quiet:$Quiet ` - -EnableBreakpoints:$EnableBreakpoints - - # set it so ctrl-c can terminate, unless serverless/iis, or disabled - if (!$PodeContext.Server.DisableTermination -and ($null -eq $psISE)) { - [Console]::TreatControlCAsInput = $true - } + # create main context object + $PodeContext = New-PodeContext ` + -ScriptBlock $ScriptBlock ` + -FilePath $FilePath ` + -Threads $Threads ` + -Interval $Interval ` + -ServerRoot (Protect-PodeValue -Value $RootPath -Default $MyInvocation.PSScriptRoot) ` + -ServerlessType $ServerlessType ` + -ListenerType $ListenerType ` + -EnablePool $EnablePool ` + -StatusPageExceptions $StatusPageExceptions ` + -DisableTermination:$DisableTermination ` + -Quiet:$Quiet ` + -EnableBreakpoints:$EnableBreakpoints + + # set it so ctrl-c can terminate, unless serverless/iis, or disabled + if (!$PodeContext.Server.DisableTermination -and ($null -eq $psISE)) { + [Console]::TreatControlCAsInput = $true + } - # start the file monitor for interally restarting - Start-PodeFileMonitor + # start the file monitor for interally restarting + Start-PodeFileMonitor - # start the server - Start-PodeInternalServer -Request $Request -Browse:$Browse + # start the server + Start-PodeInternalServer -Request $Request -Browse:$Browse - # at this point, if it's just a one-one off script, return - if (!(Test-PodeServerKeepOpen)) { - return - } + # at this point, if it's just a one-one off script, return + if (!(Test-PodeServerKeepOpen)) { + return + } - # sit here waiting for termination/cancellation, or to restart the server - while (!(Test-PodeTerminationPressed -Key $key) -and !($PodeContext.Tokens.Cancellation.IsCancellationRequested)) { - Start-Sleep -Seconds 1 + # sit here waiting for termination/cancellation, or to restart the server + while (!(Test-PodeTerminationPressed -Key $key) -and !($PodeContext.Tokens.Cancellation.IsCancellationRequested)) { + Start-Sleep -Seconds 1 - # get the next key presses - $key = Get-PodeConsoleKey + # get the next key presses + $key = Get-PodeConsoleKey + + # check for internal restart + if (($PodeContext.Tokens.Restart.IsCancellationRequested) -or (Test-PodeRestartPressed -Key $key)) { + Restart-PodeInternalServer + } - # check for internal restart - if (($PodeContext.Tokens.Restart.IsCancellationRequested) -or (Test-PodeRestartPressed -Key $key)) { - Restart-PodeInternalServer + # check for open browser + if (Test-PodeOpenBrowserPressed -Key $key) { + Invoke-PodeEvent -Type Browser + Start-Process (Get-PodeEndpointUrl) + } } - # check for open browser - if (Test-PodeOpenBrowserPressed -Key $key) { - Invoke-PodeEvent -Type Browser - Start-Process (Get-PodeEndpointUrl) + if ($PodeContext.Server.IsIIS -and $PodeContext.Server.IIS.Shutdown) { + # (IIS Shutdown) + Write-PodeHost $PodeLocale.iisShutdownMessage -NoNewLine -ForegroundColor Yellow + Write-PodeHost ' ' -NoNewLine } + # Terminating... + Write-PodeHost $PodeLocale.terminatingMessage -NoNewLine -ForegroundColor Yellow + Invoke-PodeEvent -Type Terminate + $PodeContext.Tokens.Cancellation.Cancel() } - - if ($PodeContext.Server.IsIIS -and $PodeContext.Server.IIS.Shutdown) { - # (IIS Shutdown) - Write-PodeHost $PodeLocale.iisShutdownMessage -NoNewline -ForegroundColor Yellow - Write-PodeHost ' ' -NoNewline + catch { + Invoke-PodeEvent -Type Crash + $ShowDoneMessage = $false + throw } - # Terminating... - Write-PodeHost $PodeLocale.terminatingMessage -NoNewline -ForegroundColor Yellow - Invoke-PodeEvent -Type Terminate - $PodeContext.Tokens.Cancellation.Cancel() - } - catch { - Invoke-PodeEvent -Type Crash - $ShowDoneMessage = $false - throw - } - finally { - Invoke-PodeEvent -Type Stop + finally { + Invoke-PodeEvent -Type Stop - # set output values - Set-PodeOutputVariable + # set output values + Set-PodeOutputVariable - # unregister secret vaults - Unregister-PodeSecretVaultsInternal + # unregister secret vaults + Unregister-PodeSecretVaultsInternal - # clean the runspaces and tokens - Close-PodeServerInternal -ShowDoneMessage:$ShowDoneMessage + # clean the runspaces and tokens + Close-PodeServerInternal -ShowDoneMessage:$ShowDoneMessage - # clean the session - $PodeContext = $null + # clean the session + $PodeContext = $null + } } } @@ -493,7 +505,7 @@ function Pode { # quick check to see if the data is required if ($Action -ine 'init') { if ($null -eq $data) { - Write-Host 'package.json file not found' -ForegroundColor Red + Write-PodeHost 'package.json file not found' -ForegroundColor Red return } else { @@ -504,14 +516,14 @@ function Pode { } if ([string]::IsNullOrWhiteSpace($actionScript) -and $Action -ine 'install') { - Write-Host "package.json does not contain a script for the $($Action) action" -ForegroundColor Yellow + Write-PodeHost "package.json does not contain a script for the $($Action) action" -ForegroundColor Yellow return } } } else { if ($null -ne $data) { - Write-Host 'package.json already exists' -ForegroundColor Yellow + Write-PodeHost 'package.json already exists' -ForegroundColor Yellow return } } @@ -535,7 +547,7 @@ function Pode { if (![string]::IsNullOrWhiteSpace($v)) { $map.license = $v } $map | ConvertTo-Json -Depth 10 | Out-File -FilePath $file -Encoding utf8 -Force - Write-Host 'Success, saved package.json' -ForegroundColor Green + Write-PodeHost 'Success, saved package.json' -ForegroundColor Green } 'test' { @@ -639,55 +651,68 @@ function Show-PodeGui { [switch] $HideFromTaskbar ) + begin { + $pipelineItemCount = 0 + } - # error if serverless - Test-PodeIsServerless -FunctionName 'Show-PodeGui' -ThrowError + process { - # only valid for Windows PowerShell - if ((Test-PodeIsPSCore) -and ($PSVersionTable.PSVersion.Major -eq 6)) { - # Show-PodeGui is currently only available for Windows PowerShell and PowerShell 7+ on Windows - throw ($PodeLocale.showPodeGuiOnlyAvailableOnWindowsExceptionMessage) + $pipelineItemCount++ } - # enable the gui and set general settings - $PodeContext.Server.Gui.Enabled = $true - $PodeContext.Server.Gui.Title = $Title - $PodeContext.Server.Gui.ShowInTaskbar = !$HideFromTaskbar - $PodeContext.Server.Gui.WindowState = $WindowState - $PodeContext.Server.Gui.WindowStyle = $WindowStyle - $PodeContext.Server.Gui.ResizeMode = $ResizeMode - - # set the window's icon path - if (![string]::IsNullOrWhiteSpace($Icon)) { - $PodeContext.Server.Gui.Icon = Get-PodeRelativePath -Path $Icon -JoinRoot -Resolve - if (!(Test-Path $PodeContext.Server.Gui.Icon)) { - # Path to icon for GUI does not exist - throw ($PodeLocale.pathToIconForGuiDoesNotExistExceptionMessage -f $PodeContext.Server.Gui.Icon) + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) } - } + # error if serverless + Test-PodeIsServerless -FunctionName 'Show-PodeGui' -ThrowError - # set the height of the window - $PodeContext.Server.Gui.Height = $Height - if ($PodeContext.Server.Gui.Height -le 0) { - $PodeContext.Server.Gui.Height = 'auto' - } + # only valid for Windows PowerShell + if ((Test-PodeIsPSCore) -and ($PSVersionTable.PSVersion.Major -eq 6)) { + # Show-PodeGui is currently only available for Windows PowerShell and PowerShell 7+ on Windows + throw ($PodeLocale.showPodeGuiOnlyAvailableOnWindowsExceptionMessage) + } - # set the width of the window - $PodeContext.Server.Gui.Width = $Width - if ($PodeContext.Server.Gui.Width -le 0) { - $PodeContext.Server.Gui.Width = 'auto' - } + # enable the gui and set general settings + $PodeContext.Server.Gui.Enabled = $true + $PodeContext.Server.Gui.Title = $Title + $PodeContext.Server.Gui.ShowInTaskbar = !$HideFromTaskbar + $PodeContext.Server.Gui.WindowState = $WindowState + $PodeContext.Server.Gui.WindowStyle = $WindowStyle + $PodeContext.Server.Gui.ResizeMode = $ResizeMode + + # set the window's icon path + if (![string]::IsNullOrWhiteSpace($Icon)) { + $PodeContext.Server.Gui.Icon = Get-PodeRelativePath -Path $Icon -JoinRoot -Resolve + if (!(Test-Path $PodeContext.Server.Gui.Icon)) { + # Path to icon for GUI does not exist + throw ($PodeLocale.pathToIconForGuiDoesNotExistExceptionMessage -f $PodeContext.Server.Gui.Icon) + } + } - # set the gui to use a specific listener - $PodeContext.Server.Gui.EndpointName = $EndpointName + # set the height of the window + $PodeContext.Server.Gui.Height = $Height + if ($PodeContext.Server.Gui.Height -le 0) { + $PodeContext.Server.Gui.Height = 'auto' + } - if (![string]::IsNullOrWhiteSpace($EndpointName)) { - if (!$PodeContext.Server.Endpoints.ContainsKey($EndpointName)) { - # Endpoint with name '$EndpointName' does not exist. - throw ($PodeLocale.endpointNameNotExistExceptionMessage -f $EndpointName) + # set the width of the window + $PodeContext.Server.Gui.Width = $Width + if ($PodeContext.Server.Gui.Width -le 0) { + $PodeContext.Server.Gui.Width = 'auto' } - $PodeContext.Server.Gui.Endpoint = $PodeContext.Server.Endpoints[$EndpointName] + # set the gui to use a specific listener + $PodeContext.Server.Gui.EndpointName = $EndpointName + + if (![string]::IsNullOrWhiteSpace($EndpointName)) { + if (!$PodeContext.Server.Endpoints.ContainsKey($EndpointName)) { + # Endpoint with name '$EndpointName' does not exist. + throw ($PodeLocale.endpointNameNotExistExceptionMessage -f $EndpointName) + } + + $PodeContext.Server.Gui.Endpoint = $PodeContext.Server.Endpoints[$EndpointName] + } } } diff --git a/src/Public/Middleware.ps1 b/src/Public/Middleware.ps1 index a279c00fe..8b7f8d15d 100644 --- a/src/Public/Middleware.ps1 +++ b/src/Public/Middleware.ps1 @@ -359,19 +359,31 @@ function Add-PodeBodyParser { [scriptblock] $ScriptBlock ) + begin { + $pipelineItemCount = 0 + } - # if a parser for the type already exists, fail - if ($PodeContext.Server.BodyParsers.ContainsKey($ContentType)) { - # A body-parser is already defined for the content-type - throw ($PodeLocale.bodyParserAlreadyDefinedForContentTypeExceptionMessage -f $ContentType) + process { + $pipelineItemCount++ } - # check for scoped vars - $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # if a parser for the type already exists, fail + if ($PodeContext.Server.BodyParsers.ContainsKey($ContentType)) { + # A body-parser is already defined for the content-type + throw ($PodeLocale.bodyParserAlreadyDefinedForContentTypeExceptionMessage -f $ContentType) + } + + # check for scoped vars + $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState - $PodeContext.Server.BodyParsers[$ContentType] = @{ - ScriptBlock = $ScriptBlock - UsingVariables = $usingVars + $PodeContext.Server.BodyParsers[$ContentType] = @{ + ScriptBlock = $ScriptBlock + UsingVariables = $usingVars + } } } @@ -397,12 +409,14 @@ function Remove-PodeBodyParser { $ContentType ) - # if there's no parser for the type, return - if (!$PodeContext.Server.BodyParsers.ContainsKey($ContentType)) { - return - } + process { + # if there's no parser for the type, return + if (!$PodeContext.Server.BodyParsers.ContainsKey($ContentType)) { + return + } - $null = $PodeContext.Server.BodyParsers.Remove($ContentType) + $null = $PodeContext.Server.BodyParsers.Remove($ContentType) + } } <# @@ -447,7 +461,7 @@ function Add-PodeMiddleware { [scriptblock] $ScriptBlock, - [Parameter(Mandatory = $true, ParameterSetName = 'Input', ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ParameterSetName = 'Input')] [hashtable] $InputObject, @@ -459,39 +473,51 @@ function Add-PodeMiddleware { [object[]] $ArgumentList ) - - # ensure name doesn't already exist - if (($PodeContext.Server.Middleware | Where-Object { $_.Name -ieq $Name } | Measure-Object).Count -gt 0) { - # [Middleware] Name: Middleware already defined - throw ($PodeLocale.middlewareAlreadyDefinedExceptionMessage -f $Name) - + begin { + $pipelineItemCount = 0 } - # if it's a script - call New-PodeMiddleware - if ($PSCmdlet.ParameterSetName -ieq 'script') { - $InputObject = (New-PodeMiddlewareInternal ` - -ScriptBlock $ScriptBlock ` - -Route $Route ` - -ArgumentList $ArgumentList ` - -PSSession $PSCmdlet.SessionState) - } - else { - $Route = ConvertTo-PodeRouteRegex -Path $Route - $InputObject.Route = Protect-PodeValue -Value $Route -Default $InputObject.Route - $InputObject.Options = Protect-PodeValue -Value $Options -Default $InputObject.Options + process { + $pipelineItemCount++ } - # ensure we have a script to run - if (Test-PodeIsEmpty $InputObject.Logic) { - # [Middleware]: No logic supplied in ScriptBlock - throw ($PodeLocale.middlewareNoLogicSuppliedExceptionMessage) - } + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # ensure name doesn't already exist + if (($PodeContext.Server.Middleware | Where-Object { $_.Name -ieq $Name } | Measure-Object).Count -gt 0) { + # [Middleware] Name: Middleware already defined + throw ($PodeLocale.middlewareAlreadyDefinedExceptionMessage -f $Name) - # set name, and override route/args - $InputObject.Name = $Name + } + + # if it's a script - call New-PodeMiddleware + if ($PSCmdlet.ParameterSetName -ieq 'script') { + $InputObject = (New-PodeMiddlewareInternal ` + -ScriptBlock $ScriptBlock ` + -Route $Route ` + -ArgumentList $ArgumentList ` + -PSSession $PSCmdlet.SessionState) + } + else { + $Route = ConvertTo-PodeRouteRegex -Path $Route + $InputObject.Route = Protect-PodeValue -Value $Route -Default $InputObject.Route + $InputObject.Options = Protect-PodeValue -Value $Options -Default $InputObject.Options + } + + # ensure we have a script to run + if (Test-PodeIsEmpty $InputObject.Logic) { + # [Middleware]: No logic supplied in ScriptBlock + throw ($PodeLocale.middlewareNoLogicSuppliedExceptionMessage) + } + + # set name, and override route/args + $InputObject.Name = $Name - # add the logic to array of middleware that needs to be run - $PodeContext.Server.Middleware += $InputObject + # add the logic to array of middleware that needs to be run + $PodeContext.Server.Middleware += $InputObject + } } <# @@ -520,7 +546,7 @@ function New-PodeMiddleware { [CmdletBinding()] [OutputType([hashtable])] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [scriptblock] $ScriptBlock, @@ -532,12 +558,24 @@ function New-PodeMiddleware { [object[]] $ArgumentList ) + begin { + $pipelineItemCount = 0 + } - return New-PodeMiddlewareInternal ` - -ScriptBlock $ScriptBlock ` - -Route $Route ` - -ArgumentList $ArgumentList ` - -PSSession $PSCmdlet.SessionState + process { + $pipelineItemCount++ + } + + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + return New-PodeMiddlewareInternal ` + -ScriptBlock $ScriptBlock ` + -Route $Route ` + -ArgumentList $ArgumentList ` + -PSSession $PSCmdlet.SessionState + } } <# diff --git a/src/Public/OAComponents.ps1 b/src/Public/OAComponents.ps1 index b0ccca20c..6cc6ae5b3 100644 --- a/src/Public/OAComponents.ps1 +++ b/src/Public/OAComponents.ps1 @@ -80,7 +80,7 @@ function Add-PodeOAComponentResponse { ) $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag foreach ($tag in $DefinitionTag) { - $PodeContext.Server.OpenAPI.Definitions[$tag].components.responses[$Name] = New-PodeOResponseInternal -DefinitionTag $tag -Params $PSBoundParameters + $PodeContext.Server.OpenAPI.Definitions[$tag].components.responses[$Name] = New-PodeOResponseInternal -DefinitionTag $tag -Params $PSBoundParameters } } @@ -129,7 +129,7 @@ function Add-PodeOAComponentSchema { [string] $Name, - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [Alias('Schema')] [hashtable] $Component, @@ -140,34 +140,45 @@ function Add-PodeOAComponentSchema { [string[]] $DefinitionTag ) + begin { + $pipelineItemCount = 0 + } - $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + process { + $pipelineItemCount++ + } - foreach ($tag in $DefinitionTag) { - $PodeContext.Server.OpenAPI.Definitions[$tag].components.schemas[$Name] = ($Component | ConvertTo-PodeOASchemaProperty -DefinitionTag $tag) - if ($PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.schemaValidation) { - try { - $modifiedComponent = ($Component | ConvertTo-PodeOASchemaProperty -DefinitionTag $tag) | Resolve-PodeOAReference -DefinitionTag $tag - $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.schemaJson[$Name] = @{ - 'available' = $true - 'schema' = $modifiedComponent - 'json' = $modifiedComponent | ConvertTo-Json -depth $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.depth - } - } - catch { - if ($_.ToString().StartsWith('Validation of schema with')) { + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + + foreach ($tag in $DefinitionTag) { + $PodeContext.Server.OpenAPI.Definitions[$tag].components.schemas[$Name] = ($Component | ConvertTo-PodeOASchemaProperty -DefinitionTag $tag) + if ($PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.schemaValidation) { + try { + $modifiedComponent = ($Component | ConvertTo-PodeOASchemaProperty -DefinitionTag $tag) | Resolve-PodeOAReference -DefinitionTag $tag $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.schemaJson[$Name] = @{ - 'available' = $false + 'available' = $true + 'schema' = $modifiedComponent + 'json' = $modifiedComponent | ConvertTo-Json -Depth $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.depth + } + } + catch { + if ($_.ToString().StartsWith('Validation of schema with')) { + $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.schemaJson[$Name] = @{ + 'available' = $false + } } } } - } - if ($Description) { - $PodeContext.Server.OpenAPI.Definitions[$tag].components.schemas[$Name].description = $Description + if ($Description) { + $PodeContext.Server.OpenAPI.Definitions[$tag].components.schemas[$Name].description = $Description + } } } - } @@ -219,26 +230,37 @@ function Add-PodeOAComponentHeader { [string] $Description, - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [hashtable] $Schema, [string[]] $DefinitionTag ) + begin { + $pipelineItemCount = 0 + } - $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + process { + $pipelineItemCount++ + } - foreach ($tag in $DefinitionTag) { - $param = [ordered]@{ - 'schema' = ($Schema | ConvertTo-PodeOASchemaProperty -NoDescription -DefinitionTag $tag) + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) } - if ( $Description) { - $param['description'] = $Description + $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + + foreach ($tag in $DefinitionTag) { + $param = [ordered]@{ + 'schema' = ($Schema | ConvertTo-PodeOASchemaProperty -NoDescription -DefinitionTag $tag) + } + if ( $Description) { + $param['description'] = $Description + } + $PodeContext.Server.OpenAPI.Definitions[$tag].components.headers[$Name] = $param } - $PodeContext.Server.OpenAPI.Definitions[$tag].components.headers[$Name] = $param } - } @@ -292,7 +314,7 @@ function Add-PodeOAComponentRequestBody { [string] $Name, - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [Alias('ContentSchemas')] [hashtable] $Content, @@ -308,20 +330,32 @@ function Add-PodeOAComponentRequestBody { [string[]] $DefinitionTag ) + begin { + $pipelineItemCount = 0 + } - $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag - - foreach ($tag in $DefinitionTag) { - $param = [ordered]@{ content = ($Content | ConvertTo-PodeOAObjectSchema -DefinitionTag $tag) } + process { + $pipelineItemCount++ + } - if ($Required.IsPresent) { - $param['required'] = $Required.IsPresent + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) } + $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + + foreach ($tag in $DefinitionTag) { + $param = [ordered]@{ content = ($Content | ConvertTo-PodeOAObjectSchema -DefinitionTag $tag) } - if ( $Description) { - $param['description'] = $Description + if ($Required.IsPresent) { + $param['required'] = $Required.IsPresent + } + + if ( $Description) { + $param['description'] = $Description + } + $PodeContext.Server.OpenAPI.Definitions[$tag].components.requestBodies[$Name] = $param } - $PodeContext.Server.OpenAPI.Definitions[$tag].components.requestBodies[$Name] = $param } } @@ -365,29 +399,41 @@ function Add-PodeOAComponentParameter { [string] $Name, - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [hashtable] $Parameter, [string[]] $DefinitionTag ) + begin { + $pipelineItemCount = 0 + } - $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + process { + $pipelineItemCount++ + } - foreach ($tag in $DefinitionTag) { - if ([string]::IsNullOrWhiteSpace($Name)) { - if ($Parameter.name) { - $Name = $Parameter.name - } - else { - # The Parameter has no name. Please provide a name to this component using the `Name` parameter - throw ($PodeLocale.parameterHasNoNameExceptionMessage) + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + + $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + + foreach ($tag in $DefinitionTag) { + if ([string]::IsNullOrWhiteSpace($Name)) { + if ($Parameter.name) { + $Name = $Parameter.name + } + else { + # The Parameter has no name. Please provide a name to this component using the `Name` parameter + throw ($PodeLocale.parameterHasNoNameExceptionMessage) + } } + $PodeContext.Server.OpenAPI.Definitions[$tag].components.parameters[$Name] = $Parameter } - $PodeContext.Server.OpenAPI.Definitions[$tag].components.parameters[$Name] = $Parameter } - } <# @@ -893,7 +939,7 @@ function Remove-PodeOAComponent { } if (!(Test-Path Alias:Enable-PodeOpenApiViewer)) { - New-Alias Enable-PodeOpenApiViewer -Value Enable-PodeOAViewer + New-Alias Enable-PodeOpenApiViewer -Value Enable-PodeOAViewer } if (!(Test-Path Alias:Enable-PodeOA)) { @@ -903,4 +949,3 @@ if (!(Test-Path Alias:Enable-PodeOA)) { if (!(Test-Path Alias:Get-PodeOpenApiDefinition)) { New-Alias Get-PodeOpenApiDefinition -Value Get-PodeOADefinition } - diff --git a/src/Public/OAProperties.ps1 b/src/Public/OAProperties.ps1 index 778d35139..80a0a7f65 100644 --- a/src/Public/OAProperties.ps1 +++ b/src/Public/OAProperties.ps1 @@ -174,7 +174,7 @@ New-PodeOAMultiTypeProperty -Name 'password' -type string,object -Format Passwor function New-PodeOAMultiTypeProperty { [CmdletBinding(DefaultParameterSetName = 'Inbuilt')] param( - [Parameter(ValueFromPipeline = $true, DontShow = $true )] + [Parameter(ValueFromPipeline = $true, Position = 0, DontShow = $true )] [hashtable[]] $ParamsList, @@ -401,6 +401,7 @@ function New-PodeOAMultiTypeProperty { } } } + <# .SYNOPSIS Creates a new OpenAPI integer property. @@ -541,7 +542,7 @@ function New-PodeOAIntProperty { [CmdletBinding(DefaultParameterSetName = 'Inbuilt')] [OutputType([System.Collections.Specialized.OrderedDictionary])] param( - [Parameter(ValueFromPipeline = $true, DontShow = $true)] + [Parameter(ValueFromPipeline = $true, Position = 0, DontShow = $true)] [hashtable[]] $ParamsList, @@ -800,7 +801,7 @@ New-PodeOANumberProperty -Name 'gravity' -Default 9.8 function New-PodeOANumberProperty { [CmdletBinding(DefaultParameterSetName = 'Inbuilt')] param( - [Parameter(ValueFromPipeline = $true, DontShow = $true )] + [Parameter(ValueFromPipeline = $true, Position = 0, DontShow = $true )] [hashtable[]] $ParamsList, @@ -1055,7 +1056,7 @@ New-PodeOAStringProperty -Name 'password' -Format Password function New-PodeOAStringProperty { [CmdletBinding(DefaultParameterSetName = 'Inbuilt')] param( - [Parameter(ValueFromPipeline = $true, DontShow = $true )] + [Parameter(ValueFromPipeline = $true, Position = 0, DontShow = $true )] [hashtable[]] $ParamsList, @@ -1301,7 +1302,7 @@ function New-PodeOABoolProperty { [CmdletBinding(DefaultParameterSetName = 'Inbuilt')] param( - [Parameter(ValueFromPipeline = $true, DontShow = $true)] + [Parameter(ValueFromPipeline = $true, Position = 0, DontShow = $true)] [hashtable[]] $ParamsList, @@ -1547,7 +1548,7 @@ function New-PodeOAObjectProperty { [CmdletBinding(DefaultParameterSetName = 'Inbuilt')] param( - [Parameter(ValueFromPipeline = $true, DontShow = $true , Position = 0 )] + [Parameter(ValueFromPipeline = $true, Position = 0, DontShow = $true )] [hashtable[]] $ParamsList, @@ -1767,7 +1768,7 @@ function Merge-PodeOAProperty { [OutputType([System.Collections.Specialized.OrderedDictionary])] param( - [Parameter(ValueFromPipeline = $true, DontShow = $true )] + [Parameter(ValueFromPipeline = $true, Position = 0, DontShow = $true )] [hashtable[]] $ParamsList, @@ -2096,4 +2097,4 @@ function New-PodeOAComponentSchemaProperty { if (!(Test-Path Alias:New-PodeOASchemaProperty)) { New-Alias New-PodeOASchemaProperty -Value New-PodeOAComponentSchemaProperty -} +} \ No newline at end of file diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index 77dd0a4d4..dcf994aa1 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -295,11 +295,11 @@ function Enable-PodeOpenApi { Write-PodeTextResponse -Value (ConvertTo-PodeYaml -InputObject $def -depth $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.depth) -ContentType 'application/yaml; charset=utf-8' #Changed to be RFC 9512 compliant } else { - Write-PodeYamlResponse -Value $def -depth $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.depth + Write-PodeYamlResponse -Value $def -Depth $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.depth } } else { - Write-PodeJsonResponse -Value $def -depth $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.depth -NoCompress:$meta.NoCompress + Write-PodeJsonResponse -Value $def -Depth $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.depth -NoCompress:$meta.NoCompress } } @@ -502,14 +502,14 @@ function Get-PodeOADefinition { $meta.Description = $Description } - $oApi = Get-PodeOpenApiDefinitionInternal -MetaInfo $meta -EndpointName $WebEvent.Endpoint.Name -DefinitionTag $DefinitionTag + $oApi = Get-PodeOpenApiDefinitionInternal -MetaInfo $meta -EndpointName $WebEvent.Endpoint.Name -DefinitionTag $DefinitionTag switch ($Format.ToLower()) { 'json' { - return ConvertTo-Json -InputObject $oApi -depth $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.depth + return ConvertTo-Json -InputObject $oApi -Depth $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.depth } 'json-compress' { - return ConvertTo-Json -InputObject $oApi -depth $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.depth -Compress + return ConvertTo-Json -InputObject $oApi -Depth $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.depth -Compress } 'yaml' { return ConvertTo-PodeYaml -InputObject $oApi -depth $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.depth @@ -626,35 +626,45 @@ function Add-PodeOAResponse { [string[]] $DefinitionTag ) - - if ($null -eq $Route) { - # The parameter 'Route' cannot be null - throw ($PodeLocale.routeParameterCannotBeNullExceptionMessage) + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() } - $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag - # override status code with default - if ($Default) { - $code = 'default' - } - else { - $code = "$($StatusCode)" + process { + # Add the current piped-in value to the array + $pipelineValue += $_ } - # add the respones to the routes - foreach ($r in @($Route)) { - foreach ($tag in $DefinitionTag) { - if (! $r.OpenApi.Responses.$tag) { - $r.OpenApi.Responses.$tag = @{} + end { + # Set Route to the array of values + if ($pipelineValue.Count -gt 1) { + $Route = $pipelineValue + } + + $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + # override status code with default + if ($Default) { + $code = 'default' + } + else { + $code = "$($StatusCode)" + } + + # add the respones to the routes + foreach ($r in $Route) { + foreach ($tag in $DefinitionTag) { + if (! $r.OpenApi.Responses.$tag) { + $r.OpenApi.Responses.$tag = @{} + } + $r.OpenApi.Responses.$tag[$code] = New-PodeOResponseInternal -DefinitionTag $tag -Params $PSBoundParameters } - $r.OpenApi.Responses.$tag[$code] = New-PodeOResponseInternal -DefinitionTag $tag -Params $PSBoundParameters } - } - if ($PassThru) { - return $Route + if ($PassThru) { + return $Route + } } - } @@ -702,26 +712,37 @@ function Remove-PodeOAResponse { [switch] $PassThru ) - - if ($null -eq $Route) { - # The parameter 'Route' cannot be null - throw ($PodeLocale.routeParameterCannotBeNullExceptionMessage) + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() } - # override status code with default - $code = "$($StatusCode)" - if ($Default) { - $code = 'default' + process { + # Add the current piped-in value to the array + $pipelineValue += $_ } - # remove the respones from the routes - foreach ($r in @($Route)) { - if ($r.OpenApi.Responses.ContainsKey($code)) { - $null = $r.OpenApi.Responses.Remove($code) + + end { + # Set Route to the array of values + if ($pipelineValue.Count -gt 1) { + $Route = $pipelineValue } - } - if ($PassThru) { - return $Route + # override status code with default + $code = "$($StatusCode)" + if ($Default) { + $code = 'default' + } + # remove the respones from the routes + foreach ($r in $Route) { + if ($r.OpenApi.Responses.ContainsKey($code)) { + $null = $r.OpenApi.Responses.Remove($code) + } + } + + if ($PassThru) { + return $Route + } } } @@ -752,7 +773,7 @@ function Set-PodeOARequest { [CmdletBinding()] [OutputType([hashtable[]])] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [hashtable[]] $Route, @@ -766,18 +787,28 @@ function Set-PodeOARequest { [switch] $PassThru ) - - if ($null -eq $Route) { - # The parameter 'Route' cannot be null - throw ($PodeLocale.routeParameterCannotBeNullExceptionMessage) + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() } - foreach ($r in @($Route)) { + process { + # Add the current piped-in value to the array + $pipelineValue += $_ + } - if (($null -ne $Parameters) -and ($Parameters.Length -gt 0)) { - $r.OpenApi.Parameters = @($Parameters) + end { + # Set Route to the array of values + if ($pipelineValue.Count -gt 1) { + $Route = $pipelineValue } + foreach ($r in $Route) { + + if (($null -ne $Parameters) -and ($Parameters.Length -gt 0)) { + $r.OpenApi.Parameters = @($Parameters) + } + if ($null -ne $RequestBody) { # Only 'POST', 'PUT', 'PATCH' can have a request body if (('POST', 'PUT', 'PATCH') -inotcontains $r.Method ) { @@ -789,8 +820,9 @@ function Set-PodeOARequest { } - if ($PassThru) { - return $Route + if ($PassThru) { + return $Route + } } } @@ -1122,8 +1154,8 @@ function ConvertTo-PodeOAParameter { [string] $In, - [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'Properties')] - [Parameter( Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'ContentProperties')] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ParameterSetName = 'Properties')] + [Parameter( Mandatory = $true, Position = 0, ValueFromPipeline = $true, ParameterSetName = 'ContentProperties')] [ValidateNotNull()] [hashtable] $Property, @@ -1211,105 +1243,117 @@ function ConvertTo-PodeOAParameter { [string[]] $DefinitionTag ) + begin { + $pipelineItemCount = 0 + } - $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + process { + $pipelineItemCount++ + } - if ($PSCmdlet.ParameterSetName -ieq 'ContentSchema' -or $PSCmdlet.ParameterSetName -ieq 'Schema') { - if (Test-PodeIsEmpty $Schema) { - return $null - } - Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $Schema -PostValidation - if (!$Name ) { - $Name = $Schema - } - $prop = [ordered]@{ - in = $In.ToLowerInvariant() - name = $Name - } - if ($In -ieq 'Header' -and $PodeContext.Server.Security.autoHeaders) { - Add-PodeSecurityHeader -Name 'Access-Control-Allow-Headers' -Value $Schema -Append - } - if ($AllowEmptyValue.IsPresent ) { - $prop['allowEmptyValue'] = $AllowEmptyValue.IsPresent - } - if ($Required.IsPresent ) { - $prop['required'] = $Required.IsPresent - } - if ($Description ) { - $prop.description = $Description - } - if ($Deprecated.IsPresent ) { - $prop.deprecated = $Deprecated.IsPresent + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) } - if ($ContentType ) { - # ensure all content types are valid - if ($ContentType -inotmatch '^[\w-]+\/[\w\.\+-]+$') { - # Invalid 'content-type' found for schema: $type - throw ($PodeLocale.invalidContentTypeForSchemaExceptionMessage -f $type) + + $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + + if ($PSCmdlet.ParameterSetName -ieq 'ContentSchema' -or $PSCmdlet.ParameterSetName -ieq 'Schema') { + if (Test-PodeIsEmpty $Schema) { + return $null } - $prop.content = [ordered]@{ - $ContentType = [ordered]@{ - schema = [ordered]@{ - '$ref' = "#/components/schemas/$($Schema )" - } - } + Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $Schema -PostValidation + if (!$Name ) { + $Name = $Schema } - if ($Example ) { - $prop.content.$ContentType.example = $Example + $prop = [ordered]@{ + in = $In.ToLowerInvariant() + name = $Name } - elseif ($Examples) { - $prop.content.$ContentType.examples = $Examples + if ($In -ieq 'Header' -and $PodeContext.Server.Security.autoHeaders) { + Add-PodeSecurityHeader -Name 'Access-Control-Allow-Headers' -Value $Schema -Append } - } - else { - $prop.schema = [ordered]@{ - '$ref' = "#/components/schemas/$($Schema )" - } - if ($Style) { - switch ($in.ToLower()) { - 'path' { - if (@('Simple', 'Label', 'Matrix' ) -inotcontains $Style) { - # OpenApi request Style cannot be $Style for a $in parameter - throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + if ($AllowEmptyValue.IsPresent ) { + $prop['allowEmptyValue'] = $AllowEmptyValue.IsPresent + } + if ($Required.IsPresent ) { + $prop['required'] = $Required.IsPresent + } + if ($Description ) { + $prop.description = $Description + } + if ($Deprecated.IsPresent ) { + $prop.deprecated = $Deprecated.IsPresent + } + if ($ContentType ) { + # ensure all content types are valid + if ($ContentType -inotmatch '^[\w-]+\/[\w\.\+-]+$') { + # Invalid 'content-type' found for schema: $type + throw ($PodeLocale.invalidContentTypeForSchemaExceptionMessage -f $type) + } + $prop.content = [ordered]@{ + $ContentType = [ordered]@{ + schema = [ordered]@{ + '$ref' = "#/components/schemas/$($Schema )" } - break } - 'query' { - if (@('Form', 'SpaceDelimited', 'PipeDelimited', 'DeepObject' ) -inotcontains $Style) { - # OpenApi request Style cannot be $Style for a $in parameter - throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + } + if ($Example ) { + $prop.content.$ContentType.example = $Example + } + elseif ($Examples) { + $prop.content.$ContentType.examples = $Examples + } + } + else { + $prop.schema = [ordered]@{ + '$ref' = "#/components/schemas/$($Schema )" + } + if ($Style) { + switch ($in.ToLower()) { + 'path' { + if (@('Simple', 'Label', 'Matrix' ) -inotcontains $Style) { + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + } + break } - break - } - 'header' { - if (@('Simple' ) -inotcontains $Style) { - # OpenApi request Style cannot be $Style for a $in parameter - throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + 'query' { + if (@('Form', 'SpaceDelimited', 'PipeDelimited', 'DeepObject' ) -inotcontains $Style) { + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + } + break } - break - } - 'cookie' { - if (@('Form' ) -inotcontains $Style) { - # OpenApi request Style cannot be $Style for a $in parameter - throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + 'header' { + if (@('Simple' ) -inotcontains $Style) { + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + } + break + } + 'cookie' { + if (@('Form' ) -inotcontains $Style) { + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + } + break } - break } + $prop['style'] = $Style.Substring(0, 1).ToLower() + $Style.Substring(1) } - $prop['style'] = $Style.Substring(0, 1).ToLower() + $Style.Substring(1) - } - if ($Explode.IsPresent ) { - $prop['explode'] = $Explode.IsPresent - } + if ($Explode.IsPresent ) { + $prop['explode'] = $Explode.IsPresent + } - if ($AllowEmptyValue.IsPresent ) { - $prop['allowEmptyValue'] = $AllowEmptyValue.IsPresent - } + if ($AllowEmptyValue.IsPresent ) { + $prop['allowEmptyValue'] = $AllowEmptyValue.IsPresent + } - if ($AllowReserved.IsPresent) { - $prop['allowReserved'] = $AllowReserved.IsPresent - } + if ($AllowReserved.IsPresent) { + $prop['allowReserved'] = $AllowReserved.IsPresent + } if ($Example ) { $prop.example = $Example @@ -1333,163 +1377,164 @@ function ConvertTo-PodeOAParameter { } else { - if (!$Name ) { - if ($Property.name) { - $Name = $Property.name + if (!$Name ) { + if ($Property.name) { + $Name = $Property.name + } + else { + # The OpenApi parameter requires a name to be specified + throw ($PodeLocale.openApiParameterRequiresNameExceptionMessage) + } } - else { - # The OpenApi parameter requires a name to be specified - throw ($PodeLocale.openApiParameterRequiresNameExceptionMessage) + if ($In -ieq 'Header' -and $PodeContext.Server.Security.autoHeaders -and $Name ) { + Add-PodeSecurityHeader -Name 'Access-Control-Allow-Headers' -Value $Name -Append } - } - if ($In -ieq 'Header' -and $PodeContext.Server.Security.autoHeaders -and $Name ) { - Add-PodeSecurityHeader -Name 'Access-Control-Allow-Headers' -Value $Name -Append - } - # build the base parameter - $prop = [ordered]@{ - in = $In.ToLowerInvariant() - name = $Name - } - $sch = [ordered]@{} - if ($Property.array) { - $sch.type = 'array' - $sch.items = [ordered]@{ - type = $Property.type - } - if ($Property.format) { - $sch.items.format = $Property.format + # build the base parameter + $prop = [ordered]@{ + in = $In.ToLowerInvariant() + name = $Name } - } - else { - $sch.type = $Property.type - if ($Property.format) { - $sch.format = $Property.format + $sch = [ordered]@{} + if ($Property.array) { + $sch.type = 'array' + $sch.items = [ordered]@{ + type = $Property.type + } + if ($Property.format) { + $sch.items.format = $Property.format + } } - } - if ($ContentType) { - if ($ContentType -inotmatch '^[\w-]+\/[\w\.\+-]+$') { - # Invalid 'content-type' found for schema: $type - throw ($PodeLocale.invalidContentTypeForSchemaExceptionMessage -f $type) + else { + $sch.type = $Property.type + if ($Property.format) { + $sch.format = $Property.format + } } - $prop.content = [ordered]@{ - $ContentType = [ordered] @{ - schema = $sch + if ($ContentType) { + if ($ContentType -inotmatch '^[\w-]+\/[\w\.\+-]+$') { + # Invalid 'content-type' found for schema: $type + throw ($PodeLocale.invalidContentTypeForSchemaExceptionMessage -f $type) + } + $prop.content = [ordered]@{ + $ContentType = [ordered] @{ + schema = $sch + } } } - } - else { - $prop.schema = $sch - } + else { + $prop.schema = $sch + } - if ($Example -and $Examples) { - # Parameters 'Examples' and 'Example' are mutually exclusive - throw ($PodeLocale.parametersMutuallyExclusiveExceptionMessage -f 'Examples' , 'Example' ) - } - if ($AllowEmptyValue.IsPresent ) { - $prop['allowEmptyValue'] = $AllowEmptyValue.IsPresent - } + if ($Example -and $Examples) { + # Parameters 'Examples' and 'Example' are mutually exclusive + throw ($PodeLocale.parametersMutuallyExclusiveExceptionMessage -f 'Examples' , 'Example' ) + } + if ($AllowEmptyValue.IsPresent ) { + $prop['allowEmptyValue'] = $AllowEmptyValue.IsPresent + } - if ($Description ) { - $prop.description = $Description - } - elseif ($Property.description) { - $prop.description = $Property.description - } + if ($Description ) { + $prop.description = $Description + } + elseif ($Property.description) { + $prop.description = $Property.description + } - if ($Required.IsPresent ) { - $prop.required = $Required.IsPresent - } - elseif ($Property.required) { - $prop.required = $Property.required - } + if ($Required.IsPresent ) { + $prop.required = $Required.IsPresent + } + elseif ($Property.required) { + $prop.required = $Property.required + } - if ($Deprecated.IsPresent ) { - $prop.deprecated = $Deprecated.IsPresent - } - elseif ($Property.deprecated) { - $prop.deprecated = $Property.deprecated - } + if ($Deprecated.IsPresent ) { + $prop.deprecated = $Deprecated.IsPresent + } + elseif ($Property.deprecated) { + $prop.deprecated = $Property.deprecated + } - if (!$ContentType) { - if ($Style) { - switch ($in.ToLower()) { - 'path' { - if (@('Simple', 'Label', 'Matrix' ) -inotcontains $Style) { - # OpenApi request Style cannot be $Style for a $in parameter - throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + if (!$ContentType) { + if ($Style) { + switch ($in.ToLower()) { + 'path' { + if (@('Simple', 'Label', 'Matrix' ) -inotcontains $Style) { + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + } + break } - break - } - 'query' { - if (@('Form', 'SpaceDelimited', 'PipeDelimited', 'DeepObject' ) -inotcontains $Style) { - # OpenApi request Style cannot be $Style for a $in parameter - throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + 'query' { + if (@('Form', 'SpaceDelimited', 'PipeDelimited', 'DeepObject' ) -inotcontains $Style) { + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + } + break } - break - } - 'header' { - if (@('Simple' ) -inotcontains $Style) { - # OpenApi request Style cannot be $Style for a $in parameter - throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + 'header' { + if (@('Simple' ) -inotcontains $Style) { + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + } + break } - break - } - 'cookie' { - if (@('Form' ) -inotcontains $Style) { - # OpenApi request Style cannot be $Style for a $in parameter - throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + 'cookie' { + if (@('Form' ) -inotcontains $Style) { + # OpenApi request Style cannot be $Style for a $in parameter + throw ($PodeLocale.openApiRequestStyleInvalidForParameterExceptionMessage -f $Style, $in) + } + break } - break } + $prop['style'] = $Style.Substring(0, 1).ToLower() + $Style.Substring(1) } - $prop['style'] = $Style.Substring(0, 1).ToLower() + $Style.Substring(1) - } - if ($Explode.IsPresent ) { - $prop['explode'] = $Explode.IsPresent - } + if ($Explode.IsPresent ) { + $prop['explode'] = $Explode.IsPresent + } - if ($AllowReserved.IsPresent) { - $prop['allowReserved'] = $AllowReserved.IsPresent - } + if ($AllowReserved.IsPresent) { + $prop['allowReserved'] = $AllowReserved.IsPresent + } - if ($Example ) { - $prop['example'] = $Example - } - elseif ($Examples) { - $prop['examples'] = $Examples - } + if ($Example ) { + $prop['example'] = $Example + } + elseif ($Examples) { + $prop['examples'] = $Examples + } - if ($Property.default -and !$prop.required ) { - $prop.schema['default'] = $Property.default - } + if ($Property.default -and !$prop.required ) { + $prop.schema['default'] = $Property.default + } - if ($Property.enum) { - if ($Property.array) { - $prop.schema.items['enum'] = $Property.enum + if ($Property.enum) { + if ($Property.array) { + $prop.schema.items['enum'] = $Property.enum + } + else { + $prop.schema['enum'] = $Property.enum + } } - else { - $prop.schema['enum'] = $Property.enum + } + else { + if ($Example ) { + $prop.content.$ContentType.example = $Example + } + elseif ($Examples) { + $prop.content.$ContentType.examples = $Examples } } } - else { - if ($Example ) { - $prop.content.$ContentType.example = $Example - } - elseif ($Examples) { - $prop.content.$ContentType.examples = $Examples - } + + if ($In -ieq 'Path' -and !$prop.required ) { + # If the parameter location is 'Path', the switch parameter 'Required' is mandatory + throw ($PodeLocale.pathParameterRequiresRequiredSwitchExceptionMessage) } - } - if ($In -ieq 'Path' -and !$prop.required ) { - # If the parameter location is 'Path', the switch parameter 'Required' is mandatory - throw ($PodeLocale.pathParameterRequiresRequiredSwitchExceptionMessage) + return $prop } - - return $prop } <# @@ -1536,7 +1581,7 @@ function Set-PodeOARouteInfo { [CmdletBinding()] [OutputType([hashtable[]])] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [hashtable[]] $Route, @@ -1565,13 +1610,23 @@ function Set-PodeOARouteInfo { [string[]] $DefinitionTag ) + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() + } - if ($null -eq $Route) { - # The parameter 'Route' cannot be null - throw ($PodeLocale.routeParameterCannotBeNullExceptionMessage) + process { + # Add the current piped-in value to the array + $pipelineValue += $_ } - $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + end { + # Set Route to the array of values + if ($pipelineValue.Count -gt 1) { + $Route = $pipelineValue + } + + $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag foreach ($r in @($Route)) { if ((Compare-Object -ReferenceObject $r.OpenApi.DefinitionTag -DifferenceObject $DefinitionTag).Count -ne 0) { @@ -1585,42 +1640,47 @@ function Set-PodeOARouteInfo { } } - if ($Summary) { - $r.OpenApi.Summary = $Summary - } - if ($Description) { - $r.OpenApi.Description = $Description - } - if ($OperationId) { - if ($Route.Count -gt 1) { - # OperationID:$OperationId has to be unique and cannot be applied to an array - throw ($PodeLocale.operationIdMustBeUniqueForArrayExceptionMessage -f $OperationId) - } - foreach ($tag in $DefinitionTag) { - if ($PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.operationId -ccontains $OperationId) { - # OperationID:$OperationId has to be unique - throw ($PodeLocale.operationIdMustBeUniqueExceptionMessage -f $OperationId) + if ($OperationId) { + if ($Route.Count -gt 1) { + # OperationID:$OperationId has to be unique and cannot be applied to an array + throw ($PodeLocale.operationIdMustBeUniqueForArrayExceptionMessage -f $OperationId) } - $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.operationId += $OperationId + foreach ($tag in $DefinitionTag) { + if ($PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.operationId -ccontains $OperationId) { + # OperationID:$OperationId has to be unique + throw ($PodeLocale.operationIdMustBeUniqueExceptionMessage -f $OperationId) + } + $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.operationId += $OperationId + } + $r.OpenApi.OperationId = $OperationId } - $r.OpenApi.OperationId = $OperationId - } - if ($Tags) { - $r.OpenApi.Tags = $Tags - } - if ($ExternalDocs) { - $r.OpenApi.ExternalDocs = $ExternalDoc - } + if ($Summary) { + $r.OpenApi.Summary = $Summary + } - $r.OpenApi.Swagger = $true - if ($Deprecated.IsPresent) { - $r.OpenApi.Deprecated = $Deprecated.IsPresent + if ($Description) { + $r.OpenApi.Description = $Description + } + + if ($Tags) { + $r.OpenApi.Tags = $Tags + } + + if ($ExternalDocs) { + $r.OpenApi.ExternalDocs = $ExternalDoc + } + + $r.OpenApi.Swagger = $true + + if ($Deprecated.IsPresent) { + $r.OpenApi.Deprecated = $Deprecated.IsPresent + } } - } - if ($PassThru) { - return $Route + if ($PassThru) { + return $Route + } } } @@ -1985,7 +2045,7 @@ $ExtDoc|Add-PodeOAExternalDoc function Add-PodeOAExternalDoc { [CmdletBinding(DefaultParameterSetName = 'Pipe')] param( - [Parameter(ValueFromPipeline = $true, DontShow = $true, ParameterSetName = 'Pipe')] + [Parameter(ValueFromPipeline = $true, Position = 0, DontShow = $true, ParameterSetName = 'Pipe')] [System.Collections.Specialized.OrderedDictionary ] $ExternalDoc, @@ -2000,22 +2060,33 @@ function Add-PodeOAExternalDoc { [string[]] $DefinitionTag ) + begin { + $pipelineItemCount = 0 + } - $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + process { + $pipelineItemCount++ + } - foreach ($tag in $DefinitionTag) { - if ($PSCmdlet.ParameterSetName -ieq 'NewRef') { - $param = [ordered]@{url = $Url } - if ($Description) { - $param.description = $Description - } - $PodeContext.Server.OpenAPI.Definitions[$tag].externalDocs = $param + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) } - else { - $PodeContext.Server.OpenAPI.Definitions[$tag].externalDocs = $ExternalDoc + $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + + foreach ($tag in $DefinitionTag) { + if ($PSCmdlet.ParameterSetName -ieq 'NewRef') { + $param = [ordered]@{url = $Url } + if ($Description) { + $param.description = $Description + } + $PodeContext.Server.OpenAPI.Definitions[$tag].externalDocs = $param + } + else { + $PodeContext.Server.OpenAPI.Definitions[$tag].externalDocs = $ExternalDoc + } } } - } @@ -2287,8 +2358,8 @@ function New-PodeOAExample { [OutputType([System.Collections.Specialized.OrderedDictionary ])] param( - [Parameter(ValueFromPipeline = $true, DontShow = $true, ParameterSetName = 'Inbuilt')] - [Parameter(ValueFromPipeline = $true, DontShow = $true, ParameterSetName = 'Reference')] + [Parameter(ValueFromPipeline = $true, Position = 0, DontShow = $true, ParameterSetName = 'Inbuilt')] + [Parameter(ValueFromPipeline = $true, Position = 0, DontShow = $true, ParameterSetName = 'Reference')] [System.Collections.Specialized.OrderedDictionary ] $ParamsList, @@ -2431,7 +2502,7 @@ New-PodeOAEncodingObject -Name 'profileImage' -ContentType 'image/png, image/jpe #> function New-PodeOAEncodingObject { param ( - [Parameter(ValueFromPipeline = $true, DontShow = $true )] + [Parameter(ValueFromPipeline = $true, Position = 0, DontShow = $true )] [hashtable[]] $EncodingList, @@ -2564,7 +2635,7 @@ function Add-PodeOACallBack { [CmdletBinding(DefaultParameterSetName = 'inbuilt')] [OutputType([hashtable[]])] param ( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [hashtable[]] $Route, @@ -2606,39 +2677,50 @@ function Add-PodeOACallBack { [string[]] $DefinitionTag ) + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() + } - if ($null -eq $Route) { - # The parameter 'Route' cannot be null - throw ($PodeLocale.routeParameterCannotBeNullExceptionMessage) + process { + # Add the current piped-in value to the array + $pipelineValue += $_ } - $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + end { + # Set Route to the array of values + if ($pipelineValue.Count -gt 1) { + $Route = $pipelineValue + } - foreach ($r in @($Route)) { - foreach ($tag in $DefinitionTag) { - if ($Reference) { - Test-PodeOAComponentInternal -Field callbacks -DefinitionTag $tag -Name $Reference -PostValidation - if (!$Name) { - $Name = $Reference - } - if (! $r.OpenApi.CallBacks.ContainsKey($tag)) { - $r.OpenApi.CallBacks[$tag] = [ordered]@{} - } - $r.OpenApi.CallBacks[$tag].$Name = @{ - '$ref' = "#/components/callbacks/$Reference" + $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + + foreach ($r in $Route) { + foreach ($tag in $DefinitionTag) { + if ($Reference) { + Test-PodeOAComponentInternal -Field callbacks -DefinitionTag $tag -Name $Reference -PostValidation + if (!$Name) { + $Name = $Reference + } + if (! $r.OpenApi.CallBacks.ContainsKey($tag)) { + $r.OpenApi.CallBacks[$tag] = [ordered]@{} + } + $r.OpenApi.CallBacks[$tag].$Name = @{ + '$ref' = "#/components/callbacks/$Reference" + } } - } - else { - if (! $r.OpenApi.CallBacks.ContainsKey($tag)) { - $r.OpenApi.CallBacks[$tag] = [ordered]@{} + else { + if (! $r.OpenApi.CallBacks.ContainsKey($tag)) { + $r.OpenApi.CallBacks[$tag] = [ordered]@{} + } + $r.OpenApi.CallBacks[$tag].$Name = New-PodeOAComponentCallBackInternal -Params $PSBoundParameters -DefinitionTag $tag } - $r.OpenApi.CallBacks[$tag].$Name = New-PodeOAComponentCallBackInternal -Params $PSBoundParameters -DefinitionTag $tag } } - } - if ($PassThru) { - return $Route + if ($PassThru) { + return $Route + } } } @@ -2707,7 +2789,7 @@ function New-PodeOAResponse { [CmdletBinding(DefaultParameterSetName = 'Schema')] [OutputType([hashtable])] param( - [Parameter(ValueFromPipeline = $true , DontShow = $true )] + [Parameter(ValueFromPipeline = $true , Position = 0, DontShow = $true )] [hashtable] $ResponseList, @@ -3026,7 +3108,7 @@ function New-PodeOAResponseLink { [CmdletBinding(DefaultParameterSetName = 'OperationId')] [OutputType([System.Collections.Specialized.OrderedDictionary])] param( - [Parameter(ValueFromPipeline = $true , DontShow = $true )] + [Parameter(ValueFromPipeline = $true , Position = 0, DontShow = $true )] [System.Collections.Specialized.OrderedDictionary ] $LinkList, @@ -3074,7 +3156,7 @@ function New-PodeOAResponseLink { $DefinitionTag = $PodeContext.Server.OpenAPI.SelectedDefinitionTag } if ($Reference) { - Test-PodeOAComponentInternal -Field links -DefinitionTag $DefinitionTag -Name $Reference -PostValidation + Test-PodeOAComponentInternal -Field links -DefinitionTag $DefinitionTag -Name $Reference -PostValidation if (!$Name) { $Name = $Reference } @@ -3163,7 +3245,7 @@ function Add-PodeOAExternalRoute { [OutputType([hashtable[]], ParameterSetName = 'Pipeline')] [OutputType([hashtable], ParameterSetName = 'builtin')] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'Pipeline')] + [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0, ParameterSetName = 'Pipeline')] [ValidateNotNullOrEmpty()] [hashtable[]] $Route, @@ -3189,58 +3271,71 @@ function Add-PodeOAExternalRoute { [string[]] $DefinitionTag ) + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() + } - $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + process { + if ($PSCmdlet.ParameterSetName -eq 'Pipeline') { + # Add the current piped-in value to the array + $pipelineValue += $_ + } + } - switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { - 'builtin' { - - # ensure the route has appropriate slashes - $Path = Update-PodeRouteSlash -Path $Path - $OpenApiPath = ConvertTo-PodeOpenApiRoutePath -Path $Path - $Path = Resolve-PodePlaceholder -Path $Path - $extRoute = @{ - Method = $Method.ToLower() - Path = $Path - Local = $false - OpenApi = @{ - Path = $OpenApiPath - Responses = $null - Parameters = $null - RequestBody = $null - callbacks = [ordered]@{} - Authentication = @() - Servers = $Servers - DefinitionTag = $DefinitionTag - } - } - foreach ($tag in $DefinitionTag) { - #add the default OpenApi responses - if ( $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses) { - $extRoute.OpenApi.Responses = $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses.Clone() + end { + $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + + switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { + 'builtin' { + # ensure the route has appropriate slashes + $Path = Update-PodeRouteSlash -Path $Path + $OpenApiPath = ConvertTo-PodeOpenApiRoutePath -Path $Path + $Path = Resolve-PodePlaceholder -Path $Path + $extRoute = @{ + Method = $Method.ToLower() + Path = $Path + Local = $false + OpenApi = @{ + Path = $OpenApiPath + Responses = $null + Parameters = $null + RequestBody = $null + callbacks = [ordered]@{} + Authentication = @() + Servers = $Servers + DefinitionTag = $DefinitionTag + } } - if (! (Test-PodeOAComponentExternalPath -DefinitionTag $tag -Name $Path)) { - $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.externalPath[$Path] = @{} + foreach ($tag in $DefinitionTag) { + #add the default OpenApi responses + if ( $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses) { + $extRoute.OpenApi.Responses = $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses.Clone() + } + if (! (Test-PodeOAComponentExternalPath -DefinitionTag $tag -Name $Path)) { + $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.externalPath[$Path] = @{} + } + + $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.externalPath.$Path[$Method] = $extRoute } - $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.externalPath.$Path[$Method] = $extRoute + if ($PassThru) { + return $extRoute + } } - if ($PassThru) { - return $extRoute - } - } + 'pipeline' { + # Set Route to the array of values + if ($pipelineValue.Count -gt 1) { + $Route = $pipelineValue + } - 'pipeline' { - if ($null -eq $Route) { - # The parameter 'Route' cannot be null - throw ($PodeLocale.routeParameterCannotBeNullExceptionMessage) - } - foreach ($r in @($Route)) { - $r.OpenApi.Servers = $Servers - } - if ($PassThru) { - return $Route + foreach ($r in $Route) { + $r.OpenApi.Servers = $Servers + } + if ($PassThru) { + return $Route + } } } } @@ -3274,7 +3369,7 @@ New-PodeOAServerEndpoint -Url '/api' -Description 'My local server' #> function New-PodeOAServerEndpoint { param ( - [Parameter(ValueFromPipeline = $true , DontShow = $true )] + [Parameter(ValueFromPipeline = $true , Position = 0, DontShow = $true )] [hashtable[]] $ServerEndpointList, @@ -3443,7 +3538,7 @@ function Select-PodeOADefinition { $PodeContext.Server.OpenAPI.SelectedDefinitionTag = $Tag - $null = Invoke-PodeScriptBlock -ScriptBlock $Scriptblock -UsingVariables $usingVars -Splat + $null = Invoke-PodeScriptBlock -ScriptBlock $Scriptblock -UsingVariables $usingVars -Splat $PodeContext.Server.OpenAPI.SelectedDefinitionTag = $PodeContext.Server.OpenApi.DefinitionTagSelectionStack.Pop() } diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index e46bb932a..d55f9fec6 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -40,7 +40,7 @@ Set-PodeResponseAttachment -Path '/assets/data.txt' -EndpointName 'Example' function Set-PodeResponseAttachment { [CmdletBinding()] param ( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [string] $Path, @@ -56,23 +56,36 @@ function Set-PodeResponseAttachment { $FileBrowser ) + begin { + $pipelineItemCount = 0 + } - # already sent? skip - if ($WebEvent.Response.Sent) { - return + process { + $pipelineItemCount++ } - # only attach files from public/static-route directories when path is relative - $route = (Find-PodeStaticRoute -Path $Path -CheckPublic -EndpointName $EndpointName) - if ($route) { - $_path = $route.Content.Source + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # already sent? skip + if ($WebEvent.Response.Sent) { + return + } + + # only attach files from public/static-route directories when path is relative + $route = (Find-PodeStaticRoute -Path $Path -CheckPublic -EndpointName $EndpointName) + if ($route) { + $_path = $route.Content.Source + + } + else { + $_path = Get-PodeRelativePath -Path $Path -JoinRoot + } + #call internal Attachment function + Write-PodeAttachmentResponseInternal -Path $_path -ContentType $ContentType -FileBrowser:$fileBrowser } - else { - $_path = Get-PodeRelativePath -Path $Path -JoinRoot - } - #call internal Attachment function - Write-PodeAttachmentResponseInternal -Path $_path -ContentType $ContentType -FileBrowser:$fileBrowser } @@ -139,157 +152,169 @@ function Write-PodeTextResponse { [switch] $Cache ) + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() + }process { + # Add the current piped-in value to the array + $pipelineValue += $_ + }end { + # Set Value to the array of values + if ($pipelineValue.Count -gt 1) { + $Value = $pipelineValue -join "`n" + } - $isStringValue = ($PSCmdlet.ParameterSetName -ieq 'string') - $isByteValue = ($PSCmdlet.ParameterSetName -ieq 'bytes') - - # set the status code of the response, but only if it's not 200 (to prevent overriding) - if ($StatusCode -ne 200) { - Set-PodeResponseStatus -Code $StatusCode -NoErrorPage - } + $isStringValue = ($PSCmdlet.ParameterSetName -ieq 'string') + $isByteValue = ($PSCmdlet.ParameterSetName -ieq 'bytes') - # if there's nothing to write, return - if ($isStringValue -and [string]::IsNullOrWhiteSpace($Value)) { - return - } + # set the status code of the response, but only if it's not 200 (to prevent overriding) + if ($StatusCode -ne 200) { + Set-PodeResponseStatus -Code $StatusCode -NoErrorPage + } - if ($isByteValue -and (($null -eq $Bytes) -or ($Bytes.Length -eq 0))) { - return - } + # if there's nothing to write, return + if ($isStringValue -and [string]::IsNullOrWhiteSpace($Value)) { + return + } - # if the response stream isn't writable or already sent, return - $res = $WebEvent.Response - if (($null -eq $res) -or ($WebEvent.Streamed -and (($null -eq $res.OutputStream) -or !$res.OutputStream.CanWrite -or $res.Sent))) { - return - } + if ($isByteValue -and (($null -eq $Bytes) -or ($Bytes.Length -eq 0))) { + return + } - # set a cache value - if ($Cache) { - Set-PodeHeader -Name 'Cache-Control' -Value "max-age=$($MaxAge), must-revalidate" - Set-PodeHeader -Name 'Expires' -Value ([datetime]::UtcNow.AddSeconds($MaxAge).ToString('r', [CultureInfo]::InvariantCulture)) - } + # if the response stream isn't writable or already sent, return + $res = $WebEvent.Response + if (($null -eq $res) -or ($WebEvent.Streamed -and (($null -eq $res.OutputStream) -or !$res.OutputStream.CanWrite -or $res.Sent))) { + return + } - # specify the content-type if supplied (adding utf-8 if missing) - if (![string]::IsNullOrWhiteSpace($ContentType)) { - $charset = 'charset=utf-8' - if ($ContentType -inotcontains $charset) { - $ContentType = "$($ContentType); $($charset)" + # set a cache value + if ($Cache) { + Set-PodeHeader -Name 'Cache-Control' -Value "max-age=$($MaxAge), must-revalidate" + Set-PodeHeader -Name 'Expires' -Value ([datetime]::UtcNow.AddSeconds($MaxAge).ToString('r', [CultureInfo]::InvariantCulture)) } - $res.ContentType = $ContentType - } + # specify the content-type if supplied (adding utf-8 if missing) + if (![string]::IsNullOrWhiteSpace($ContentType)) { + $charset = 'charset=utf-8' + if ($ContentType -inotcontains $charset) { + $ContentType = "$($ContentType); $($charset)" + } - # if we're serverless, set the string as the body - if (!$WebEvent.Streamed) { - if ($isStringValue) { - $res.Body = $Value + $res.ContentType = $ContentType } - else { - $res.Body = $Bytes - } - } - else { - # convert string to bytes - if ($isStringValue) { - $Bytes = ConvertFrom-PodeValueToByteArray -Value $Value + # if we're serverless, set the string as the body + if (!$WebEvent.Streamed) { + if ($isStringValue) { + $res.Body = $Value + } + else { + $res.Body = $Bytes + } } - # check if we only need a range of the bytes - if (($null -ne $WebEvent.Ranges) -and ($WebEvent.Response.StatusCode -eq 200) -and ($StatusCode -eq 200)) { - $lengths = @() - $size = $Bytes.Length + else { + # convert string to bytes + if ($isStringValue) { + $Bytes = ConvertFrom-PodeValueToByteArray -Value $Value + } - $Bytes = @(foreach ($range in $WebEvent.Ranges) { - # ensure range not invalid - if (([int]$range.Start -lt 0) -or ([int]$range.Start -ge $size) -or ([int]$range.End -lt 0)) { - Set-PodeResponseStatus -Code 416 -NoErrorPage - return - } + # check if we only need a range of the bytes + if (($null -ne $WebEvent.Ranges) -and ($WebEvent.Response.StatusCode -eq 200) -and ($StatusCode -eq 200)) { + $lengths = @() + $size = $Bytes.Length - # skip start bytes only - if ([string]::IsNullOrWhiteSpace($range.End)) { - $Bytes[$range.Start..($size - 1)] - $lengths += "$($range.Start)-$($size - 1)/$($size)" - } + $Bytes = @(foreach ($range in $WebEvent.Ranges) { + # ensure range not invalid + if (([int]$range.Start -lt 0) -or ([int]$range.Start -ge $size) -or ([int]$range.End -lt 0)) { + Set-PodeResponseStatus -Code 416 -NoErrorPage + return + } - # end bytes only - elseif ([string]::IsNullOrWhiteSpace($range.Start)) { - if ([int]$range.End -gt $size) { - $range.End = $size + # skip start bytes only + if ([string]::IsNullOrWhiteSpace($range.End)) { + $Bytes[$range.Start..($size - 1)] + $lengths += "$($range.Start)-$($size - 1)/$($size)" } - if ([int]$range.End -gt 0) { - $Bytes[$($size - $range.End)..($size - 1)] - $lengths += "$($size - $range.End)-$($size - 1)/$($size)" + # end bytes only + elseif ([string]::IsNullOrWhiteSpace($range.Start)) { + if ([int]$range.End -gt $size) { + $range.End = $size + } + + if ([int]$range.End -gt 0) { + $Bytes[$($size - $range.End)..($size - 1)] + $lengths += "$($size - $range.End)-$($size - 1)/$($size)" + } + else { + $lengths += "0-0/$($size)" + } } + + # normal range else { - $lengths += "0-0/$($size)" - } - } + if ([int]$range.End -ge $size) { + Set-PodeResponseStatus -Code 416 -NoErrorPage + return + } - # normal range - else { - if ([int]$range.End -ge $size) { - Set-PodeResponseStatus -Code 416 -NoErrorPage - return + $Bytes[$range.Start..$range.End] + $lengths += "$($range.Start)-$($range.End)/$($size)" } + }) + + Set-PodeHeader -Name 'Content-Range' -Value "bytes $($lengths -join ', ')" + if ($StatusCode -eq 200) { + Set-PodeResponseStatus -Code 206 -NoErrorPage + } + } - $Bytes[$range.Start..$range.End] - $lengths += "$($range.Start)-$($range.End)/$($size)" + # check if we need to compress the response + if ($PodeContext.Server.Web.Compression.Enabled -and ![string]::IsNullOrWhiteSpace($WebEvent.AcceptEncoding)) { + try { + $ms = New-Object -TypeName System.IO.MemoryStream + $stream = New-Object "System.IO.Compression.$($WebEvent.AcceptEncoding)Stream"($ms, [System.IO.Compression.CompressionMode]::Compress, $true) + $stream.Write($Bytes, 0, $Bytes.Length) + $stream.Close() + $ms.Position = 0 + $Bytes = $ms.ToArray() + } + finally { + if ($null -ne $stream) { + $stream.Close() } - }) - Set-PodeHeader -Name 'Content-Range' -Value "bytes $($lengths -join ', ')" - if ($StatusCode -eq 200) { - Set-PodeResponseStatus -Code 206 -NoErrorPage + if ($null -ne $ms) { + $ms.Close() + } + } + + # set content encoding header + Set-PodeHeader -Name 'Content-Encoding' -Value $WebEvent.AcceptEncoding } - } - # check if we need to compress the response - if ($PodeContext.Server.Web.Compression.Enabled -and ![string]::IsNullOrWhiteSpace($WebEvent.AcceptEncoding)) { + # write the content to the response stream + $res.ContentLength64 = $Bytes.Length + try { $ms = New-Object -TypeName System.IO.MemoryStream - $stream = New-Object "System.IO.Compression.$($WebEvent.AcceptEncoding)Stream"($ms, [System.IO.Compression.CompressionMode]::Compress, $true) - $stream.Write($Bytes, 0, $Bytes.Length) - $stream.Close() - $ms.Position = 0 - $Bytes = $ms.ToArray() + $ms.Write($Bytes, 0, $Bytes.Length) + $ms.WriteTo($res.OutputStream) } - finally { - if ($null -ne $stream) { - $stream.Close() + catch { + if ((Test-PodeValidNetworkFailure $_.Exception)) { + return } + $_ | Write-PodeErrorLog + throw + } + finally { if ($null -ne $ms) { $ms.Close() } } - - # set content encoding header - Set-PodeHeader -Name 'Content-Encoding' -Value $WebEvent.AcceptEncoding - } - - # write the content to the response stream - $res.ContentLength64 = $Bytes.Length - - try { - $ms = New-Object -TypeName System.IO.MemoryStream - $ms.Write($Bytes, 0, $Bytes.Length) - $ms.WriteTo($res.OutputStream) - } - catch { - if ((Test-PodeValidNetworkFailure $_.Exception)) { - return - } - - $_ | Write-PodeErrorLog - throw - } - finally { - if ($null -ne $ms) { - $ms.Close() - } } } } @@ -344,7 +369,7 @@ Write-PodeFileResponse -Path 'C:/Files/' -FileBrowser function Write-PodeFileResponse { [CmdletBinding()] param ( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [ValidateNotNull()] [string] $Path, @@ -370,12 +395,24 @@ function Write-PodeFileResponse { [switch] $FileBrowser ) + begin { + $pipelineItemCount = 0 + } + + process { + $pipelineItemCount++ + } - # resolve for relative path - $RelativePath = Get-PodeRelativePath -Path $Path -JoinRoot + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # resolve for relative path + $RelativePath = Get-PodeRelativePath -Path $Path -JoinRoot - Write-PodeFileResponseInternal -Path $RelativePath -Data $Data -ContentType $ContentType -MaxAge $MaxAge ` - -StatusCode $StatusCode -Cache:$Cache -FileBrowser:$FileBrowser + Write-PodeFileResponseInternal -Path $RelativePath -Data $Data -ContentType $ContentType -MaxAge $MaxAge ` + -StatusCode $StatusCode -Cache:$Cache -FileBrowser:$FileBrowser + } } <# @@ -399,22 +436,35 @@ Generates and serves an HTML page that lists the contents of the './static' dire function Write-PodeDirectoryResponse { [CmdletBinding()] param ( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [ValidateNotNull()] [string] $Path ) + begin { + $pipelineItemCount = 0 + } - # resolve for relative path - $RelativePath = Get-PodeRelativePath -Path $Path -JoinRoot - - if (Test-Path -Path $RelativePath -PathType Container) { - Write-PodeDirectoryResponseInternal -Path $RelativePath + process { + $pipelineItemCount++ } - else { - Set-PodeResponseStatus -Code 404 + + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # resolve for relative path + $RelativePath = Get-PodeRelativePath -Path $Path -JoinRoot + + if (Test-Path -Path $RelativePath -PathType Container) { + Write-PodeDirectoryResponseInternal -Path $RelativePath + } + else { + Set-PodeResponseStatus -Code 404 + } } } + <# .SYNOPSIS Writes CSV data to the Response. @@ -621,29 +671,41 @@ function Write-PodeMarkdownResponse { [switch] $AsHtml ) + begin { + $pipelineItemCount = 0 + } + + process { + $pipelineItemCount++ + } - switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { - 'file' { - if (Test-PodePath $Path) { - $Value = Get-PodeFileContent -Path $Path + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { + 'file' { + if (Test-PodePath $Path) { + $Value = Get-PodeFileContent -Path $Path + } } } - } - if ([string]::IsNullOrWhiteSpace($Value)) { - $Value = [string]::Empty - } + if ([string]::IsNullOrWhiteSpace($Value)) { + $Value = [string]::Empty + } - $mimeType = 'text/markdown' + $mimeType = 'text/markdown' - if ($AsHtml) { - if ($PSVersionTable.PSVersion.Major -ge 7) { - $mimeType = 'text/html' - $Value = ($Value | ConvertFrom-Markdown).Html + if ($AsHtml) { + if ($PSVersionTable.PSVersion.Major -ge 7) { + $mimeType = 'text/html' + $Value = ($Value | ConvertFrom-Markdown).Html + } } - } - Write-PodeTextResponse -Value $Value -ContentType $mimeType -StatusCode $StatusCode + Write-PodeTextResponse -Value $Value -ContentType $mimeType -StatusCode $StatusCode + } } <# @@ -1003,7 +1065,7 @@ Write-PodeViewResponse -Path 'login' -FlashMessages function Write-PodeViewResponse { [CmdletBinding()] param ( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [string] $Path, @@ -1022,59 +1084,71 @@ function Write-PodeViewResponse { [switch] $FlashMessages ) - - # default data if null - if ($null -eq $Data) { - $Data = @{} + begin { + $pipelineItemCount = 0 } - # add path to data as "pagename" - unless key already exists - if (!$Data.ContainsKey('pagename')) { - $Data['pagename'] = $Path + process { + $pipelineItemCount++ } - # load all flash messages if needed - if ($FlashMessages -and ($null -ne $WebEvent.Session.Data.Flash)) { - $Data['flash'] = @{} + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # default data if null + if ($null -eq $Data) { + $Data = @{} + } - foreach ($name in (Get-PodeFlashMessageNames)) { - $Data.flash[$name] = (Get-PodeFlashMessage -Name $name) + # add path to data as "pagename" - unless key already exists + if (!$Data.ContainsKey('pagename')) { + $Data['pagename'] = $Path } - } - elseif ($null -eq $Data['flash']) { - $Data['flash'] = @{} - } - # add view engine extension - $ext = Get-PodeFileExtension -Path $Path - if ([string]::IsNullOrWhiteSpace($ext)) { - $Path += ".$($PodeContext.Server.ViewEngine.Extension)" - } + # load all flash messages if needed + if ($FlashMessages -and ($null -ne $WebEvent.Session.Data.Flash)) { + $Data['flash'] = @{} - # only look in the view directories - $viewFolder = $PodeContext.Server.InbuiltDrives['views'] - if (![string]::IsNullOrWhiteSpace($Folder)) { - $viewFolder = $PodeContext.Server.Views[$Folder] - } + foreach ($name in (Get-PodeFlashMessageNames)) { + $Data.flash[$name] = (Get-PodeFlashMessage -Name $name) + } + } + elseif ($null -eq $Data['flash']) { + $Data['flash'] = @{} + } - $Path = [System.IO.Path]::Combine($viewFolder, $Path) + # add view engine extension + $ext = Get-PodeFileExtension -Path $Path + if ([string]::IsNullOrWhiteSpace($ext)) { + $Path += ".$($PodeContext.Server.ViewEngine.Extension)" + } - # test the file path, and set status accordingly - if (!(Test-PodePath $Path)) { - return - } + # only look in the view directories + $viewFolder = $PodeContext.Server.InbuiltDrives['views'] + if (![string]::IsNullOrWhiteSpace($Folder)) { + $viewFolder = $PodeContext.Server.Views[$Folder] + } - # run any engine logic and render it - $engine = (Get-PodeViewEngineType -Path $Path) - $value = (Get-PodeFileContentUsingViewEngine -Path $Path -Data $Data) + $Path = [System.IO.Path]::Combine($viewFolder, $Path) - switch ($engine.ToLowerInvariant()) { - 'md' { - Write-PodeMarkdownResponse -Value $value -StatusCode $StatusCode -AsHtml + # test the file path, and set status accordingly + if (!(Test-PodePath $Path)) { + return } - default { - Write-PodeHtmlResponse -Value $value -StatusCode $StatusCode + # run any engine logic and render it + $engine = (Get-PodeViewEngineType -Path $Path) + $value = (Get-PodeFileContentUsingViewEngine -Path $Path -Data $Data) + + switch ($engine.ToLowerInvariant()) { + 'md' { + Write-PodeMarkdownResponse -Value $value -StatusCode $StatusCode -AsHtml + } + + default { + Write-PodeHtmlResponse -Value $value -StatusCode $StatusCode + } } } } @@ -1293,8 +1367,23 @@ function Write-PodeTcpClient { [string] $Message ) + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() + } + + process { + # Add the current piped-in value to the array + $pipelineValue += $_ + } - $TcpEvent.Response.WriteLine($Message, $true) + end { + # Set Route to the array of values + if ($pipelineValue.Count -gt 1) { + $Message = $pipelineValue -join "`n" + } + $TcpEvent.Response.WriteLine($Message, $true) + } } <# @@ -1581,7 +1670,7 @@ function Use-PodePartialView { [CmdletBinding()] [OutputType([string])] param ( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string] $Path, @@ -1592,33 +1681,45 @@ function Use-PodePartialView { [string] $Folder ) - - # default data if null - if ($null -eq $Data) { - $Data = @{} - } - # add view engine extension - $ext = Get-PodeFileExtension -Path $Path - if ([string]::IsNullOrWhiteSpace($ext)) { - $Path += ".$($PodeContext.Server.ViewEngine.Extension)" + begin { + $pipelineItemCount = 0 } - # only look in the view directory - $viewFolder = $PodeContext.Server.InbuiltDrives['views'] - if (![string]::IsNullOrWhiteSpace($Folder)) { - $viewFolder = $PodeContext.Server.Views[$Folder] + process { + $pipelineItemCount++ } - $Path = [System.IO.Path]::Combine($viewFolder, $Path) + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # default data if null + if ($null -eq $Data) { + $Data = @{} + } + # add view engine extension + $ext = Get-PodeFileExtension -Path $Path + if ([string]::IsNullOrWhiteSpace($ext)) { + $Path += ".$($PodeContext.Server.ViewEngine.Extension)" + } - # test the file path, and set status accordingly - if (!(Test-PodePath $Path -NoStatus)) { - # The Views path does not exist - throw ($PodeLocale.viewsPathDoesNotExistExceptionMessage -f $Path) - } + # only look in the view directory + $viewFolder = $PodeContext.Server.InbuiltDrives['views'] + if (![string]::IsNullOrWhiteSpace($Folder)) { + $viewFolder = $PodeContext.Server.Views[$Folder] + } - # run any engine logic - return (Get-PodeFileContentUsingViewEngine -Path $Path -Data $Data) + $Path = [System.IO.Path]::Combine($viewFolder, $Path) + + # test the file path, and set status accordingly + if (!(Test-PodePath $Path -NoStatus)) { + # The Views path does not exist + throw ($PodeLocale.viewsPathDoesNotExistExceptionMessage -f $Path) + } + + # run any engine logic + return (Get-PodeFileContentUsingViewEngine -Path $Path -Data $Data) + } } <# @@ -1655,7 +1756,7 @@ Send-PodeSignal -Value @{ Data = @(123, 100, 101) } -Path '/response-charts' function Send-PodeSignal { [CmdletBinding()] param( - [Parameter(ValueFromPipeline = $true)] + [Parameter(ValueFromPipeline = $true, Position = 0 )] $Value, [Parameter()] @@ -1678,48 +1779,61 @@ function Send-PodeSignal { [switch] $IgnoreEvent ) - # error if not configured - if (!$PodeContext.Server.Signals.Enabled) { - # WebSockets have not been configured to send signal messages - throw ($PodeLocale.websocketsNotConfiguredForSignalMessagesExceptionMessage) + begin { + $pipelineItemCount = 0 } - # do nothing if no value - if (($null -eq $Value) -or ([string]::IsNullOrEmpty($Value))) { - return + process { + $pipelineItemCount++ } - # jsonify the value - if ($Value -isnot [string]) { - if ($Depth -le 0) { - $Value = (ConvertTo-Json -InputObject $Value -Compress) + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) } - else { - $Value = (ConvertTo-Json -InputObject $Value -Depth $Depth -Compress) + # error if not configured + if (!$PodeContext.Server.Signals.Enabled) { + # WebSockets have not been configured to send signal messages + throw ($PodeLocale.websocketsNotConfiguredForSignalMessagesExceptionMessage) } - } - # check signal event - if (!$IgnoreEvent -and ($null -ne $SignalEvent)) { - if ([string]::IsNullOrWhiteSpace($Path)) { - $Path = $SignalEvent.Data.Path + # do nothing if no value + if (($null -eq $Value) -or ([string]::IsNullOrEmpty($Value))) { + return } - if ([string]::IsNullOrWhiteSpace($ClientId)) { - $ClientId = $SignalEvent.Data.ClientId + # jsonify the value + if ($Value -isnot [string]) { + if ($Depth -le 0) { + $Value = (ConvertTo-Json -InputObject $Value -Compress) + } + else { + $Value = (ConvertTo-Json -InputObject $Value -Depth $Depth -Compress) + } } - if (($Mode -ieq 'Auto') -and ($SignalEvent.Data.Direct -or ($SignalEvent.ClientId -ieq $SignalEvent.Data.ClientId))) { - $Mode = 'Direct' + # check signal event + if (!$IgnoreEvent -and ($null -ne $SignalEvent)) { + if ([string]::IsNullOrWhiteSpace($Path)) { + $Path = $SignalEvent.Data.Path + } + + if ([string]::IsNullOrWhiteSpace($ClientId)) { + $ClientId = $SignalEvent.Data.ClientId + } + + if (($Mode -ieq 'Auto') -and ($SignalEvent.Data.Direct -or ($SignalEvent.ClientId -ieq $SignalEvent.Data.ClientId))) { + $Mode = 'Direct' + } } - } - # broadcast or direct? - if ($Mode -iin @('Auto', 'Broadcast')) { - $PodeContext.Server.Signals.Listener.AddServerSignal($Value, $Path, $ClientId) - } - else { - $SignalEvent.Response.Write($Value) + # broadcast or direct? + if ($Mode -iin @('Auto', 'Broadcast')) { + $PodeContext.Server.Signals.Listener.AddServerSignal($Value, $Path, $ClientId) + } + else { + $SignalEvent.Response.Write($Value) + } } } diff --git a/src/Public/Routes.ps1 b/src/Public/Routes.ps1 index ffed8e91f..34246c3d4 100644 --- a/src/Public/Routes.ps1 +++ b/src/Public/Routes.ps1 @@ -1949,7 +1949,7 @@ ConvertTo-PodeRoute -Commands @('Invoke-Pester') -Module Pester function ConvertTo-PodeRoute { [CmdletBinding()] param( - [Parameter(ValueFromPipeline = $true)] + [Parameter(ValueFromPipeline = $true, Position = 0 )] [string[]] $Commands, @@ -2004,131 +2004,147 @@ function ConvertTo-PodeRoute { [switch] $NoOpenApi ) - - # if a module was supplied, import it - then validate the commands - if (![string]::IsNullOrWhiteSpace($Module)) { - Import-PodeModule -Name $Module - - Write-Verbose 'Getting exported commands from module' - $ModuleCommands = (Get-Module -Name $Module | Sort-Object -Descending | Select-Object -First 1).ExportedCommands.Keys - - # if commands were supplied validate them - otherwise use all exported ones - if (Test-PodeIsEmpty $Commands) { - Write-Verbose "Using all commands in $($Module) for converting to routes" - $Commands = $ModuleCommands - } - else { - Write-Verbose "Validating supplied commands against module's exported commands" - foreach ($cmd in $Commands) { - if ($ModuleCommands -inotcontains $cmd) { - # Module Module does not contain function cmd to convert to a Route - throw ($PodeLocale.moduleDoesNotContainFunctionExceptionMessage -f $Module, $cmd) - } - } - } + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() } - # if there are no commands, fail - if (Test-PodeIsEmpty $Commands) { - # No commands supplied to convert to Routes - throw ($PodeLocale.noCommandsSuppliedToConvertToRoutesExceptionMessage) + process { + # Add the current piped-in value to the array + $pipelineValue += $_ } - # trim end trailing slashes from the path - $Path = Protect-PodeValue -Value $Path -Default '/' - $Path = $Path.TrimEnd('/') + end { + # Set InputObject to the array of values + if ($pipelineValue.Count -gt 1) { + $Commands = $pipelineValue + } - # create the routes for each of the commands - foreach ($cmd in $Commands) { - # get module verb/noun and comvert verb to HTTP method - $split = ($cmd -split '\-') + # if a module was supplied, import it - then validate the commands + if (![string]::IsNullOrWhiteSpace($Module)) { + Import-PodeModule -Name $Module - if ($split.Length -ge 2) { - $verb = $split[0] - $noun = $split[1..($split.Length - 1)] -join ([string]::Empty) - } - else { - $verb = [string]::Empty - $noun = $split[0] - } + Write-Verbose 'Getting exported commands from module' + $ModuleCommands = (Get-Module -Name $Module | Sort-Object -Descending | Select-Object -First 1).ExportedCommands.Keys - # determine the http method, or use the one passed - $_method = $Method - if ([string]::IsNullOrWhiteSpace($_method)) { - $_method = Convert-PodeFunctionVerbToHttpMethod -Verb $verb + # if commands were supplied validate them - otherwise use all exported ones + if (Test-PodeIsEmpty $Commands) { + Write-Verbose "Using all commands in $($Module) for converting to routes" + $Commands = $ModuleCommands + } + else { + Write-Verbose "Validating supplied commands against module's exported commands" + foreach ($cmd in $Commands) { + if ($ModuleCommands -inotcontains $cmd) { + # Module Module does not contain function cmd to convert to a Route + throw ($PodeLocale.moduleDoesNotContainFunctionExceptionMessage -f $Module, $cmd) + } + } + } } - # use the full function name, or remove the verb - $name = $cmd - if ($NoVerb) { - $name = $noun + # if there are no commands, fail + if (Test-PodeIsEmpty $Commands) { + # No commands supplied to convert to Routes + throw ($PodeLocale.noCommandsSuppliedToConvertToRoutesExceptionMessage) } - # build the route's path - $_path = ("$($Path)/$($Module)/$($name)" -replace '[/]+', '/') - - # create the route - $params = @{ - Method = $_method - Path = $_path - Middleware = $Middleware - Authentication = $Authentication - Access = $Access - Role = $Role - Group = $Group - Scope = $Scope - User = $User - AllowAnon = $AllowAnon - ArgumentList = $cmd - PassThru = $true - } + # trim end trailing slashes from the path + $Path = Protect-PodeValue -Value $Path -Default '/' + $Path = $Path.TrimEnd('/') - $route = Add-PodeRoute @params -ScriptBlock { - param($cmd) + # create the routes for each of the commands + foreach ($cmd in $Commands) { + # get module verb/noun and comvert verb to HTTP method + $split = ($cmd -split '\-') - # either get params from the QueryString or Payload - if ($WebEvent.Method -ieq 'get') { - $parameters = $WebEvent.Query + if ($split.Length -ge 2) { + $verb = $split[0] + $noun = $split[1..($split.Length - 1)] -join ([string]::Empty) } else { - $parameters = $WebEvent.Data + $verb = [string]::Empty + $noun = $split[0] } - # invoke the function - $result = (. $cmd @parameters) + # determine the http method, or use the one passed + $_method = $Method + if ([string]::IsNullOrWhiteSpace($_method)) { + $_method = Convert-PodeFunctionVerbToHttpMethod -Verb $verb + } - # if we have a result, convert it to json - if (!(Test-PodeIsEmpty $result)) { - Write-PodeJsonResponse -Value $result -Depth 1 + # use the full function name, or remove the verb + $name = $cmd + if ($NoVerb) { + $name = $noun } - } - # set the openapi metadata of the function, unless told to skip - if ($NoOpenApi) { - continue - } + # build the route's path + $_path = ("$($Path)/$($Module)/$($name)" -replace '[/]+', '/') + + # create the route + $params = @{ + Method = $_method + Path = $_path + Middleware = $Middleware + Authentication = $Authentication + Access = $Access + Role = $Role + Group = $Group + Scope = $Scope + User = $User + AllowAnon = $AllowAnon + ArgumentList = $cmd + PassThru = $true + } - $help = Get-Help -Name $cmd - $route = ($route | Set-PodeOARouteInfo -Summary $help.Synopsis -Tags $Module -PassThru) + $route = Add-PodeRoute @params -ScriptBlock { + param($cmd) - # set the routes parameters (get = query, everything else = payload) - $params = (Get-Command -Name $cmd).Parameters - if (($null -eq $params) -or ($params.Count -eq 0)) { - continue - } + # either get params from the QueryString or Payload + if ($WebEvent.Method -ieq 'get') { + $parameters = $WebEvent.Query + } + else { + $parameters = $WebEvent.Data + } - $props = @(foreach ($key in $params.Keys) { - $params[$key] | ConvertTo-PodeOAPropertyFromCmdletParameter - }) + # invoke the function + $result = (. $cmd @parameters) - if ($_method -ieq 'get') { - $route | Set-PodeOARequest -Parameters @(foreach ($prop in $props) { $prop | ConvertTo-PodeOAParameter -In Query }) - } + # if we have a result, convert it to json + if (!(Test-PodeIsEmpty $result)) { + Write-PodeJsonResponse -Value $result -Depth 1 + } + } + + # set the openapi metadata of the function, unless told to skip + if ($NoOpenApi) { + continue + } + + $help = Get-Help -Name $cmd + $route = ($route | Set-PodeOARouteInfo -Summary $help.Synopsis -Tags $Module -PassThru) + + # set the routes parameters (get = query, everything else = payload) + $params = (Get-Command -Name $cmd).Parameters + if (($null -eq $params) -or ($params.Count -eq 0)) { + continue + } - else { - $route | Set-PodeOARequest -RequestBody ( - New-PodeOARequestBody -ContentSchemas @{ 'application/json' = (New-PodeOAObjectProperty -Array -Properties $props) } - ) + $props = @(foreach ($key in $params.Keys) { + $params[$key] | ConvertTo-PodeOAPropertyFromCmdletParameter + }) + + if ($_method -ieq 'get') { + $route | Set-PodeOARequest -Parameters @(foreach ($prop in $props) { $prop | ConvertTo-PodeOAParameter -In Query }) + } + + else { + $route | Set-PodeOARequest -RequestBody ( + New-PodeOARequestBody -ContentSchemas @{ 'application/json' = (New-PodeOAObjectProperty -Array -Properties $props) } + ) + } } } } diff --git a/src/Public/Secrets.ps1 b/src/Public/Secrets.ps1 index ac87f3fa3..80d857842 100644 --- a/src/Public/Secrets.ps1 +++ b/src/Public/Secrets.ps1 @@ -660,7 +660,7 @@ function Update-PodeSecret { $Name, #> byte[], string, securestring, pscredential, hashtable - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true )] [object] $InputObject, @@ -668,42 +668,57 @@ function Update-PodeSecret { [hashtable] $Metadata ) + begin { + # has the secret been mounted? + if (!(Test-PodeSecret -Name $Name)) { + # No Secret named has been mounted + throw ($PodeLocale.noSecretNamedMountedExceptionMessage -f $Name) + } + # Initialize an array to hold piped-in values + $pipelineValue = @() + } - # has the secret been mounted? - if (!(Test-PodeSecret -Name $Name)) { - # No Secret named has been mounted - throw ($PodeLocale.noSecretNamedMountedExceptionMessage -f $Name) + process { + # Add the current piped-in value to the array + $pipelineValue += $_ } - # make sure the value type is correct - $InputObject = Protect-PodeSecretValueType -Value $InputObject + end { + # Set InputObject to the array of values + if ($pipelineValue.Count -gt 1) { + $InputObject = $pipelineValue + } - # get the secret and vault - $secret = $PodeContext.Server.Secrets.Keys[$Name] + # make sure the value type is correct + $InputObject = Protect-PodeSecretValueType -Value $InputObject - # reset the cache if enabled - if ($secret.Cache.Enabled) { - $secret.Cache.Value = $InputObject - $secret.Cache.Expiry = [datetime]::UtcNow.AddMinutes($secret.Cache.Ttl) - } + # get the secret and vault + $secret = $PodeContext.Server.Secrets.Keys[$Name] - # if we're expanding a property, convert this to a hashtable - if ($secret.Properties.Enabled -and $secret.Properties.Expand) { - $InputObject = @{ - "$($secret.Properties.Fields)" = $InputObject + # reset the cache if enabled + if ($secret.Cache.Enabled) { + $secret.Cache.Value = $InputObject + $secret.Cache.Expiry = [datetime]::UtcNow.AddMinutes($secret.Cache.Ttl) } - } - # set the secret depending on vault type - $vault = $PodeContext.Server.Secrets.Vaults[$secret.Vault] - Lock-PodeObject -Name $vault.LockableName -ScriptBlock { - switch ($vault.Type) { - 'custom' { - Set-PodeSecretCustomKey -Vault $secret.Vault -Key $secret.Key -Value $InputObject -Metadata $Metadata -ArgumentList $secret.Arguments + # if we're expanding a property, convert this to a hashtable + if ($secret.Properties.Enabled -and $secret.Properties.Expand) { + $InputObject = @{ + "$($secret.Properties.Fields)" = $InputObject } + } - 'secretmanagement' { - Set-PodeSecretManagementKey -Vault $secret.Vault -Key $secret.Key -Value $InputObject -Metadata $Metadata + # set the secret depending on vault type + $vault = $PodeContext.Server.Secrets.Vaults[$secret.Vault] + Lock-PodeObject -Name $vault.LockableName -ScriptBlock { + switch ($vault.Type) { + 'custom' { + Set-PodeSecretCustomKey -Vault $secret.Vault -Key $secret.Key -Value $InputObject -Metadata $Metadata -ArgumentList $secret.Arguments + } + + 'secretmanagement' { + Set-PodeSecretManagementKey -Vault $secret.Vault -Key $secret.Key -Value $InputObject -Metadata $Metadata + } } } } @@ -890,7 +905,7 @@ function Set-PodeSecret { $Vault, #> byte[], string, securestring, pscredential, hashtable - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [object] $InputObject, @@ -902,26 +917,41 @@ function Set-PodeSecret { [object[]] $ArgumentList ) + begin { + # has the vault been registered? + if (!(Test-PodeSecretVault -Name $Vault)) { + # No Secret Vault with the name has been registered + throw ($PodeLocale.noSecretVaultRegisteredExceptionMessage -f $Vault) + } + # Initialize an array to hold piped-in values + $pipelineValue = @() + } - # has the vault been registered? - if (!(Test-PodeSecretVault -Name $Vault)) { - # No Secret Vault with the name has been registered - throw ($PodeLocale.noSecretVaultRegisteredExceptionMessage -f $Vault) + process { + # Add the current piped-in value to the array + $pipelineValue += $_ } - # make sure the value type is correct - $InputObject = Protect-PodeSecretValueType -Value $InputObject + end { + # Set InputObject to the array of values + if ($pipelineValue.Count -gt 1) { + $InputObject = $pipelineValue + } - # set the secret depending on vault type - $_vault = $PodeContext.Server.Secrets.Vaults[$Vault] - Lock-PodeObject -Name $_vault.LockableName -ScriptBlock { - switch ($_vault.Type) { - 'custom' { - Set-PodeSecretCustomKey -Vault $Vault -Key $Key -Value $InputObject -Metadata $Metadata -ArgumentList $ArgumentList - } + # make sure the value type is correct + $InputObject = Protect-PodeSecretValueType -Value $InputObject - 'secretmanagement' { - Set-PodeSecretManagementKey -Vault $Vault -Key $Key -Value $InputObject -Metadata $Metadata + # set the secret depending on vault type + $_vault = $PodeContext.Server.Secrets.Vaults[$Vault] + Lock-PodeObject -Name $_vault.LockableName -ScriptBlock { + switch ($_vault.Type) { + 'custom' { + Set-PodeSecretCustomKey -Vault $Vault -Key $Key -Value $InputObject -Metadata $Metadata -ArgumentList $ArgumentList + } + + 'secretmanagement' { + Set-PodeSecretManagementKey -Vault $Vault -Key $Key -Value $InputObject -Metadata $Metadata + } } } } diff --git a/src/Public/State.ps1 b/src/Public/State.ps1 index 3ca7face2..282eaf1eb 100644 --- a/src/Public/State.ps1 +++ b/src/Public/State.ps1 @@ -28,7 +28,7 @@ function Set-PodeState { [string] $Name, - [Parameter(ValueFromPipeline = $true)] + [Parameter(ValueFromPipeline = $true, Position = 0)] [object] $Value, @@ -37,21 +37,38 @@ function Set-PodeState { $Scope ) - if ($null -eq $PodeContext.Server.State) { - # Pode has not been initialized - throw ($PodeLocale.podeNotInitializedExceptionMessage) - } + begin { + if ($null -eq $PodeContext.Server.State) { + # Pode has not been initialized + throw ($PodeLocale.podeNotInitializedExceptionMessage) + } - if ($null -eq $Scope) { - $Scope = @() + if ($null -eq $Scope) { + $Scope = @() + } + + # Initialize an array to hold piped-in values + $pipelineValue = @() } - $PodeContext.Server.State[$Name] = @{ - Value = $Value - Scope = $Scope + process { + # Add the current piped-in value to the array + $pipelineValue += $_ } - return $Value + end { + # Set Value to the array of values + if ($pipelineValue.Count -gt 1) { + $Value = $pipelineValue + } + + $PodeContext.Server.State[$Name] = @{ + Value = $Value + Scope = $Scope + } + + return $Value + } } <# @@ -426,4 +443,4 @@ function Test-PodeState { } return $PodeContext.Server.State.ContainsKey($Name) -} +} \ No newline at end of file diff --git a/src/Public/Tasks.ps1 b/src/Public/Tasks.ps1 index 0f46cbded..57cc041fd 100644 --- a/src/Public/Tasks.ps1 +++ b/src/Public/Tasks.ps1 @@ -143,7 +143,7 @@ Invoke-PodeTask -Name 'Example1' | Wait-PodeTask -Timeout 3 function Invoke-PodeTask { [CmdletBinding()] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [string] $Name, @@ -158,23 +158,24 @@ function Invoke-PodeTask { [switch] $Wait ) - - # ensure the task exists - if (!$PodeContext.Tasks.Items.ContainsKey($Name)) { - # Task does not exist - throw ($PodeLocale.taskDoesNotExistExceptionMessage -f $Name) - } - - # run task logic - $task = Invoke-PodeInternalTask -Task $PodeContext.Tasks.Items[$Name] -ArgumentList $ArgumentList -Timeout $Timeout - - # wait, and return result? - if ($Wait) { - return (Wait-PodeTask -Task $task -Timeout $Timeout) + process { + # ensure the task exists + if (!$PodeContext.Tasks.Items.ContainsKey($Name)) { + # Task does not exist + throw ($PodeLocale.taskDoesNotExistExceptionMessage -f $Name) + } + + # run task logic + $task = Invoke-PodeInternalTask -Task $PodeContext.Tasks.Items[$Name] -ArgumentList $ArgumentList -Timeout $Timeout + + # wait, and return result? + if ($Wait) { + return (Wait-PodeTask -Task $task -Timeout $Timeout) + } + + # return task + return $task } - - # return task - return $task } <# @@ -193,12 +194,13 @@ Remove-PodeTask -Name 'Example1' function Remove-PodeTask { [CmdletBinding()] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [string] $Name ) - - $null = $PodeContext.Tasks.Items.Remove($Name) + process { + $null = $PodeContext.Tasks.Items.Remove($Name) + } } <# @@ -240,7 +242,7 @@ Edit-PodeTask -Name 'Example1' -ScriptBlock { Invoke-SomeNewLogic } function Edit-PodeTask { [CmdletBinding()] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [string] $Name, @@ -252,25 +254,26 @@ function Edit-PodeTask { [hashtable] $ArgumentList ) - - # ensure the task exists - if (!$PodeContext.Tasks.Items.ContainsKey($Name)) { - # Task does not exist - throw ($PodeLocale.taskDoesNotExistExceptionMessage -f $Name) - } - - $_task = $PodeContext.Tasks.Items[$Name] - - # edit scriptblock if supplied - if (!(Test-PodeIsEmpty $ScriptBlock)) { - $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState - $_task.Script = $ScriptBlock - $_task.UsingVariables = $usingVars - } - - # edit arguments if supplied - if (!(Test-PodeIsEmpty $ArgumentList)) { - $_task.Arguments = $ArgumentList + process { + # ensure the task exists + if (!$PodeContext.Tasks.Items.ContainsKey($Name)) { + # Task does not exist + throw ($PodeLocale.taskDoesNotExistExceptionMessage -f $Name) + } + + $_task = $PodeContext.Tasks.Items[$Name] + + # edit scriptblock if supplied + if (!(Test-PodeIsEmpty $ScriptBlock)) { + $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState + $_task.Script = $ScriptBlock + $_task.UsingVariables = $usingVars + } + + # edit arguments if supplied + if (!(Test-PodeIsEmpty $ArgumentList)) { + $_task.Arguments = $ArgumentList + } } } @@ -360,12 +363,13 @@ Invoke-PodeTask -Name 'Example1' | Close-PodeTask function Close-PodeTask { [CmdletBinding()] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [hashtable] $Task ) - - Close-PodeTaskInternal -Result $Task + process { + Close-PodeTaskInternal -Result $Task + } } <# @@ -385,12 +389,13 @@ function Test-PodeTaskCompleted { [CmdletBinding()] [OutputType([bool])] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [hashtable] $Task ) - - return [bool]$Task.Runspace.Handler.IsCompleted + process { + return [bool]$Task.Runspace.Handler.IsCompleted + } } <# @@ -416,22 +421,34 @@ function Wait-PodeTask { [CmdletBinding()] [OutputType([object])] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] $Task, [Parameter()] [int] $Timeout = -1 ) - - if ($Task -is [System.Threading.Tasks.Task]) { - return (Wait-PodeNetTaskInternal -Task $Task -Timeout $Timeout) + begin { + $pipelineItemCount = 0 } - if ($Task -is [hashtable]) { - return (Wait-PodeTaskInternal -Task $Task -Timeout $Timeout) + process { + $pipelineItemCount++ } - # Task type is invalid, expected either [System.Threading.Tasks.Task] or [hashtable] - throw ($PodeLocale.invalidTaskTypeExceptionMessage) + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + if ($Task -is [System.Threading.Tasks.Task]) { + return (Wait-PodeNetTaskInternal -Task $Task -Timeout $Timeout) + } + + if ($Task -is [hashtable]) { + return (Wait-PodeTaskInternal -Task $Task -Timeout $Timeout) + } + + # Task type is invalid, expected either [System.Threading.Tasks.Task] or [hashtable] + throw ($PodeLocale.invalidTaskTypeExceptionMessage) + } } \ No newline at end of file diff --git a/src/Public/Threading.ps1 b/src/Public/Threading.ps1 index 0438773f5..b3461bc74 100644 --- a/src/Public/Threading.ps1 +++ b/src/Public/Threading.ps1 @@ -39,7 +39,7 @@ function Lock-PodeObject { [CmdletBinding(DefaultParameterSetName = 'Object')] [OutputType([object])] param( - [Parameter(ValueFromPipeline = $true, ParameterSetName = 'Object')] + [Parameter(ValueFromPipeline = $true, Position = 0, ParameterSetName = 'Object')] [object] $Object, @@ -61,29 +61,41 @@ function Lock-PodeObject { [switch] $CheckGlobal ) + begin { + $pipelineItemCount = 0 + } - try { - if ([string]::IsNullOrEmpty($Name)) { - Enter-PodeLockable -Object $Object -Timeout $Timeout -CheckGlobal:$CheckGlobal - } - else { - Enter-PodeLockable -Name $Name -Timeout $Timeout -CheckGlobal:$CheckGlobal - } + process { + $pipelineItemCount++ + } - if ($null -ne $ScriptBlock) { - Invoke-PodeScriptBlock -ScriptBlock $ScriptBlock -NoNewClosure -Return:$Return + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) } - } - catch { - $_ | Write-PodeErrorLog - throw $_.Exception - } - finally { - if ([string]::IsNullOrEmpty($Name)) { - Exit-PodeLockable -Object $Object + try { + if ([string]::IsNullOrEmpty($Name)) { + Enter-PodeLockable -Object $Object -Timeout $Timeout -CheckGlobal:$CheckGlobal + } + else { + Enter-PodeLockable -Name $Name -Timeout $Timeout -CheckGlobal:$CheckGlobal + } + + if ($null -ne $ScriptBlock) { + Invoke-PodeScriptBlock -ScriptBlock $ScriptBlock -NoNewClosure -Return:$Return + } + } + catch { + $_ | Write-PodeErrorLog + throw $_.Exception } - else { - Exit-PodeLockable -Name $Name + finally { + if ([string]::IsNullOrEmpty($Name)) { + Exit-PodeLockable -Object $Object + } + else { + Exit-PodeLockable -Name $Name + } } } } @@ -218,7 +230,7 @@ Enter-PodeLockable -Name 'LockName' -Timeout 5000 function Enter-PodeLockable { [CmdletBinding(DefaultParameterSetName = 'Object')] param( - [Parameter(ValueFromPipeline = $true, ParameterSetName = 'Object')] + [Parameter(ValueFromPipeline = $true, Position = 0, ParameterSetName = 'Object')] [object] $Object, @@ -233,40 +245,52 @@ function Enter-PodeLockable { [switch] $CheckGlobal ) - - # get object by name if set - if (![string]::IsNullOrEmpty($Name)) { - $Object = Get-PodeLockable -Name $Name + begin { + $pipelineItemCount = 0 } - # if object is null, default to global - if ($null -eq $Object) { - $Object = $PodeContext.Threading.Lockables.Global + process { + $pipelineItemCount++ } - # check if value type and throw - if ($Object -is [valuetype]) { - # Cannot lock a [ValueType] - throw ($PodeLocale.cannotLockValueTypeExceptionMessage) - } + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # get object by name if set + if (![string]::IsNullOrEmpty($Name)) { + $Object = Get-PodeLockable -Name $Name + } - # check if null and throw - if ($null -eq $Object) { - # Cannot lock an object that is null - throw ($PodeLocale.cannotLockNullObjectExceptionMessage) - } + # if object is null, default to global + if ($null -eq $Object) { + $Object = $PodeContext.Threading.Lockables.Global + } - # check if the global lockable is locked - if ($CheckGlobal) { - Lock-PodeObject -Object $PodeContext.Threading.Lockables.Global -ScriptBlock {} -Timeout $Timeout - } + # check if value type and throw + if ($Object -is [valuetype]) { + # Cannot lock a [ValueType] + throw ($PodeLocale.cannotLockValueTypeExceptionMessage) + } - # attempt to acquire lock - $locked = $false - [System.Threading.Monitor]::TryEnter($Object.SyncRoot, $Timeout, [ref]$locked) - if (!$locked) { - # Failed to acquire a lock on the object - throw ($PodeLocale.failedToAcquireLockExceptionMessage) + # check if null and throw + if ($null -eq $Object) { + # Cannot lock an object that is null + throw ($PodeLocale.cannotLockNullObjectExceptionMessage) + } + + # check if the global lockable is locked + if ($CheckGlobal) { + Lock-PodeObject -Object $PodeContext.Threading.Lockables.Global -ScriptBlock {} -Timeout $Timeout + } + + # attempt to acquire lock + $locked = $false + [System.Threading.Monitor]::TryEnter($Object.SyncRoot, $Timeout, [ref]$locked) + if (!$locked) { + # Failed to acquire a lock on the object + throw ($PodeLocale.failedToAcquireLockExceptionMessage) + } } } @@ -292,7 +316,7 @@ Exit-PodeLockable -Name 'LockName' function Exit-PodeLockable { [CmdletBinding(DefaultParameterSetName = 'Object')] param( - [Parameter(ValueFromPipeline = $true, ParameterSetName = 'Object')] + [Parameter(ValueFromPipeline = $true, Position = 0, ParameterSetName = 'Object')] [object] $Object, @@ -300,32 +324,44 @@ function Exit-PodeLockable { [string] $Name ) - - # get object by name if set - if (![string]::IsNullOrEmpty($Name)) { - $Object = Get-PodeLockable -Name $Name + begin { + $pipelineItemCount = 0 } - # if object is null, default to global - if ($null -eq $Object) { - $Object = $PodeContext.Threading.Lockables.Global + process { + $pipelineItemCount++ } - # check if value type and throw - if ($Object -is [valuetype]) { - # Cannot unlock a [ValueType] - throw ($PodeLocale.cannotUnlockValueTypeExceptionMessage) - } + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # get object by name if set + if (![string]::IsNullOrEmpty($Name)) { + $Object = Get-PodeLockable -Name $Name + } - # check if null and throw - if ($null -eq $Object) { - # Cannot unlock an object that is null - throw ($PodeLocale.cannotUnlockNullObjectExceptionMessage) - } + # if object is null, default to global + if ($null -eq $Object) { + $Object = $PodeContext.Threading.Lockables.Global + } - if ([System.Threading.Monitor]::IsEntered($Object.SyncRoot)) { - [System.Threading.Monitor]::Pulse($Object.SyncRoot) - [System.Threading.Monitor]::Exit($Object.SyncRoot) + # check if value type and throw + if ($Object -is [valuetype]) { + # Cannot unlock a [ValueType] + throw ($PodeLocale.cannotUnlockValueTypeExceptionMessage) + } + + # check if null and throw + if ($null -eq $Object) { + # Cannot unlock an object that is null + throw ($PodeLocale.cannotUnlockNullObjectExceptionMessage) + } + + if ([System.Threading.Monitor]::IsEntered($Object.SyncRoot)) { + [System.Threading.Monitor]::Pulse($Object.SyncRoot) + [System.Threading.Monitor]::Exit($Object.SyncRoot) + } } } diff --git a/src/Public/Timers.ps1 b/src/Public/Timers.ps1 index 8042bca71..693fcec94 100644 --- a/src/Public/Timers.ps1 +++ b/src/Public/Timers.ps1 @@ -155,7 +155,7 @@ Invoke-PodeTimer -Name 'timer-name' function Invoke-PodeTimer { [CmdletBinding()] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [string] $Name, @@ -163,15 +163,16 @@ function Invoke-PodeTimer { [object[]] $ArgumentList = $null ) - - # ensure the timer exists - if (!$PodeContext.Timers.Items.ContainsKey($Name)) { - # Timer 'Name' does not exist - throw ($PodeLocale.timerDoesNotExistExceptionMessage -f $Name) + process { + # ensure the timer exists + if (!$PodeContext.Timers.Items.ContainsKey($Name)) { + # Timer 'Name' does not exist + throw ($PodeLocale.timerDoesNotExistExceptionMessage -f $Name) + } + + # run timer logic + Invoke-PodeInternalTimer -Timer $PodeContext.Timers.Items[$Name] -ArgumentList $ArgumentList } - - # run timer logic - Invoke-PodeInternalTimer -Timer $PodeContext.Timers.Items[$Name] -ArgumentList $ArgumentList } <# @@ -190,12 +191,13 @@ Remove-PodeTimer -Name 'SaveState' function Remove-PodeTimer { [CmdletBinding()] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [string] $Name ) - - $null = $PodeContext.Timers.Items.Remove($Name) + process { + $null = $PodeContext.Timers.Items.Remove($Name) + } } <# @@ -240,7 +242,7 @@ Edit-PodeTimer -Name 'Hello' -Interval 10 function Edit-PodeTimer { [CmdletBinding()] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [string] $Name, @@ -256,30 +258,31 @@ function Edit-PodeTimer { [object[]] $ArgumentList ) - - # ensure the timer exists - if (!$PodeContext.Timers.Items.ContainsKey($Name)) { - # Timer 'Name' does not exist - throw ($PodeLocale.timerDoesNotExistExceptionMessage -f $Name) - } - - $_timer = $PodeContext.Timers.Items[$Name] - - # edit interval if supplied - if ($Interval -gt 0) { - $_timer.Interval = $Interval - } - - # edit scriptblock if supplied - if (!(Test-PodeIsEmpty $ScriptBlock)) { - $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState - $_timer.Script = $ScriptBlock - $_timer.UsingVariables = $usingVars - } - - # edit arguments if supplied - if (!(Test-PodeIsEmpty $ArgumentList)) { - $_timer.Arguments = $ArgumentList + process { + # ensure the timer exists + if (!$PodeContext.Timers.Items.ContainsKey($Name)) { + # Timer 'Name' does not exist + throw ($PodeLocale.timerDoesNotExistExceptionMessage -f $Name) + } + + $_timer = $PodeContext.Timers.Items[$Name] + + # edit interval if supplied + if ($Interval -gt 0) { + $_timer.Interval = $Interval + } + + # edit scriptblock if supplied + if (!(Test-PodeIsEmpty $ScriptBlock)) { + $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState + $_timer.Script = $ScriptBlock + $_timer.UsingVariables = $usingVars + } + + # edit arguments if supplied + if (!(Test-PodeIsEmpty $ArgumentList)) { + $_timer.Arguments = $ArgumentList + } } } diff --git a/src/Public/Utilities.ps1 b/src/Public/Utilities.ps1 index dde5ff1bb..5b44c4188 100644 --- a/src/Public/Utilities.ps1 +++ b/src/Public/Utilities.ps1 @@ -94,22 +94,34 @@ function Start-PodeStopwatch { [string] $Name, - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [scriptblock] $ScriptBlock ) - - try { - $watch = [System.Diagnostics.Stopwatch]::StartNew() - . $ScriptBlock + begin { + $pipelineItemCount = 0 } - catch { - $_ | Write-PodeErrorLog - throw $_.Exception + + process { + $pipelineItemCount++ } - finally { - $watch.Stop() - "[Stopwatch]: $($watch.Elapsed) [$($Name)]" | Out-PodeHost + + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + try { + $watch = [System.Diagnostics.Stopwatch]::StartNew() + . $ScriptBlock + } + catch { + $_ | Write-PodeErrorLog + throw $_.Exception + } + finally { + $watch.Stop() + "[Stopwatch]: $($watch.Elapsed) [$($Name)]" | Out-PodeHost + } } } @@ -240,7 +252,7 @@ Add-PodeEndware -ScriptBlock { /* logic */ } function Add-PodeEndware { [CmdletBinding()] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [scriptblock] $ScriptBlock, @@ -248,15 +260,27 @@ function Add-PodeEndware { [object[]] $ArgumentList ) + begin { + $pipelineItemCount = 0 + } - # check for scoped vars - $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState + process { + $pipelineItemCount++ + } - # add the scriptblock to array of endware that needs to be run - $PodeContext.Server.Endware += @{ - Logic = $ScriptBlock - UsingVariables = $usingVars - Arguments = $ArgumentList + end { + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) + } + # check for scoped vars + $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState + + # add the scriptblock to array of endware that needs to be run + $PodeContext.Server.Endware += @{ + Logic = $ScriptBlock + UsingVariables = $usingVars + Arguments = $ArgumentList + } } } @@ -495,7 +519,7 @@ Spat the argument onto the ScriptBlock. Don't create a new closure before invoking the ScriptBlock. .EXAMPLE -Invoke-PodeScriptBlock -ScriptBlock { Write-Host 'Hello!' } +Invoke-PodeScriptBlock -ScriptBlock { Write-PodeHost 'Hello!' } .EXAMPLE Invoke-PodeScriptBlock -Arguments 'Morty' -ScriptBlock { /* logic */ } @@ -772,14 +796,34 @@ The object to output. function Out-PodeHost { [CmdletBinding()] param( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [object] $InputObject ) + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() + } + + process { + # Add the current piped-in value to the array + $pipelineValue += $_ + } - if (!$PodeContext.Server.Quiet) { - $InputObject | Out-Default + end { + if ($PodeContext.Server.Quiet) { + return + } + # Set InputObject to the array of values + if ($pipelineValue.Count -gt 1) { + $InputObject = $pipelineValue + $InputObject | Out-Default + } + else { + Out-Default -InputObject $InputObject + } } + } <# @@ -805,6 +849,9 @@ Show the object content .PARAMETER ShowType Show the Object Type +.PARAMETER Label +Show a label for the object + .EXAMPLE 'Some output' | Write-PodeHost -ForegroundColor Cyan #> @@ -829,34 +876,67 @@ function Write-PodeHost { [Parameter( Mandatory = $false, ParameterSetName = 'object')] [switch] - $ShowType + $ShowType, + + [Parameter( Mandatory = $false, ParameterSetName = 'object')] + [string] + $Label ) + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() + } - if ($PodeContext.Server.Quiet) { - return + process { + # Add the current piped-in value to the array + $pipelineValue += $_ } - if ($Explode.IsPresent ) { - if ($null -eq $Object) { - if ($ShowType) { - $Object = "`tNull Value" + end { + if ($PodeContext.Server.Quiet) { + return + } + # Set Object to the array of values + if ($pipelineValue.Count -gt 1) { + $Object = $pipelineValue + } + + if ($Explode.IsPresent ) { + if ($null -eq $Object) { + if ($ShowType) { + $Object = "`tNull Value" + } + } + else { + $type = $Object.gettype().FullName + $Object = $Object | Out-String + if ($ShowType) { + $Object = "`tTypeName: $type`n$Object" + } + } + if ($Label) { + $Object = "`tName: $Label $Object" + } + + } + + if ($ForegroundColor) { + if ($pipelineValue.Count -gt 1) { + $Object | Write-Host -ForegroundColor $ForegroundColor -NoNewline:$NoNewLine + } + else { + Write-Host -Object $Object -ForegroundColor $ForegroundColor -NoNewline:$NoNewLine } } else { - $type = $Object.gettype().FullName - $Object = $Object | Out-String - if ($ShowType) { - $Object = "`tTypeName: $type`n$Object" + if ($pipelineValue.Count -gt 1) { + $Object | Write-Host -NoNewline:$NoNewLine + } + else { + Write-Host -Object $Object -NoNewline:$NoNewLine } } } - - if ($ForegroundColor) { - Write-Host -Object $Object -ForegroundColor $ForegroundColor -NoNewline:$NoNewLine - } - else { - Write-Host -Object $Object -NoNewline:$NoNewLine - } } <# @@ -954,12 +1034,28 @@ function Out-PodeVariable { [string] $Name, - [Parameter(ValueFromPipeline = $true)] + [Parameter(Position = 0, ValueFromPipeline = $true)] [object] $Value ) + begin { + # Initialize an array to hold piped-in values + $pipelineValue = @() + } + + process { + # Add the current piped-in value to the array + $pipelineValue += $_ + } + + end { + # Set Value to the array of values + if ($pipelineValue.Count -gt 1) { + $Value = $pipelineValue + } - $PodeContext.Server.Output.Variables[$Name] = $Value + $PodeContext.Server.Output.Variables[$Name] = $Value + } } <# @@ -1282,86 +1378,92 @@ Outputs an ordered hashtable representing the XML node structure. .NOTES This cmdlet is useful for transforming XML data into a structure that's easier to manipulate in PowerShell scripts. - -.LINK -https://badgerati.github.io/Pode/Functions/Utility/ConvertFrom-PodeXml - #> function ConvertFrom-PodeXml { [CmdletBinding()] [OutputType([System.Collections.Specialized.OrderedDictionary])] param ( - [Parameter(Mandatory = $true, ValueFromPipeline)] - [System.Xml.XmlNode]$node, #we are working through the nodes - [string]$Prefix = '', #do we indicate an attribute with a prefix? - $ShowDocElement = $false, #Do we show the document element?, + [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] + [System.Xml.XmlNode]$node, + + [Parameter()] + [string] + $Prefix = '', + + [Parameter()] + [switch] + $ShowDocElement, + + [Parameter()] [switch] $KeepAttributes ) - #if option set, we skip the Document element - if ($node.DocumentElement -and !($ShowDocElement)) - { $node = $node.DocumentElement } - $oHash = [ordered] @{ } # start with an ordered hashtable. - #The order of elements is always significant regardless of what they are - if ($null -ne $node.Attributes ) { - #if there are elements - # record all the attributes first in the ordered hash - $node.Attributes | ForEach-Object { - $oHash.$("$Prefix$($_.FirstChild.parentNode.LocalName)") = $_.FirstChild.value - } - } - # check to see if there is a pseudo-array. (more than one - # child-node with the same name that must be handled as an array) - $node.ChildNodes | #we just group the names and create an empty - #array for each - Group-Object -Property LocalName | Where-Object { $_.count -gt 1 } | Select-Object Name | - ForEach-Object { - $oHash.($_.Name) = @() <# create an empty array for each one#> - } - foreach ($child in $node.ChildNodes) { - #now we look at each node in turn. - $childName = $child.LocalName - if ($child -is [system.xml.xmltext]) { - # if it is simple XML text - $oHash.$childname += $child.InnerText + process { + #if option set, we skip the Document element + if ($node.DocumentElement -and !($ShowDocElement.IsPresent)) + { $node = $node.DocumentElement } + $oHash = [ordered] @{ } # start with an ordered hashtable. + #The order of elements is always significant regardless of what they are + if ($null -ne $node.Attributes ) { + #if there are elements + # record all the attributes first in the ordered hash + $node.Attributes | ForEach-Object { + $oHash.$("$Prefix$($_.FirstChild.parentNode.LocalName)") = $_.FirstChild.value + } } - # if it has a #text child we may need to cope with attributes - elseif ($child.FirstChild.Name -eq '#text' -and $child.ChildNodes.Count -eq 1) { - if ($null -ne $child.Attributes -and $KeepAttributes ) { - #hah, an attribute - <#we need to record the text with the #text label and preserve all + # check to see if there is a pseudo-array. (more than one + # child-node with the same name that must be handled as an array) + $node.ChildNodes | #we just group the names and create an empty + #array for each + Group-Object -Property LocalName | Where-Object { $_.count -gt 1 } | Select-Object Name | + ForEach-Object { + $oHash.($_.Name) = @() <# create an empty array for each one#> + } + foreach ($child in $node.ChildNodes) { + #now we look at each node in turn. + $childName = $child.LocalName + if ($child -is [system.xml.xmltext]) { + # if it is simple XML text + $oHash.$childname += $child.InnerText + } + # if it has a #text child we may need to cope with attributes + elseif ($child.FirstChild.Name -eq '#text' -and $child.ChildNodes.Count -eq 1) { + if ($null -ne $child.Attributes -and $KeepAttributes ) { + #hah, an attribute + <#we need to record the text with the #text label and preserve all the attributes #> - $aHash = [ordered]@{ } - $child.Attributes | ForEach-Object { - $aHash.$($_.FirstChild.parentNode.LocalName) = $_.FirstChild.value + $aHash = [ordered]@{ } + $child.Attributes | ForEach-Object { + $aHash.$($_.FirstChild.parentNode.LocalName) = $_.FirstChild.value + } + #now we add the text with an explicit name + $aHash.'#text' += $child.'#text' + $oHash.$childname += $aHash + } + else { + #phew, just a simple text attribute. + $oHash.$childname += $child.FirstChild.InnerText } - #now we add the text with an explicit name - $aHash.'#text' += $child.'#text' - $oHash.$childname += $aHash } - else { - #phew, just a simple text attribute. - $oHash.$childname += $child.FirstChild.InnerText + elseif ($null -ne $child.'#cdata-section' ) { + # if it is a data section, a block of text that isnt parsed by the parser, + # but is otherwise recognized as markup + $oHash.$childname = $child.'#cdata-section' } - } - elseif ($null -ne $child.'#cdata-section' ) { - # if it is a data section, a block of text that isnt parsed by the parser, - # but is otherwise recognized as markup - $oHash.$childname = $child.'#cdata-section' - } - elseif ($child.ChildNodes.Count -gt 1 -and + elseif ($child.ChildNodes.Count -gt 1 -and ($child | Get-Member -MemberType Property).Count -eq 1) { - $oHash.$childname = @() - foreach ($grandchild in $child.ChildNodes) { - $oHash.$childname += (ConvertFrom-PodeXml $grandchild) + $oHash.$childname = @() + foreach ($grandchild in $child.ChildNodes) { + $oHash.$childname += (ConvertFrom-PodeXml $grandchild) + } + } + else { + # create an array as a value to the hashtable element + $oHash.$childname += (ConvertFrom-PodeXml $child) } } - else { - # create an array as a value to the hashtable element - $oHash.$childname += (ConvertFrom-PodeXml $child) - } + return $oHash } - return $oHash } \ No newline at end of file diff --git a/tests/unit/Helpers.Tests.ps1 b/tests/unit/Helpers.Tests.ps1 index e9d9cb76f..4348a858e 100644 --- a/tests/unit/Helpers.Tests.ps1 +++ b/tests/unit/Helpers.Tests.ps1 @@ -1308,6 +1308,11 @@ Describe 'Out-PodeHost' { @{ Name = 'Rick' } | Out-PodeHost Assert-MockCalled Out-Default -Scope It -Times 1 } + + It 'Writes an Array to the Host by pipeline' { + @('France','Rick',21 ,'male') | Out-PodeHost + Assert-MockCalled Out-Default -Scope It -Times 1 + } } Describe 'Remove-PodeNullKeysFromHashtable' { diff --git a/tests/unit/OpenApi.Tests.ps1 b/tests/unit/OpenApi.Tests.ps1 index aab9ca389..270fc8604 100644 --- a/tests/unit/OpenApi.Tests.ps1 +++ b/tests/unit/OpenApi.Tests.ps1 @@ -2086,7 +2086,7 @@ Describe 'OpenApi' { { Merge-PodeOAProperty -Type AllOf -DiscriminatorProperty 'name' -ObjectDefinitions @('Pet', (New-PodeOAObjectProperty -Properties @((New-PodeOAIntProperty -Name 'id'), (New-PodeOAStringProperty -Name 'name'))) - # Discriminator parameter is not compatible with allOf + # Discriminator parameter is not compatible with allOf ) } | Should -Throw -ExpectedMessage $PodeLocale.discriminatorIncompatibleWithAllOfExceptionMessage } @@ -2184,20 +2184,20 @@ Describe 'OpenApi' { - Context 'Set-PodeOARouteInfo' { + Context 'Set-PodeOARouteInfo single route' { BeforeEach { $Route = @{ OpenApi = @{ - Path = '/test' - Responses = @{ + Path = '/test' + Responses = @{ '200' = @{ description = 'OK' } 'default' = @{ description = 'Internal server error' } } - Parameters = $null - RequestBody = $null - Authentication = @() - DefinitionTag = @('Default') - IsDefTagConfigured = $false + Parameters = $null + RequestBody = $null + Authentication = @() + DefinitionTag = @('Default') + IsDefTagConfigured = $false } } @@ -2243,6 +2243,74 @@ Describe 'OpenApi' { } } + Context 'Set-PodeOARouteInfo multi routes' { + BeforeEach { + $Route = @(@{ + OpenApi = @{ + Path = '/test' + Responses = @{ + '200' = @{ description = 'OK' } + 'default' = @{ description = 'Internal server error' } + } + Parameters = $null + RequestBody = $null + Authentication = @() + DefinitionTag = @('Default') + } + }, + @{ + OpenApi = @{ + Path = '/test2' + Responses = @{ + '200' = @{ description = 'OK' } + 'default' = @{ description = 'Internal server error' } + } + Parameters = $null + RequestBody = $null + Authentication = @() + DefinitionTag = @('Default') + } + }) + + Add-PodeOATag -Name 'pet' -Description 'Everything about your Pets' -ExternalDoc (New-PodeOAExternalDoc -Description 'Find out more about Swagger' -Url 'http://swagger.io') + } + + It 'No switches' { + $Route | Set-PodeOARouteInfo -Summary 'Update an existing pet' -Description 'Update an existing pet by Id' -Tags 'pet' + $Route.OpenApi | Should -Not -BeNullOrEmpty + $Route.OpenApi.Summary | Should -Be @('Update an existing pet', 'Update an existing pet') + $Route.OpenApi.description | Should -Be @('Update an existing pet by Id', 'Update an existing pet by Id') + $Route.OpenApi.tags | Should -Be @('pet', 'pet') + $Route.OpenApi.swagger | Should -BeTrue + $Route.OpenApi.deprecated | Should -BeNullOrEmpty + } + It 'Deprecated' { + $Route | Set-PodeOARouteInfo -Summary 'Update an existing pet' -Description 'Update an existing pet by Id' -Tags 'pet' -Deprecated + $Route.OpenApi | Should -Not -BeNullOrEmpty + $Route.OpenApi.Summary | Should -Be @('Update an existing pet', 'Update an existing pet') + $Route.OpenApi.description | Should -Be @('Update an existing pet by Id', 'Update an existing pet by Id') + $Route.OpenApi.tags | Should -Be @('pet', 'pet') + $Route.OpenApi.swagger | Should -BeTrue + $Route.OpenApi.deprecated | Should -BeTrue + } + + It 'PassThru' { + $result = $Route | Set-PodeOARouteInfo -Summary 'Update an existing pet' -Description 'Update an existing pet by Id' -Tags 'pet' -PassThru + $result | Should -Not -BeNullOrEmpty + $result.OpenApi | Should -Not -BeNullOrEmpty + $Route.OpenApi.Summary | Should -Be @('Update an existing pet', 'Update an existing pet') + $Route.OpenApi.description | Should -Be @('Update an existing pet by Id', 'Update an existing pet by Id') + $Route.OpenApi.tags | Should -Be @('pet', 'pet') + $result.OpenApi.swagger | Should -BeTrue + $result.OpenApi.deprecated | Should -BeNullOrEmpty + } + + It 'PassThru with OperationID' { + { $Route | Set-PodeOARouteInfo -Summary 'Update an existing pet' -Description 'Update an existing pet by Id' -Tags 'pet' -OperationId 'updatePet' -PassThru } | + Should -Throw -ExpectedMessage ($PodeLocale.operationIdMustBeUniqueForArrayExceptionMessage -f 'updatePet') #'OperationID: {0} has to be unique and cannot be applied to an array.' + } + } + Context 'Add-PodeOAComponentParameter' { # Check if the function exists @@ -3043,16 +3111,16 @@ Describe 'OpenApi' { $PodeContext = @{ Server = @{ OpenAPI = @{ - Definitions = @{ + Definitions = @{ 'oldTag' = @{ # Mock definition details Description = 'Old tag description' } } - SelectedDefinitionTag = 'oldTag' + SelectedDefinitionTag = 'oldTag' DefinitionTagSelectionStack = [System.Collections.Stack]@() } - Web = @{ + Web = @{ OpenApi = @{ DefaultDefinitionTag = 'oldTag' } @@ -3111,7 +3179,7 @@ Describe 'OpenApi' { It 'Sets Parameters on the route if provided' { $route = @{ - Method = 'GET' + Method = 'GET' OpenApi = @{} } $parameters = @( @@ -3125,7 +3193,7 @@ Describe 'OpenApi' { It 'Sets RequestBody on the route if method is POST' { $route = @{ - Method = 'POST' + Method = 'POST' OpenApi = @{} } $requestBody = @{ Content = 'application/json' } @@ -3137,7 +3205,7 @@ Describe 'OpenApi' { It 'Throws an exception if RequestBody is set on a method that does not allow it' { $route = @{ - Method = 'GET' + Method = 'GET' OpenApi = @{} } $requestBody = @{ Content = 'application/json' } @@ -3149,7 +3217,7 @@ Describe 'OpenApi' { It 'Returns the route when PassThru is used' { $route = @{ - Method = 'POST' + Method = 'POST' OpenApi = @{} } @@ -3160,7 +3228,7 @@ Describe 'OpenApi' { It 'Does not set RequestBody if not provided' { $route = @{ - Method = 'PUT' + Method = 'PUT' OpenApi = @{} } @@ -3294,4 +3362,4 @@ Describe 'OpenApi' { } } -} +} \ No newline at end of file diff --git a/tests/unit/Routes.Tests.ps1 b/tests/unit/Routes.Tests.ps1 index dc5aff5ca..cca2a9aa5 100644 --- a/tests/unit/Routes.Tests.ps1 +++ b/tests/unit/Routes.Tests.ps1 @@ -599,6 +599,11 @@ Describe 'ConvertTo-PodeRoute' { Assert-MockCalled Add-PodeRoute -Times 2 -Scope It } + It 'Calls Add-PodeRoute twice for commands by pipe' { + @('Get-ChildItem', 'Invoke-Expression') | ConvertTo-PodeRoute -NoOpenApi + Assert-MockCalled Add-PodeRoute -Times 2 -Scope It + } + It 'Calls Add-PodeRoute twice for module commands' { ConvertTo-PodeRoute -Module Example -NoOpenApi Assert-MockCalled Add-PodeRoute -Times 2 -Scope It diff --git a/tests/unit/State.Tests.ps1 b/tests/unit/State.Tests.ps1 index 2f3125570..f8c2ff61b 100644 --- a/tests/unit/State.Tests.ps1 +++ b/tests/unit/State.Tests.ps1 @@ -24,6 +24,15 @@ Describe 'Set-PodeState' { $PodeContext.Server.State['test'].Value | Should -Be 7 $PodeContext.Server.State['test'].Scope | Should -Be @() } + + It 'Sets by pipe and returns an object array' { + $PodeContext.Server = @{ 'State' = @{} } + $result = @(7,3,4)|Set-PodeState -Name 'test' + + $result | Should -Be @(7,3,4) + $PodeContext.Server.State['test'].Value | Should -Be @(7,3,4) + $PodeContext.Server.State['test'].Scope | Should -Be @() + } } Describe 'Get-PodeState' { From acac2357b5bbc07714361df76b4c8c92d0c2c991 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sun, 8 Sep 2024 19:46:28 -0700 Subject: [PATCH 145/177] Fix documentation - Change documentation reference of `-ContentMediaType ` to `-ContentType` - Set an alias for the `ContentType` parameter as `MediaType` for compatibility with previous release to the functions : - `New-PodeOAExample` - `New-PodeOAContentMediaType` --- docs/Tutorials/OpenAPI/1Overview.md | 5 +- docs/Tutorials/OpenAPI/3Components.md | 16 +- .../Tutorials/OpenAPI/5ParameterValidation.md | 4 +- .../Tutorials/OpenAPI/6MultipleDefinitions.md | 4 +- .../Tutorials/OpenAPI/Specification/v3.0.3.md | 144 +++++++++--------- examples/OpenApi-TuttiFrutti.ps1 | 78 +++++----- examples/PetStore/Petstore-OpenApi.ps1 | 38 ++--- .../PetStore/Petstore-OpenApiMultiTag.ps1 | 38 ++--- src/Public/OAComponents.ps1 | 2 +- src/Public/OpenApi.ps1 | 84 +++++----- tests/unit/OpenApi.Tests.ps1 | 10 +- 11 files changed, 214 insertions(+), 209 deletions(-) diff --git a/docs/Tutorials/OpenAPI/1Overview.md b/docs/Tutorials/OpenAPI/1Overview.md index 8e832e041..65cf5ebe6 100644 --- a/docs/Tutorials/OpenAPI/1Overview.md +++ b/docs/Tutorials/OpenAPI/1Overview.md @@ -212,7 +212,7 @@ Add-PodeRoute -Method Get -Path '/api/users/:userId' -ScriptBlock { } } -PassThru | Add-PodeOAResponse -StatusCode 200 -Description 'A user object' -Content ( - New-PodeOAContentMediaType -ContentMediaType 'application/json' -Array -Content ( + New-PodeOAContentMediaType -ContentType 'application/json' -Array -Content ( New-PodeOAStringProperty -Name 'Name' | New-PodeOAIntProperty -Name 'UserId' | New-PodeOAObjectProperty @@ -288,7 +288,7 @@ Add-PodeRoute -Method Patch -Path '/api/users' -ScriptBlock { } -PassThru | Set-PodeOARequest -RequestBody ( New-PodeOARequestBody -Required -Content ( - New-PodeOAContentMediaType -ContentMediaType 'application/json','application/xml' -Content ( New-PodeOAStringProperty -Name 'Name'| New-PodeOAIntProperty -Name 'UserId'| New-PodeOAObjectProperty ) ) + New-PodeOAContentMediaType -ContentType 'application/json','application/xml' -Content ( New-PodeOAStringProperty -Name 'Name'| New-PodeOAIntProperty -Name 'UserId'| New-PodeOAObjectProperty ) ) ) ``` @@ -310,4 +310,3 @@ The expected payload would look as follows: ``` - \ No newline at end of file diff --git a/docs/Tutorials/OpenAPI/3Components.md b/docs/Tutorials/OpenAPI/3Components.md index 054513915..2610eb604 100644 --- a/docs/Tutorials/OpenAPI/3Components.md +++ b/docs/Tutorials/OpenAPI/3Components.md @@ -37,7 +37,7 @@ The following is an example of defining a JSON object that a Name, UserId, and a ```powershell # define a reusable request body -New-PodeOAContentMediaType -ContentMediaType 'application/json', 'application/x-www-form-urlencoded' -Content ( +New-PodeOAContentMediaType -ContentType 'application/json', 'application/x-www-form-urlencoded' -Content ( New-PodeOAStringProperty -Name 'Name' | New-PodeOAIntProperty -Name 'UserId' | New-PodeOABoolProperty -Name 'Enabled' | @@ -90,7 +90,7 @@ The following is an example of defining a 200 response with a JSON payload of an ```powershell # defines a response with a json payload using New-PodeOAContentMediaType Add-PodeOAComponentResponse -Name 'OK' -Description 'A user object' -Content ( - New-PodeOAContentMediaType -MediaType 'application/json' -Array -Content ( + New-PodeOAContentMediaType -ContentType 'application/json' -Array -Content ( New-PodeOAStringProperty -Name 'Name' | New-PodeOAIntProperty -Name 'UserId' | New-PodeOAObjectProperty @@ -148,9 +148,9 @@ Add-PodeRoute -PassThru -Method Put -Path '/pet/:petId' -ScriptBlock { (New-PodeOAStringProperty -Name 'petId' -Description 'ID of pet that needs to be updated' | ConvertTo-PodeOAParameter -In Path -Required) ) -RequestBody ( New-PodeOARequestBody -Description 'user to add to the system' -Content @{ 'application/json' = 'Pet' } -Examples ( - New-PodeOAExample -ContentMediaType 'application/json', 'application/xml' -Reference 'cat-example' | - New-PodeOAExample -ContentMediaType 'application/json', 'application/xml' -Reference 'dog-example' | - New-PodeOAExample -ContentMediaType 'application/json', 'application/xml' -Reference 'frog-example' + New-PodeOAExample -ContentType 'application/json', 'application/xml' -Reference 'cat-example' | + New-PodeOAExample -ContentType 'application/json', 'application/xml' -Reference 'dog-example' | + New-PodeOAExample -ContentType 'application/json', 'application/xml' -Reference 'frog-example' ) ) -PassThru | Add-PodeOAResponse -StatusCode 200 -Description 'Pet updated.' @@ -173,7 +173,7 @@ Add-PodeRoute -PassThru -Method Get -Path '/user/login' -ScriptBlock { -Tags 'user' -OperationId 'loginUser' -PassThru | Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' ` -Header @('X-Rate-Limit', 'X-Expires-After') -Content ( - New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'string' + New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'string' ) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid username/password supplied' ``` @@ -191,7 +191,7 @@ Add-PodeRoute -PassThru -Method Post -Path '/petcallbackReference' -Authenticat -Tags 'pet' -OperationId 'petcallbackReference' -PassThru | Set-PodeOARequest -RequestBody ( New-PodeOARequestBody -Reference 'PetBodySchema' ) -PassThru | Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content ( - New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' + New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Validation exception' -Content @{ 'application / json' = ( New-PodeOAStringProperty -Name 'result' | @@ -220,7 +220,7 @@ Add-PodeRoute -PassThru -Method Put -Path '/userLinkByRef/:username' -ScriptBloc ( New-PodeOAStringProperty -Name 'username' -Description ' name that need to be updated.' -Required | ConvertTo-PodeOAParameter -In Path ) ) -RequestBody ( New-PodeOARequestBody -Required -Content ( - New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' ) + New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' ) ) -PassThru | Add-PodeOAResponse -StatusCode 200 -Content @{'application/json' = 'User' } -PassThru -Links ( New-PodeOAResponseLink -Name 'address2' -Reference 'address' diff --git a/docs/Tutorials/OpenAPI/5ParameterValidation.md b/docs/Tutorials/OpenAPI/5ParameterValidation.md index 23ca5a859..e1693997a 100644 --- a/docs/Tutorials/OpenAPI/5ParameterValidation.md +++ b/docs/Tutorials/OpenAPI/5ParameterValidation.md @@ -44,7 +44,7 @@ Add-PodeRoute -PassThru -Method Post -Path '/user' -ScriptBlock { Write-PodeHtmlResponse -StatusCode 405 -Value ($Validate.message -join ', ') } } | Set-PodeOARouteInfo -Summary 'Create user.' -Description 'This can only be done by the logged in user.' -Tags 'user' -OperationId 'createUser' -PassThru | - Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | + Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' -PassThru | - Add-PodeOAResponse -Default -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'User' ) + Add-PodeOAResponse -Default -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'User' ) ``` diff --git a/docs/Tutorials/OpenAPI/6MultipleDefinitions.md b/docs/Tutorials/OpenAPI/6MultipleDefinitions.md index ef0161873..c3278723f 100644 --- a/docs/Tutorials/OpenAPI/6MultipleDefinitions.md +++ b/docs/Tutorials/OpenAPI/6MultipleDefinitions.md @@ -118,9 +118,9 @@ Select-PodeOADefinition -Tag 'v3', 'v3.1' -ScriptBlock { } | Set-PodeOARouteInfo -Summary 'Update an existing pet' -Description 'Update an existing pet by Id' -Tags 'pet' -OperationId 'updatePet' -PassThru | Set-PodeOARequest -RequestBody ( New-PodeOARequestBody -Description 'Update an existent pet in the store' -Required -Content ( - New-PodeOAContentMediaType -ContentMediaType 'application/json', 'application/xml' -Content 'Pet' ) + New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentMediaType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'Pet not found' -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Validation exception' diff --git a/docs/Tutorials/OpenAPI/Specification/v3.0.3.md b/docs/Tutorials/OpenAPI/Specification/v3.0.3.md index 55274d89b..9d9ae153f 100644 --- a/docs/Tutorials/OpenAPI/Specification/v3.0.3.md +++ b/docs/Tutorials/OpenAPI/Specification/v3.0.3.md @@ -161,10 +161,10 @@ Types that are not accompanied by a `format` property follow the type definition The formats defined by the OAS are: -| [`type`](#dataTypes) | [`format`](#dataTypeFormat) | [`Pode CmdLet`](https://badgerati.github.io/Pode/Tutorials/OpenAPI/) | Comments | -| -------------------- | --------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | -| `integer` | `int32` | [`New-PodeOAIntProperty -Name 'anInteger' -Format Int32`] | signed 32 bits | -| `integer` | `int64` | [`New-PodeOAIntProperty -Name 'aLong' -Format Int64`] | signed 64 bits (a.k.a long) | +| [`type`](#dataTypes) | [`format`](#dataTypeFormat) | [`Pode CmdLet`](https://badgerati.github.io/Pode/Tutorials/OpenAPI/) | Comments | +|----------------------|-----------------------------|----------------------------------------------------------------------|-----------------------------| +| `integer` | `int32` | [`New-PodeOAIntProperty -Name 'anInteger' -Format Int32`] | signed 32 bits | +| `integer` | `int64` | [`New-PodeOAIntProperty -Name 'aLong' -Format Int64`] | signed 64 bits (a.k.a long) | | `number` | `float` | [`New-PodeOANumberProperty -Name 'aFloat' -Format Float`] | | `number` | `double` | [`New-PodeOANumberProperty -Name 'aDouble' -Format Double`] | | `string` | | [`New-PodeOAStringProperty -Name 'aString'`] | @@ -198,7 +198,7 @@ This is the root document object of the [OpenAPI document](#oasDocument). ##### Fixed Fields | Field Name | Type | Pode CmdLets | Description | -| ------------------------------------------ | :-----------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|--------------------------------------------|:-------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | openapi | `string` | [`Enable-PodeOpenApi`](../../../../Functions/OpenApi/Enable-PodeOpenApi) | **REQUIRED**. This string MUST be the [semantic version number](https://semver.org/spec/v2.0.0.html) of the [OpenAPI Specification version](#versions) that the OpenAPI document uses. The `openapi` field SHOULD be used by tooling specifications and clients to interpret the OpenAPI document. This is *not* related to the API [`info.version`](#infoVersion) string. | | info | [Info Object](#infoObject) | [`Add-PodeOAInfo`](../../../../Functions/OpenApi/Add-PodeOAInfo) | **REQUIRED**. Provides metadata about the API. The metadata MAY be used by tooling as required. | | servers | [[Server Object](#serverObject)] | [`Add-PodeOAServerEndpoint`](../../../../Functions/OpenApi/Add-PodeOAServerEndpoint) | An array of Server Objects, which provide connectivity information to a target server. If the `servers` property is not provided, or is an empty array, the default value would be a [Server Object](#serverObject) with a [url](#serverUrl) value of `/`. | @@ -218,7 +218,7 @@ The metadata MAY be used by the clients if needed, and MAY be presented in editi ##### Fixed Fields | Field Name | Type | `Add-PodeOAInfo` | Description | -| ----------------------------------------------- | :------------------------------: | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-------------------------------------------------|:--------------------------------:|----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| | title | `string` | `-Title` | **REQUIRED**. The title of the API. | | description | `string` | `-Description` | A short description of the API. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation. | | termsOfService | `string` | `-TermOfService` | A URL to the Terms of Service for the API. MUST be in the format of a URL. | @@ -278,7 +278,7 @@ Contact information for the exposed API. ##### Fixed Fields | Field Name | Type | `Add-PodeOAInfo` | Description | -| -------------------------------- | :------: | ---------------- | ------------------------------------------------------------------------------------------------ | +|----------------------------------|:--------:|------------------|--------------------------------------------------------------------------------------------------| | name | `string` | `-ContactName` | The identifying name of the contact person/organization. | | url | `string` | `-ContactUrl` | The URL pointing to the contact information. MUST be in the format of a URL. | | email | `string` | `-ContactEmail` | The email address of the contact person/organization. MUST be in the format of an email address. | @@ -312,7 +312,7 @@ License information for the exposed API. ##### Fixed Fields | Field Name | Type | `Add-PodeOAInfo` | Description | -| ------------------------------ | :------: | ---------------- | ---------------------------------------------------------------------- | +|--------------------------------|:--------:|------------------|------------------------------------------------------------------------| | name | `string` | `-LicenseName` | **REQUIRED**. The license name used for the API. | | url | `string` | `-LicenseUrl` | A URL to the license used for the API. MUST be in the format of a URL. | @@ -342,7 +342,7 @@ An object representing a Server. ##### Fixed Fields | Field Name | Type | `Add-PodeOAServerEndpoint` | Description | -| ------------------------------------------- | :------------------------------------------------------------: | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +|---------------------------------------------|:--------------------------------------------------------------:|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | url | `string` | `-Url` | **REQUIRED**. A URL to the target host. This URL supports Server Variables and MAY be relative, to indicate that the host location is relative to the location where the OpenAPI document is being served. Variable substitutions will be made when a variable is named in `{`brackets`}`. | | description | `string` | `-Description` | An optional string describing the host designated by the URL. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation. | | variables | Map[`string`, [Server Variable Object](#serverVariableObject)] | `-Variable` | A map between a variable name and its value. The value is used for substitution in the server's URL template. In Pode the OpenAPI Object's [`servers`](#oasServers) with variables can be defined using a `[ordered]@{}` [System.Collections.Specialized.OrderedDictionary](https://learn.microsoft.com/en-us/dotnet/api/system.collections.specialized.ordereddictionary?view=net-7.0) | @@ -481,7 +481,7 @@ An object representing a Server Variable for server URL template substitution. ##### Fixed Fields | Field Name | Type | Description | -| --------------------------------------------------- | :--------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------------------------------|:----------:|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | enum | [`string`] | An enumeration of string values to be used if the substitution options are from a limited set. The array SHOULD NOT be empty. | | default | `string` | **REQUIRED**. The default value to use for substitution, which SHALL be sent if an alternate value is _not_ supplied. Note this behavior is different than the [Schema Object's](#schemaObject) treatment of default values, because in those cases parameter values are optional. If the [`enum`](#serverVariableEnum) is defined, the value SHOULD exist in the enum's values. | | description | `string` | An optional description for the server variable. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation. | @@ -496,10 +496,10 @@ All objects defined within the components object will have no effect on the API ##### Fixed Fields -| Field Name | Type | Pode | Description | -| -------------------------------------------------------- | :----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | -| schemas | Map[`string`, [Schema Object](#schemaObject) \| [Reference Object](#referenceObject)] | [`Add-PodeOAComponentSchema`](../../../../Functions/OAComponents/Add-PodeOAComponentSchema) | An object to hold reusable [Schema Objects](#schemaObject). | -| responses | Map[`string`, [Response Object](#responseObject) \| [Reference Object](#referenceObject)] | [`Add-PodeOAComponentResponse`](../../../../Functions/OAComponents/Add-PodeOAComponentResponse) | An object to hold reusable [Response Objects](#responseObject). | +| Field Name | Type | Pode | Description | +|----------------------------------------------|:------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|-----------------------------------------------------------------| +| schemas | Map[`string`, [Schema Object](#schemaObject) \| [Reference Object](#referenceObject)] | [`Add-PodeOAComponentSchema`](../../../../Functions/OAComponents/Add-PodeOAComponentSchema) | An object to hold reusable [Schema Objects](#schemaObject). | +| responses | Map[`string`, [Response Object](#responseObject) \| [Reference Object](#referenceObject)] | [`Add-PodeOAComponentResponse`](../../../../Functions/OAComponents/Add-PodeOAComponentResponse) | An object to hold reusable [Response Objects](#responseObject). | | parameters | Map[`string`, [Parameter Object](#parameterObject) \| [Reference Object](#referenceObject)] | [`Add-PodeOAComponentParameter`](../../../../Functions/OAComponents/Add-PodeOAComponentParameter) | An object to hold reusable [Parameter Objects](#parameterObject). | PodeOAComponentExample | | examples | Map[`string`, [Example Object](#exampleObject) \| [Reference Object](#referenceObject)] | [`Add-PodeOAComponentExample`](../../../../Functions/OAComponents/Add-PodeOAComponentExample) | An object to hold reusable [Example Objects](#exampleObject). | | requestBodies | Map[`string`, [Request Body Object](#requestBodyObject) \| [Reference Object](#referenceObject)] | [`Add-PodeOAComponentRequestBody`](../../../../Functions/OAComponents/Add-PodeOAComponentRequestBody) | An object to hold reusable [Request Body Objects](#requestBodyObject). | @@ -752,7 +752,7 @@ The path is appended to the URL from the [`Server Object`](#serverObject) in ord ##### Patterned Fields | Field Pattern | Type | Description | -| ------------------------------- | :---------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|---------------------------------|:-----------------------------------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | /{path} | [Path Item Object](#pathItemObject) | A relative path to an individual endpoint. The field name MUST begin with a forward slash (`/`). The path is **appended** (no relative URL resolution) to the expanded URL from the [`Server Object`](#serverObject)'s `url` field in order to construct the full URL. [Path templating](#pathTemplating) is allowed. When matching URLs, concrete (non-templated) paths would be matched before their templated counterparts. Templated paths with the same hierarchy but different templated names MUST NOT exist as they are identical. In case of ambiguous matching, it's up to the tooling to decide which one to use. | This object MAY be extended with [Specification Extensions](#specificationExtensions). @@ -839,7 +839,7 @@ The path itself is still exposed to the documentation viewer but they will not k ##### Fixed Fields | Field Name | Type | Description | -| --------------------------------------------- | :----------------------------------------------------------------------------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------------------------|:------------------------------------------------------------------------------:|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | $ref | `string` | (Unsupported by Pode) Allows for an external definition of this path item. The referenced structure MUST be in the format of a [Path Item Object](#pathItemObject). In case a Path Item Object field appears both in the defined object and the referenced object, the behavior is undefined. | | summary | `string` | An optional, string summary, intended to apply to all operations in this path. | | description | `string` | An optional, string description, intended to apply to all operations in this path. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation. | @@ -1096,7 +1096,7 @@ $Route = Add-PodeRoute -PassThru -Method Get -Path '/pet/:petId' -ScriptBlock { ``` | Field Name | Type | `Set-PodeOARouteInfo` | Description | -| ------------------------------------------------ | :---------------------------------------------------------------------------------------: | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +|--------------------------------------------------|:-----------------------------------------------------------------------------------------:|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | tags | `string` | `-Tags` | A list of tags for API documentation control. Tags can be used for logical grouping of operations by resources or any other qualifier. | | summary | `string` | `-Summary` | A short summary of what the operation does. | | description | `string` | `-Description` | A verbose explanation of the operation behavior. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation. | @@ -1107,25 +1107,25 @@ $Route = Add-PodeRoute -PassThru -Method Get -Path '/pet/:petId' -ScriptBlock { | servers | [[Server Object](#serverObject)] | TBD | An alternative `server` array to service this operation. If an alternative `server` object is specified at the Path Item Object or Root level, it will be overridden by this value. | | Field Name | Type | `Set-PodeOARequest` | Description | -| ---------------------------------------------- | :-------------------------------------------------------------------------------: | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|------------------------------------------------|:---------------------------------------------------------------------------------:|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | parameters | [[Parameter Object](#parameterObject) \| [Reference Object](#referenceObject)] | `-Parameters` | A list of parameters that are applicable for this operation. If a parameter is already defined at the [Path Item](#pathItemParameters), the new definition will override it but can never remove it. The list MUST NOT include duplicated parameters. A unique parameter is defined by a combination of a [name](#parameterName) and [location](#parameterIn). The list can use the [Reference Object](#referenceObject) to link to parameters that are defined at the [OpenAPI Object's components/parameters](#componentsParameters). | | requestBody | [Request Body Object](#requestBodyObject) \| [Reference Object](#referenceObject) | `-RequestBody` | The request body applicable for this operation. The `requestBody` is only supported in HTTP methods where the HTTP 1.1 specification [RFC7231](https://tools.ietf.org/html/rfc7231#section-4.3.1) has explicitly defined semantics for request bodies. In other cases where the HTTP spec is vague, `requestBody` SHALL be ignored by consumers. | | Field Name | Type | `Set-PodeOAResponse` | Description | -| ------------------------------------------ | :----------------------------------: | -------------------- | ------------------------------------------------------------------------------------------------ | +|--------------------------------------------|:------------------------------------:|----------------------|--------------------------------------------------------------------------------------------------| | responses | [Responses Object](#responsesObject) | | **REQUIRED**. The list of possible responses as they are returned from executing this operation. | | Field Name | Type | `Add-PodeRoute` | Description | -| ---------------------------------------- | :---------------------------------------------------------: | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|------------------------------------------|:-----------------------------------------------------------:|-------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | security | [[Security Requirement Object](#securityRequirementObject)] | `-Authentication` `-Scope ` | A declaration of which security mechanisms can be used for this operation. The list of values includes alternative security requirement objects that can be used. Only one of the security requirement objects need to be satisfied to authorize a request. To make security optional, an empty security requirement (`{}`) can be included in the array. This definition overrides any declared top-level [`security`](#oasSecurity). To remove a top-level security declaration, an empty array can be used. | | Field Name | Type | Unsupported | Description | -| ------------------------------------------ | :---------------------------------------------------------------------------------------: | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|--------------------------------------------|:-----------------------------------------------------------------------------------------:|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | callbacks | Map[`string`, [Callback Object](#callbackObject) \| [Reference Object](#referenceObject)] | | A map of possible out-of band callbacks related to the parent operation. The key is a unique identifier for the Callback Object. Each value in the map is a [Callback Object](#callbackObject) that describes a request that may be initiated by the API provider and the expected responses. | | servers | [[Server Object](#serverObject)] | | An alternative `server` array to service this operation. If an alternative `server` object is specified at the Path Item Object or Root level, it will be overridden by this value. | @@ -1275,7 +1275,7 @@ Allows referencing an external resource for extended documentation. ##### Fixed Fields | Field Name | Type | `New-PodeOAExternalDoc` | Description | -| ------------------------------------------------ | :------: | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +|--------------------------------------------------|:--------:|-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------| | description | `string` | `-Description` | A short description of the target documentation. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation. | | url | `string` | `-Url` | **REQUIRED**. The URL for the target documentation. Value MUST be in the format of a URL. | @@ -1317,7 +1317,7 @@ There are four possible parameter locations specified by the `in` field: ##### Fixed Fields | Field Name | Type | `ConvertTo-PodeOAParameter` | Description | -| ------------------------------------------------------- | :-------: | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +|---------------------------------------------------------|:---------:|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | name | `string` | `-Name` | **REQUIRED**. The name of the parameter. Parameter names are *case sensitive*.
  • If [`in`](#parameterIn) is `"path"`, the `name` field MUST correspond to a template expression occurring within the [path](#pathsPath) field in the [Paths Object](#pathsObject). See [Path Templating](#pathTemplating) for further information.
  • If [`in`](#parameterIn) is `"header"` and the `name` field is `"Accept"`, `"Content-Type"` or `"Authorization"`, the parameter definition SHALL be ignored.
  • For all other cases, the `name` corresponds to the parameter name used by the [`in`](#parameterIn) property.
Note. In Pode if the -Name parameter is not used the name of the Property created by `New-PodeOAIntProperty`, `New-PodeOANumberProperty`, `New-PodeOABoolProperty `, `New-PodeOAStringProperty`, `New-PodeOAObjectProperty` is used. | | in | `string` | `-In` | **REQUIRED**. The location of the parameter. Possible values are `"query"`, `"header"`, `"path"` or `"cookie"`. | | description | `string` | `-Description` | A brief description of the parameter. This could contain examples of use. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation. | @@ -1329,7 +1329,7 @@ The rules for serialization of the parameter are specified in one of two ways. For simpler scenarios, a [`schema`](#parameterSchema) and [`style`](#parameterStyle) can describe the structure and syntax of the parameter. | Field Name | Type | `ConvertTo-PodeOAParameter` | Description | -| -------------------------------------------------- | :--------------------------------------------------------------------------------------: | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|----------------------------------------------------|:----------------------------------------------------------------------------------------:|-----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | style | `string` | `-Style` | Describes how the parameter value will be serialized depending on the type of the parameter value. Default values (based on value of `in`): for `query` - `form`; for `path` - `simple`; for `header` - `simple`; for `cookie` - `form`. | | explode | `boolean` | `-Explode` | When this is true, parameter values of type `array` or `object` generate separate parameters for each value of the array or key-value pair of the map. For other types of parameters this property has no effect. When [`style`](#parameterStyle) is `form`, the default value is `true`. For all other styles, the default value is `false`. | | allowReserved | `boolean` | `-AllowReserved` | Determines whether the parameter value SHOULD allow reserved characters, as defined by [RFC3986](https://tools.ietf.org/html/rfc3986#section-2.2) `:/?#[]@!$&'()*+,;=` to be included without percent-encoding. This property only applies to parameters with an `in` value of `query`. The default value is `false`. | @@ -1343,7 +1343,7 @@ When `example` or `examples` are provided in conjunction with the `schema` objec | Field Name | Type | `ConvertTo-PodeOAParameter` | Description | -| -------------------------------------- | :--------------------------------------------------: | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +|----------------------------------------|:----------------------------------------------------:|-----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------| | content | Map[`string`, [Media Type Object](#mediaTypeObject)] | `-Content` | A map containing the representations for the parameter. The key is the media type and the value describes it. The map MUST only contain one entry. | ##### Style Values @@ -1351,7 +1351,7 @@ When `example` or `examples` are provided in conjunction with the `schema` objec In order to support common ways of serializing simple parameters, a set of `style` values are defined. | `style` | [`type`](#dataTypes) | `in` | Comments | -| -------------- | ------------------------------ | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|----------------|--------------------------------|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | matrix | `primitive`, `array`, `object` | `path` | Path-style parameters defined by [RFC6570](https://tools.ietf.org/html/rfc6570#section-3.2.7) | | label | `primitive`, `array`, `object` | `path` | Label style parameters defined by [RFC6570](https://tools.ietf.org/html/rfc6570#section-3.2.5) | | form | `primitive`, `array`, `object` | `query`, `cookie` | Form style parameters defined by [RFC6570](https://tools.ietf.org/html/rfc6570#section-3.2.8). This option replaces `collectionFormat` with a `csv` (when `explode` is false) or `multi` (when `explode` is true) value from OpenAPI 2.0. | @@ -1372,7 +1372,7 @@ Assume a parameter named `color` has one of the following values: The following table shows examples of rendering differences for each value. | [`style`](#dataTypeFormat) | `explode` | `empty` | `string` | `array` | `object` | -| -------------------------- | --------- | ------- | ----------- | ----------------------------------- | -------------------------------------- | +|----------------------------|-----------|---------|-------------|-------------------------------------|----------------------------------------| | matrix | false | ;color | ;color=blue | ;color=blue,black,brown | ;color=R,100,G,200,B,150 | | matrix | true | ;color | ;color=blue | ;color=blue;color=black;color=brown | ;R=100;G=200;B=150 | | label | false | . | .blue | .blue.black.brown | .R.100.G.200.B.150 | @@ -1575,7 +1575,7 @@ Describes a single request body. ##### Fixed Fields | Field Name | Type | `New-PodeOARequestBody` | Description | -| ------------------------------------------------ | :--------------------------------------------------: | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|--------------------------------------------------|:----------------------------------------------------:|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | description | `string` | `-Description` | A brief description of the request body. This could contain examples of use. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation. | | content | Map[`string`, [Media Type Object](#mediaTypeObject)] | `-Content` | **REQUIRED**. The content of the request body. The key is a media type or [media type range](https://tools.ietf.org/html/rfc7231#appendix-D) and the value describes it. For requests that match multiple keys, only the most specific key is applicable. e.g. text/plain overrides text/* | | required | `boolean` | `-Required` | Determines if the request body is required in the request. Defaults to `false`. | @@ -1587,10 +1587,10 @@ This object MAY be extended with [Specification Extensions](#specificationExtens A request body with a referenced model definition. ```powershell New-PodeOARequestBody -Description 'user to add to the system' -Content @{ 'application/json' = 'User'; 'application/xml' = 'User'} -Examples ( - New-PodeOAExample -MediaType 'application/json' -Name 'user' -Summary 'User Example' -ExternalValue 'http://foo.bar/examples/user-example.json' | - New-PodeOAExample -MediaType 'application/xml' -Name 'user' -Summary 'User Example in XML' -ExternalValue 'http://foo.bar/examples/user-example.xml' | - New-PodeOAExample -MediaType 'text/plain' -Name 'user' -Summary 'User Example in Plain text' -ExternalValue 'http://foo.bar/examples/user-example.txt' | - New-PodeOAExample -MediaType '*/*' -Name 'user' -Summary 'User example in other format' -ExternalValue 'http://foo.bar/examples/user-example.whatever' + New-PodeOAExample -ContentType 'application/json' -Name 'user' -Summary 'User Example' -ExternalValue 'http://foo.bar/examples/user-example.json' | + New-PodeOAExample -ContentType 'application/xml' -Name 'user' -Summary 'User Example in XML' -ExternalValue 'http://foo.bar/examples/user-example.xml' | + New-PodeOAExample -ContentType 'text/plain' -Name 'user' -Summary 'User Example in Plain text' -ExternalValue 'http://foo.bar/examples/user-example.txt' | + New-PodeOAExample -ContentType '*/*' -Name 'user' -Summary 'User example in other format' -ExternalValue 'http://foo.bar/examples/user-example.whatever' ) ``` @@ -1709,7 +1709,7 @@ Each Media Type Object provides schema and examples for the media type identifie ##### Fixed Fields | Field Name | Type | `New-PodeOARequestBody` | Description | -| ---------------------------------------- | :--------------------------------------------------------------------------------------: | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|------------------------------------------|:----------------------------------------------------------------------------------------:|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | schema | [Schema Object](#schemaObject) \| [Reference Object](#referenceObject) | `-Schema` | The schema defining the content of the request, response, or parameter. | | example | Any | `Not Supported` | Example of the media type. The example object SHOULD be in the correct format as specified by the media type. The `example` field is mutually exclusive of the `examples` field. Furthermore, if referencing a `schema` which contains an example, the `example` value SHALL _override_ the example provided by the schema. | | examples | Map[ `string`, [Example Object](#exampleObject) \| [Reference Object](#referenceObject)] | `-Examples` | Examples of the media type. Each example object SHOULD match the media type and specified schema if present. The `examples` field is mutually exclusive of the `example` field. Furthermore, if referencing a `schema` which contains an example, the `examples` value SHALL _override_ the example provided by the schema. | @@ -1721,9 +1721,9 @@ This object MAY be extended with [Specification Extensions](#specificationExtens ```powershell New-PodeOARequestBody -Content @{ 'application/json' = 'Pet' } -Examples ( - New-PodeOAExample -MediaType 'application/json' -Name 'cat' -Summary 'An example of a cat' -Value @{name = 'Fluffy'; petType = 'Cat'; color = 'White'; gender = 'male'; breed = 'Persian' } | - New-PodeOAExample -MediaType 'application/json' -Name 'dog' -Summary "An example of a dog with a cat's name" -Value @{name = 'Puma'; petType = 'Dog'; color = 'Black'; gender = 'Female'; breed = 'Mixed' }| - New-PodeOAExample -MediaType 'application/json' -Reference 'frog-example' + New-PodeOAExample -ContentType 'application/json' -Name 'cat' -Summary 'An example of a cat' -Value @{name = 'Fluffy'; petType = 'Cat'; color = 'White'; gender = 'male'; breed = 'Persian' } | + New-PodeOAExample -ContentType 'application/json' -Name 'dog' -Summary "An example of a dog with a cat's name" -Value @{name = 'Puma'; petType = 'Dog'; color = 'Black'; gender = 'Female'; breed = 'Mixed' }| + New-PodeOAExample -ContentType 'application/json' -Reference 'frog-example' ) ``` @@ -1834,7 +1834,7 @@ In addition, specific media types MAY be specified: or ```powershell -New-PodeOAContentMediaType -MediaType 'image/jpeg','image/png' -Content (New-PodeOAStringProperty -Format binary) +New-PodeOAContentMediaType -ContentType 'image/jpeg','image/png' -Content (New-PodeOAStringProperty -Format binary) ``` ```yaml @@ -1933,7 +1933,7 @@ Examples: ```powershell Set-PodeOARequest -RequestBody ( New-PodeOARequestBody -Content ( - New-PodeOAContentMediaType -MediaType 'multipart/form-data' -Content ( + New-PodeOAContentMediaType -ContentType 'multipart/form-data' -Content ( New-PodeOAStringProperty -name 'id' -format 'uuid' | New-PodeOAObjectProperty -name 'address' -NoProperties | New-PodeOAStringProperty -name 'children' -array | @@ -1982,7 +1982,7 @@ A single encoding definition applied to a single schema property. ##### Fixed Fields | Field Name | Type | `New-PodeOAEncodingObject` | Description | -| ------------------------------------------------- | :-----------------------------------------------------------------------------------: | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|---------------------------------------------------|:-------------------------------------------------------------------------------------:|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | contentType | `string` | `-ContentType` | The Content-Type for encoding a specific property. Default value depends on the property type: for `string` with `format` being `binary` ? `application/octet-stream`; for other primitive types ? `text/plain`; for `object` - `application/json`; for `array` ? the default is defined based on the inner type. The value can be a specific media type (e.g. `application/json`), a wildcard media type (e.g. `image/*`), or a comma-separated list of the two types. | | headers | Map[`string`, [Header Object](#headerObject) \| [Reference Object](#referenceObject)] | `-Headers` | A map allowing additional information to be provided as headers, for example `Content-Disposition`. `Content-Type` is described separately and SHALL be ignored in this section. This property SHALL be ignored if the request body media type is not a `multipart`. | | style | `string` | `-Style` | Describes how a specific property value will be serialized depending on its type. See [Parameter Object](#parameterObject) for details on the [`style`](#parameterStyle) property. The behavior follows the same values as `query` parameters, including default values. This property SHALL be ignored if the request body media type is not `application/x-www-form-urlencoded`. | @@ -1994,7 +1994,7 @@ This object MAY be extended with [Specification Extensions](#specificationExtens ##### Encoding Object Example ```powershell -New-PodeOARequestBody -Content (New-PodeOAContentMediaType -MediaType 'multipart/mixed' -Content ( +New-PodeOARequestBody -Content (New-PodeOAContentMediaType -ContentType 'multipart/mixed' -Content ( New-PodeOAStringProperty -name 'id' -format 'uuid' | New-PodeOAObjectProperty -name 'address' -NoProperties | New-PodeOAObjectProperty -name 'historyMetadata' -Description 'metadata in XML format' -NoProperties | @@ -2063,12 +2063,12 @@ SHOULD be the response for a successful operation call. ##### Fixed Fields | Field Name | Type | `Add-PodeOAResponse` | Description | -| -------------------------------------- | :------------------------------------------------------------------------: | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|----------------------------------------|:--------------------------------------------------------------------------:|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | default | [Response Object](#responseObject) \| [Reference Object](#referenceObject) | `-Default` | The documentation of responses other than the ones declared for specific HTTP response codes. Use this field to cover undeclared responses. A [Reference Object](#referenceObject) can link to a response that the [OpenAPI Object's components/responses](#componentsResponses) section defines. | ##### Patterned Fields | Field Pattern | Type | `Add-PodeOAResponse` | Description | -| ---------------------------------------------------------- | :------------------------------------------------------------------------: | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|------------------------------------------------------------|:--------------------------------------------------------------------------:|----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [HTTP Status Code](#httpCodes) | [Response Object](#responseObject) \| [Reference Object](#referenceObject) | `-StatusCode` | Any [HTTP status code](#httpCodes) can be used as the property name, but only one property per code, to describe the expected response for that HTTP status code. A [Reference Object](#referenceObject) can link to a response that is defined in the [OpenAPI Object's components/responses](#componentsResponses) section. This field MUST be enclosed in quotation marks (for example, "200") for compatibility between JSON and YAML. To define a range of response codes, this field MAY contain the uppercase wildcard character `X`. For example, `2XX` represents all response codes between `[200-299]`. Only the following range definitions are allowed: `1XX`, `2XX`, `3XX`, `4XX`, and `5XX`. If a response is defined using an explicit code, the explicit code definition takes precedence over the range definition for that code. | @@ -2129,7 +2129,7 @@ Describes a single response from an API Operation, including design-time, static ##### Fixed Fields | Field Name | Type | `Add-PodeOAResponse` | Description | -| --------------------------------------------- | :------------------------------------------------------------------------------------: | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------------------------|:--------------------------------------------------------------------------------------:|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | description | `string` | `-Description` | **REQUIRED**. A short description of the response. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation. | | headers | Map[`string`, [Header Object](#headerObject) \| [Reference Object](#referenceObject)] | `-Headers` | Maps a header name to its definition. [RFC7230](https://tools.ietf.org/html/rfc7230#page-22) states header names are case insensitive. If a response header is defined with the name `"Content-Type"`, it SHALL be ignored. | | content | Map[`string`, [Media Type Object](#mediaTypeObject)] | `-Content` | A map containing descriptions of potential response payloads. The key is a media type or [media type range](https://tools.ietf.org/html/rfc7231#appendix-D) and the value describes it. For responses that match multiple keys, only the most specific key is applicable. e.g. text/plain overrides text/* | @@ -2143,7 +2143,7 @@ Response of an array of a complex type: ```powershell Add-PodeOAResponse -StatusCode 200 -Description 'A complex object array response' -Content ( - New-PodeOAMediaContentType -MediaType 'application/json' -Content 'VeryComplexType' -Array + New-PodeOAMediaContentType -ContentType 'application/json' -Content 'VeryComplexType' -Array ) ``` @@ -2179,13 +2179,13 @@ Add-PodeOAResponse -StatusCode 200 -Description 'A complex object array response Response with a string type: ```powershell -Add-PodeOAResponse -StatusCode 200 -Description 'A simple string response' -Content (New-PodeOAMediaContentType -MediaType 'text/plain' -Content (New-PodeOAStringProperty) -Array) +Add-PodeOAResponse -StatusCode 200 -Description 'A simple string response' -Content (New-PodeOAMediaContentType -ContentType 'text/plain' -Content (New-PodeOAStringProperty) -Array) ``` or ```powershell -Add-PodeOAResponse -StatusCode 200 -Description 'A simple string response' -Content (New-PodeOAMediaContentType -MediaType 'text/plain' -Content 'string' -Array) +Add-PodeOAResponse -StatusCode 200 -Description 'A simple string response' -Content (New-PodeOAMediaContentType -ContentType 'text/plain' -Content 'string' -Array) ``` ```json @@ -2310,7 +2310,7 @@ The key value used to identify the path item object is an expression, evaluated ##### Patterned Fields | Field Pattern | Type | Description | -| --------------------------------------------- | :---------------------------------: | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------------------------|:-----------------------------------:|----------------------------------------------------------------------------------------------------------------------------------------------------------| | {expression} | [Path Item Object](#pathItemObject) | A Path Item Object used to define a callback request and expected responses. A [complete example](../examples/v3.0/callback-example.yaml) is available. | This object MAY be extended with [Specification Extensions](#specificationExtensions). @@ -2346,7 +2346,7 @@ Location: http://example.org/subscription/1 The following examples show how the various expressions evaluate, assuming the callback operation has a path parameter named `eventType` and a query parameter named `queryUrl`. | Expression | Value | -| ---------------------------- | :--------------------------------------------------------------------------------- | +|------------------------------|:-----------------------------------------------------------------------------------| | $url | http://example.org/subscribe/myevent?queryUrl=http://clientdomain.com/stillrunning | | $method | POST | | $request.path.eventType | myevent | @@ -2404,7 +2404,7 @@ transactionCallback: ##### Fixed Fields | Field Name | Type | `New-PodeOAExample ` | Description | -| ------------------------------------------------ | :------: | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|--------------------------------------------------|:--------:|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | summary | `string` | `-Summary` | Short description for the example. | | description | `string` | `-Description` | Long description for the example. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation. | | value | Any | `-Value` | Embedded literal example. The `value` field and `externalValue` field are mutually exclusive. To represent examples of media types that cannot naturally represented in JSON or YAML, use a string value to contain the example, escaping where necessary. | @@ -2422,10 +2422,10 @@ In a request body: ```powershell New-PodeOARequestBody -Content @{ 'application/json' = 'Address' } -Examples ( - New-PodeOAExample -MediaType 'application/json' -Name 'foo' -Summary 'A foo example' -Value @{foo = 'bar' } | - New-PodeOAExample -MediaType 'application/json' -Name 'bar' -Summary 'A bar example' -Value @{'bar' = 'baz' }| - New-PodeOAExample -MediaType 'application/xml' -Name 'xmlExample' -Summary 'This is an example in XML' -ExternalValue 'http://example.org/examples/address-example.xml' | - New-PodeOAExample -MediaType 'text/plain' -Name 'textExample' -Summary 'This is an example' -ExternalValue 'http://example.org/examples/address-example.txt' | + New-PodeOAExample -ContentType 'application/json' -Name 'foo' -Summary 'A foo example' -Value @{foo = 'bar' } | + New-PodeOAExample -ContentType 'application/json' -Name 'bar' -Summary 'A bar example' -Value @{'bar' = 'baz' }| + New-PodeOAExample -ContentType 'application/xml' -Name 'xmlExample' -Summary 'This is an example in XML' -ExternalValue 'http://example.org/examples/address-example.xml' | + New-PodeOAExample -ContentType 'text/plain' -Name 'textExample' -Summary 'This is an example' -ExternalValue 'http://example.org/examples/address-example.txt' | ) ``` @@ -2503,7 +2503,7 @@ For computing links, and providing instructions to execute them, a [runtime expr ##### Fixed Fields | Field Name | Type | Description | -| ------------------------------------------- | :------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|---------------------------------------------|:--------------------------------------------------------:|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | operationRef | `string` | A relative or absolute URI reference to an OAS operation. This field is mutually exclusive of the `operationId` field, and MUST point to an [Operation Object](#operationObject). Relative `operationRef` values MAY be used to locate an existing [Operation Object](#operationObject) in the OpenAPI definition. | | operationId | `string` | The name of an _existing_, resolvable OAS operation, as defined with a unique `operationId`. This field is mutually exclusive of the `operationRef` field. | | parameters | Map[`string`, Any \| [{expression}](#runtimeExpression)] | A map representing parameters to pass to an operation as specified with `operationId` or identified via `operationRef`. The key is the parameter name to be used, whereas the value can be a constant or an expression to be evaluated and passed to the linked operation. The parameter name can be qualified using the [parameter location](#parameterIn) `[{in}.]{name}` for operations that use the same parameter name in different locations (e.g. path.id). | @@ -2649,9 +2649,9 @@ The table below provides examples of runtime expressions and examples of their u ##### Examples -| Source Location | example expression | notes | -| --------------------- | :------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- | -| HTTP Method | `$method` | The allowable values for the `$method` will be those for the HTTP operation. | +| Source Location | example expression | notes | +|-----------------|:-------------------|:-----------------------------------------------------------------------------| +| HTTP Method | `$method` | The allowable values for the `$method` will be those for the HTTP operation. | | Requested media type | `$request.header.accept` | | Request parameter | `$request.path.id` | Request parameters MUST be declared in the `parameters` section of the parent operation or they cannot be evaluated. This includes request headers. | | Request body property | `$request.body#/user/uuid` | In operations which accept payloads, references may be made to portions of the `requestBody` or the entire body. | @@ -2696,7 +2696,7 @@ It is not mandatory to have a Tag Object per tag defined in the Operation Object ##### Fixed Fields | Field Name | Type | `Add-PodeOATag` | Description | -| ------------------------------------------ | :-----------------------------------------------------------: | --------------- | ---------------------------------------------------------------------------------------------------------------------------- | +|--------------------------------------------|:-------------------------------------------------------------:|-----------------|------------------------------------------------------------------------------------------------------------------------------| | name | `string` | `-Name` | **REQUIRED**. The name of the tag. | | description | `string` | `-Description` | A short description for the tag. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation. | | externalDocs | [External Documentation Object](#externalDocumentationObject) | `-ExternalDocs` | Additional external documentation for this tag. In Pode is an ExternalDoc object created with `New-PodeOAExternalDoc` | @@ -2730,7 +2730,7 @@ For this specification, reference resolution is accomplished as defined by the J ##### Fixed Fields | Field Name | Type | Description | -| ------------------------------- | :------: | ----------------------------------- | +|---------------------------------|:--------:|-------------------------------------| | $ref | `string` | **REQUIRED**. The reference string. | This object cannot be extended with additional properties and any properties added SHALL be ignored. @@ -2807,7 +2807,7 @@ The following properties are taken directly from the JSON Schema definition and type - Value MUST be a string. Multiple types via an array are not supported. | type | cmdlet | -| ------ | -------------------------- | +|--------|----------------------------| | int | `New-PodeOAIntProperty` | | string | `New-PodeOAStringProperty` | | object | `New-PodeOAObjectProperty` | @@ -2839,7 +2839,7 @@ type - Value MUST be a string. Multiple types via an array are not supported. | properties | `-properties` | `New-PodeOAObjectProperty` Property definitions MUST be a [Schema Object](#schemaObject) and not a standard JSON Schema (inline or referenced). | | type | `Merge-PodeOAProperty` | Note | -| ----------------------------------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-------------------------------------------------|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | allOf | `-Type AllOf` | | | oneOf | `-Type OneOf` | (Pode) Doesn't support schema validation | | anyOf | `-Type AnyOf` | (Pode)Doesn't support schema validation | @@ -2862,7 +2862,7 @@ Other than the JSON Schema subset fields, the following fields MAY be used for f ##### Fixed Fields | Field Name | Type | | Description | -| --------------------------------------------- | :-----------------------------------------------------------: | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------------------------|:-------------------------------------------------------------:|-----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | nullable | `boolean` | `-Nullable` | A `true` value adds `"null"` to the allowed type specified by the `type` keyword, only if `type` is explicitly defined within the same Schema Object. Other Schema Object constraints retain their defined behavior, and therefore may disallow the use of `null` as a value. A `false` value leaves the specified or default `type` unmodified. The default value is `false`. | | readOnly | `boolean` | `-ReadOnly` | Relevant only for Schema `"properties"` definitions. Declares the property as "read only". This means that it MAY be sent as part of a response but SHOULD NOT be sent as part of the request. If the property is marked as `readOnly` being `true` and is in the `required` list, the `required` will take effect on the response only. A property MUST NOT be marked as both `readOnly` and `writeOnly` being `true`. Default value is `false`. | | writeOnly | `boolean` | `-WriteOnly` | Relevant only for Schema `"properties"` definitions. Declares the property as "write only". Therefore, it MAY be sent as part of a request but SHOULD NOT be sent as part of the response. If the property is marked as `writeOnly` being `true` and is in the `required` list, the `required` will take effect on the request only. A property MUST NOT be marked as both `readOnly` and `writeOnly` being `true`. Default value is `false`. | @@ -3279,7 +3279,7 @@ When using the discriminator, _inline_ schemas will not be considered. ##### Fixed Fields | Field Name | Type | `New-PodeOAObjectProperty` | Description | -| ------------------------------------------- | :---------------------: | -------------------------- | --------------------------------------------------------------------------------------------- | +|---------------------------------------------|:-----------------------:|----------------------------|-----------------------------------------------------------------------------------------------| | propertyName | `string` | `-DiscriminatorProperty` | **REQUIRED**. The name of the property in the payload that will hold the discriminator value. | | mapping | Map[`string`, `string`] | `-DiscriminatorMapping` | An object to hold mappings between payload values and schema names or references. | @@ -3442,7 +3442,7 @@ See examples for expected behavior. ##### Fixed Fields | Field Name | Type | `New-PodeOA(*)Property` | Description | -| ------------------------------------ | :-------: | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|--------------------------------------|:---------:|-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | name | `string` | `-XmlName` | Replaces the name of the element/attribute used for the described schema property. When defined within `items`, it will affect the name of the individual XML elements within the list. When defined alongside `type` being `array` (outside the `items`), it will affect the wrapping element and only if `wrapped` is `true`. If `wrapped` is `false`, it will be ignored. | | namespace | `string` | `-XmlNameSpace` | The URI of the namespace definition. Value MUST be in the form of an absolute URI. | | prefix | `string` | `-XmlPrefix` | The prefix to be used for the [name](#xmlName). | @@ -3832,7 +3832,7 @@ Supported schemes are HTTP authentication, an API key (either as a header, a coo ##### Fixed Fields | Field Name | Type | Applies To | Description | -| ------------------------------------------------------------- | :-------------------------------------: | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|---------------------------------------------------------------|:---------------------------------------:|---------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | type | `string` | Any | **REQUIRED**. The type of the security scheme. Valid values are `"apiKey"`, `"http"`, `"oauth2"`, `"openIdConnect"`. | | description | `string` | Any | A short description for security scheme. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation. | | name | `string` | `apiKey` | **REQUIRED**. The name of the header, query or cookie parameter to be used. | @@ -3962,7 +3962,7 @@ Allows configuration of the supported OAuth Flows. ##### Fixed Fields | Field Name | Type | Description | -| ----------------------------------------------------------- | :-----------------------------------: | ----------------------------------------------------------------------------------------------------- | +|-------------------------------------------------------------|:-------------------------------------:|-------------------------------------------------------------------------------------------------------| | implicit | [OAuth Flow Object](#oauthFlowObject) | Configuration for the OAuth Implicit flow | | password | [OAuth Flow Object](#oauthFlowObject) | Configuration for the OAuth Resource Owner Password flow | | clientCredentials | [OAuth Flow Object](#oauthFlowObject) | Configuration for the OAuth Client Credentials flow. Previously called `application` in OpenAPI 2.0. | @@ -3976,7 +3976,7 @@ Configuration details for a supported OAuth Flow ##### Fixed Fields | Field Name | Type | Applies To | Description | -| -------------------------------------------------------- | :---------------------: | --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +|----------------------------------------------------------|:-----------------------:|-----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| | authorizationUrl | `string` | `oauth2` (`"implicit"`, `"authorizationCode"`) | **REQUIRED**. The authorization URL to be used for this flow. This MUST be in the form of a URL. | | tokenUrl | `string` | `oauth2` (`"password"`, `"clientCredentials"`, `"authorizationCode"`) | **REQUIRED**. The token URL to be used for this flow. This MUST be in the form of a URL. | | refreshUrl | `string` | `oauth2` | The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL. | @@ -4038,7 +4038,7 @@ When a list of Security Requirement Objects is defined on the [OpenAPI Object](# ##### Patterned Fields | Field Pattern | Type | Description | -| --------------------------------------------- | :--------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------------------------------|:----------:|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | {name} | [`string`] | Each name MUST correspond to a security scheme which is declared in the [Security Schemes](#componentsSecuritySchemes) under the [Components Object](#componentsObject). If the security scheme is of type `"oauth2"` or `"openIdConnect"`, then the value is a list of scope names required for the execution, and the list MAY be empty if authorization does not require a specified scope. For other security scheme types, the array MUST be empty. | ##### Security Requirement Object Examples @@ -4227,9 +4227,9 @@ While the OpenAPI Specification tries to accommodate most use cases, additional The extensions properties are implemented as patterned fields that are always prefixed by `"x-"`. -| Field Pattern | Type | Description | -| -------------------------------- | :---: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ^x- | Any | Allows extensions to the OpenAPI Schema. The field name MUST begin with `x-`, for example, `x-internal-id`. The value can be `null`, a primitive, an array or an object. Can have any valid JSON format value. | +| Field Pattern | Type | Description | +|----------------------------------|:----:|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ^x- | Any | Allows extensions to the OpenAPI Schema. The field name MUST begin with `x-`, for example, `x-internal-id`. The value can be `null`, a primitive, an array or an object. Can have any valid JSON format value. | The extensions may or may not be supported by the available tooling, but those may be extended as well to add requested support (if tools are internal or open-sourced). @@ -4248,7 +4248,7 @@ Two examples of this: ## Appendix A: Revision History | Version | Date | Notes | -| ---------- | ---------- | ------------------------------------------------- | +|------------|------------|---------------------------------------------------| | 3.0.3-Pode | 2023-11-20 | OpenAPI Specification 3.0.3 Pode Version | | 3.0.3 | 2020-02-20 | Patch release of the OpenAPI Specification 3.0.3 | | 3.0.2 | 2018-10-08 | Patch release of the OpenAPI Specification 3.0.2 | diff --git a/examples/OpenApi-TuttiFrutti.ps1 b/examples/OpenApi-TuttiFrutti.ps1 index b880fff00..9b0c91e1e 100644 --- a/examples/OpenApi-TuttiFrutti.ps1 +++ b/examples/OpenApi-TuttiFrutti.ps1 @@ -390,10 +390,10 @@ Some useful links: Merge-PodeAuth -Name 'test' -Authentication 'Login-OAuth2', 'api_key' $ex = - New-PodeOAExample -MediaType 'application/json' -Name 'user' -Summary 'User Example' -ExternalValue 'http://foo.bar/examples/user-example.json' | - New-PodeOAExample -MediaType 'application/xml' -Name 'user' -Summary 'User Example in XML' -ExternalValue 'http://foo.bar/examples/user-example.xml' | - New-PodeOAExample -MediaType 'text/plain' -Name 'user' -Summary 'User Example in Plain text' -ExternalValue 'http://foo.bar/examples/user-example.txt' | - New-PodeOAExample -MediaType '*/*' -Name 'user' -Summary 'User example in other forma' -ExternalValue 'http://foo.bar/examples/user-example.whatever' + New-PodeOAExample -ContentType 'application/json' -Name 'user' -Summary 'User Example' -ExternalValue 'http://foo.bar/examples/user-example.json' | + New-PodeOAExample -ContentType 'application/xml' -Name 'user' -Summary 'User Example in XML' -ExternalValue 'http://foo.bar/examples/user-example.xml' | + New-PodeOAExample -ContentType 'text/plain' -Name 'user' -Summary 'User Example in Plain text' -ExternalValue 'http://foo.bar/examples/user-example.txt' | + New-PodeOAExample -ContentType '*/*' -Name 'user' -Summary 'User example in other forma' -ExternalValue 'http://foo.bar/examples/user-example.whatever' Select-PodeOADefinition -Tag 'v3' -Scriptblock { Add-PodeRouteGroup -Path '/api/v4' -Routes { @@ -448,7 +448,7 @@ Some useful links: Set-PodeOARequest -PassThru -Parameters ( New-PodeOAIntProperty -Name 'petId' -Description 'ID of pet to return' -Format Int64 | ConvertTo-PodeOAParameter -In Path -Required ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet') -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet') -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'Pet not found' -PassThru | Add-PodeOAResponse -StatusCode 415 @@ -478,10 +478,10 @@ Some useful links: $ex = - New-PodeOAExample -MediaType 'application/json' -Name 'user' -Summary 'User Example' -ExternalValue 'http://foo.bar/examples/user-example.json' | - New-PodeOAExample -MediaType 'application/xml' -Name 'user' -Summary 'User Example in XML' -ExternalValue 'http://foo.bar/examples/user-example.xml' | - New-PodeOAExample -MediaType 'text/plain' -Name 'user' -Summary 'User Example in Plain text' -ExternalValue 'http://foo.bar/examples/user-example.txt' | - New-PodeOAExample -MediaType '*/*' -Name 'user' -Summary 'User example in other forma' -ExternalValue 'http://foo.bar/examples/user-example.whatever' + New-PodeOAExample -ContentType 'application/json' -Name 'user' -Summary 'User Example' -ExternalValue 'http://foo.bar/examples/user-example.json' | + New-PodeOAExample -ContentType 'application/xml' -Name 'user' -Summary 'User Example in XML' -ExternalValue 'http://foo.bar/examples/user-example.xml' | + New-PodeOAExample -ContentType 'text/plain' -Name 'user' -Summary 'User Example in Plain text' -ExternalValue 'http://foo.bar/examples/user-example.txt' | + New-PodeOAExample -ContentType '*/*' -Name 'user' -Summary 'User example in other forma' -ExternalValue 'http://foo.bar/examples/user-example.whatever' Add-PodeOAComponentExample -name 'frog-example' -Summary "An example of a frog with a cat's name" -Value @{name = 'Jaguar'; petType = 'Panthera'; color = 'Lion'; gender = 'Male'; breed = 'Mantella Baroni' } @@ -497,9 +497,9 @@ Some useful links: Set-PodeOARequest -Parameters @( (New-PodeOAStringProperty -Name 'petId' -Description 'ID of pet that needs to be updated' | ConvertTo-PodeOAParameter -In Path -Required) ) -RequestBody (New-PodeOARequestBody -Description 'user to add to the system' -Content @{ 'application/json' = 'NewCat' } -Examples ( - New-PodeOAExample -MediaType 'application/json' -Name 'cat' -Summary 'An example of a cat' -Value @{name = 'Fluffy'; petType = 'Cat'; color = 'White'; gender = 'male'; breed = 'Persian' } | - New-PodeOAExample -MediaType 'application/json' -Name 'dog' -Summary "An example of a dog with a cat's name" -Value @{name = 'Puma'; petType = 'Dog'; color = 'Black'; gender = 'Female'; breed = 'Mixed' } | - New-PodeOAExample -MediaType 'application/json' -Reference 'frog-example' + New-PodeOAExample -ContentType 'application/json' -Name 'cat' -Summary 'An example of a cat' -Value @{name = 'Fluffy'; petType = 'Cat'; color = 'White'; gender = 'male'; breed = 'Persian' } | + New-PodeOAExample -ContentType 'application/json' -Name 'dog' -Summary "An example of a dog with a cat's name" -Value @{name = 'Puma'; petType = 'Dog'; color = 'Black'; gender = 'Female'; breed = 'Mixed' } | + New-PodeOAExample -ContentType 'application/json' -Reference 'frog-example' ) ) -PassThru | Add-PodeOAResponse -StatusCode 200 -Description 'Pet updated.' -Content (@{ 'application/json' = '' ; 'application/xml' = '' }) -PassThru | @@ -518,13 +518,13 @@ Some useful links: Set-PodeOARequest -Parameters @( (New-PodeOAStringProperty -Name 'petId' -Description 'ID of pet that needs to be updated' | ConvertTo-PodeOAParameter -In Path -Required -ContentType 'application/json') ) -RequestBody (New-PodeOARequestBody -Description 'user to add to the system' -Content @{ 'application/json' = 'Pet' } -Examples ( - New-PodeOAExample -MediaType 'application/json' -Name 'cat' -Summary 'An example of a cat' -Value @{name = 'Fluffy'; petType = 'Cat'; color = 'White'; gender = 'male'; breed = 'Persian' } | - New-PodeOAExample -MediaType 'application/json' -Name 'dog' -Summary "An example of a dog with a cat's name" -Value @{name = 'Puma'; petType = 'Dog'; color = 'Black'; gender = 'Female'; breed = 'Mixed' } | - New-PodeOAExample -MediaType 'application/json' -Reference 'frog-example' + New-PodeOAExample -ContentType 'application/json' -Name 'cat' -Summary 'An example of a cat' -Value @{name = 'Fluffy'; petType = 'Cat'; color = 'White'; gender = 'male'; breed = 'Persian' } | + New-PodeOAExample -ContentType 'application/json' -Name 'dog' -Summary "An example of a dog with a cat's name" -Value @{name = 'Puma'; petType = 'Dog'; color = 'Black'; gender = 'Female'; breed = 'Mixed' } | + New-PodeOAExample -ContentType 'application/json' -Reference 'frog-example' ) ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Pet updated.' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content '') -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Pet updated.' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content '') -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Method Not Allowed' -Content (@{ 'application/json' = '' ; 'application/xml' = '' }) } @@ -549,7 +549,7 @@ Some useful links: } } | Set-PodeOARouteInfo -Summary 'Update an existing pet' -Description 'Update an existing pet by Id' -Tags 'pet' -OperationId 'updatePet' -PassThru | Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Reference 'PetBodySchema' ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'Pet not found' -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Validation exception' -Content @{ @@ -573,7 +573,7 @@ Some useful links: } } | Set-PodeOARouteInfo -Summary 'Add a new pet to the store' -Description 'Add a new pet to the store' -Tags 'pet' -OperationId 'addPet' -PassThru | Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Reference 'PetBodySchema' ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Validation exception' -Content @{ 'application/json' = (New-PodeOAObjectProperty -Properties @((New-PodeOAStringProperty -Name 'result'), (New-PodeOAStringProperty -Name 'message'))) } @@ -594,13 +594,13 @@ Some useful links: } } | Set-PodeOARouteInfo -Summary 'Add a new pet to the store' -Description 'Add a new pet to the store' -Tags 'pet' -OperationId 'addPetcallback' -PassThru | Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Reference 'PetBodySchema' ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Validation exception' -Content @{ 'application/json' = (New-PodeOAObjectProperty -Properties @((New-PodeOAStringProperty -Name 'result'), (New-PodeOAStringProperty -Name 'message'))) } -PassThru | Add-PodeOACallBack -Name 'test' -Path '{$request.body#/id}' -Method Post -RequestBody (New-PodeOARequestBody -Content @{'*/*' = (New-PodeOAStringProperty -Name 'id') } ) ` -Response ( - New-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' -Array) | + New-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' -Array) | New-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' | New-PodeOAResponse -StatusCode 404 -Description 'Pet not found' | New-PodeOAResponse -Default -Description 'Something is wrong' @@ -610,7 +610,7 @@ Some useful links: Add-PodeOAComponentCallBack -Name 'test' -Path '{$request.body#/id}' -Method Post -RequestBody (New-PodeOARequestBody -Content @{'*/*' = (New-PodeOAStringProperty -Name 'id') } ) ` -Response ( - New-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' -Array) | + New-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' -Array) | New-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' | New-PodeOAResponse -StatusCode 404 -Description 'Pet not found' | New-PodeOAResponse -Default -Description 'Something is wrong' @@ -633,7 +633,7 @@ Some useful links: } } | Set-PodeOARouteInfo -Summary 'Add a new pet to the store' -Description 'Add a new pet to the store' -Tags 'pet' -OperationId 'petcallbackReference' -PassThru | Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Reference 'PetBodySchema' ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Validation exception' -Content @{ 'application/json' = ( New-PodeOAStringProperty -Name 'result' | New-PodeOAStringProperty -Name 'message' | New-PodeOAObjectProperty ) } -PassThru | @@ -646,7 +646,7 @@ Some useful links: Set-PodeOARequest -PassThru -Parameters @( ( New-PodeOAStringProperty -Name 'status' -Description 'Status values that need to be considered for filter' -Default 'available' -Enum @('available', 'pending', 'sold') | ConvertTo-PodeOAParameter -In Query ) ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' -Array) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' -Array) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid status value' @@ -663,13 +663,13 @@ Some useful links: Set-PodeOARequest -PassThru -Parameters @( ( New-PodeOAStringProperty -Name 'tag' -Description 'Tags to filter by' -Array | ConvertTo-PodeOAParameter -In Query -Explode) ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | #missing array application/json: + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | #missing array application/json: # schema: # type: array # items: # $ref: '#/components/schemas/Pet' Add-PodeOAResponse -StatusCode 400 -Description 'Invalid status value' -PassThru | - Add-PodeOAResponse -Default -Description 'Unexpected error' -Content (New-PodeOAContentMediaType -MediaType 'application/json' -Content 'ErrorModel' ) + Add-PodeOAResponse -Default -Description 'Unexpected error' -Content (New-PodeOAContentMediaType -ContentType 'application/json' -Content 'ErrorModel' ) Add-PodeRoute -PassThru -Method Get -Path '/pet/:petId' -Authentication 'Login-OAuth2' -Scope 'read' -ScriptBlock { Write-PodeJsonResponse -Value 'done' -StatusCode 200 @@ -745,7 +745,7 @@ Some useful links: New-PodeOAIntProperty -Name 'X-Rate-Limit-Reset' -Description 'The number of seconds left in the current period' -Minimum 2 ) ) - ) | Add-PodeOAResponse -StatusCode 200 -PassThru -Description 'A simple string response' -Content ( New-PodeOAContentMediaType -MediaType 'text/plain' -Content ( New-PodeOAStringProperty)) | + ) | Add-PodeOAResponse -StatusCode 200 -PassThru -Description 'A simple string response' -Content ( New-PodeOAContentMediaType -ContentType 'text/plain' -Content ( New-PodeOAStringProperty)) | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' @@ -759,7 +759,7 @@ Some useful links: ( New-PodeOAStringProperty -Name 'additionalMetadata' -Description 'Additional Metadata' | ConvertTo-PodeOAParameter -In Query ) ) -RequestBody (New-PodeOARequestBody -Required -Content @{ 'multipart/form-data' = New-PodeOAObjectProperty -Properties @( (New-PodeOAStringProperty -Name 'image' -Format Binary )) } ) -PassThru | Add-PodeOAResponse -StatusCode 200 -Description 'A simple string response' -Content ( - New-PodeOAContentMediaType -MediaType 'text/plain' -Content ( New-PodeOAStringProperty -Example 'whoa!')) -Headers ( + New-PodeOAContentMediaType -ContentType 'text/plain' -Content ( New-PodeOAStringProperty -Example 'whoa!')) -Headers ( New-PodeOAIntProperty -Name 'X-Rate-Limit-Limit' -Description 'The number of allowed requests in the current period' | New-PodeOAIntProperty -Name 'X-Rate-Limit-Remaining' -Description 'The number of remaining requests in the current period' | New-PodeOAIntProperty -Name 'X-Rate-Limit-Reset' -Description 'The number of seconds left in the current period' -Maximum 3 @@ -780,7 +780,7 @@ Some useful links: ( New-PodeOAIntProperty -Name 'petId' -Format Int64 -Description 'ID of pet that needs to be updated' -Required | ConvertTo-PodeOAParameter -In Path ), ( New-PodeOAStringProperty -Name 'additionalMetadata' -Description 'Additional Metadata' | ConvertTo-PodeOAParameter -In Query ) ) -RequestBody ( - New-PodeOARequestBody -Required -Content ( New-PodeOAContentMediaType -MediaType 'multipart/form-data' -Upload -PartContentMediaType 'application/octect-stream' -Content ( + New-PodeOARequestBody -Required -Content ( New-PodeOAContentMediaType -ContentType 'multipart/form-data' -Upload -PartContentMediaType 'application/octect-stream' -Content ( New-PodeOAIntProperty -name 'orderId' | New-PodeOAStringProperty -Name 'image' -Format Binary | New-PodeOAObjectProperty )) ) -PassThru | Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content @{'application/json' = 'ApiResponse' } -PassThru | @@ -795,7 +795,7 @@ Some useful links: ( New-PodeOAIntProperty -Name 'petId' -Format Int64 -Description 'ID of pet that needs to be updated' -Required | ConvertTo-PodeOAParameter -In Path ), ( New-PodeOAStringProperty -Name 'additionalMetadata' -Description 'Additional Metadata' | ConvertTo-PodeOAParameter -In Query ) ) -RequestBody ( - New-PodeOARequestBody -Required -Content ( New-PodeOAContentMediaType -MediaType 'application/octet-stream' -Upload ) + New-PodeOARequestBody -Required -Content ( New-PodeOAContentMediaType -ContentType 'application/octet-stream' -Upload ) ) -PassThru | Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content @{'application/json' = 'ApiResponse' } -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' -PassThru | @@ -810,7 +810,7 @@ Some useful links: Add-PodeRoute -PassThru -Method post -Path '/store/order' -ScriptBlock { Write-PodeJsonResponse -Value 'done' -StatusCode 200 } | Set-PodeOARouteInfo -Deprecated -Summary 'Place an order for a pet' -Description 'Place a new order in the store' -Tags 'store' -OperationId 'placeOrder' -PassThru | - Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Required -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'Order' )) -PassThru | + Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Required -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'Order' )) -PassThru | Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (@{ 'application/json' = 'Order' ; 'application/xml' = 'Order' }) -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' @@ -826,7 +826,7 @@ Some useful links: Set-PodeOARequest -PassThru -Parameters @( ( New-PodeOAIntProperty -Name 'orderId' -Format Int64 -Description 'ID of order that needs to be fetched' -Required | ConvertTo-PodeOAParameter -In Path ) ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'Order' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'Order' ) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'Order not found' @@ -856,7 +856,7 @@ Some useful links: } } } | Set-PodeOARouteInfo -Summary 'Create user.' -Description 'This can only be done by the logged in user.' -Tags 'user' -OperationId 'createUser' -PassThru | - Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Required -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | + Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Required -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | Add-PodeOAResponse -StatusCode 200 -Reference 'UserOpSuccess' -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' -Content @{ 'application/json' = (New-PodeOAObjectProperty -Properties @((New-PodeOAStringProperty -Name 'result'), (New-PodeOAStringProperty -Name 'message'))) @@ -865,7 +865,7 @@ Some useful links: Add-PodeRoute -PassThru -Method post -Path '/user/createWithList' -ScriptBlock { Write-PodeJsonResponse -Value 'done' -StatusCode 200 } | Set-PodeOARouteInfo -Summary 'Creates list of users with given input array.' -Description 'Creates list of users with given input array.' -Tags 'user' -OperationId 'createUsersWithListInput' -PassThru | - Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Required -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | + Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Required -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | Add-PodeOAResponse -StatusCode 200 -Reference 'UserOpSuccess' -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' @@ -876,7 +876,7 @@ Some useful links: ( New-PodeOAStringProperty -Name 'username' -Description 'The user name for login' | ConvertTo-PodeOAParameter -In Query ) ( New-PodeOAStringProperty -Name 'password' -Description 'The password for login in clear text' -Format Password | ConvertTo-PodeOAParameter -In Query ) ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'string' ) ` + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'string' ) ` -Header @('X-Rate-Limit', 'X-Expires-After') -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid username/password supplied' @@ -907,7 +907,7 @@ Some useful links: } | Set-PodeOARouteInfo -Summary 'Update user' -Description 'This can only be done by the logged in user.' -Tags 'user' -OperationId 'updateUser_1' -PassThru | Set-PodeOARequest -Parameters @( ( New-PodeOAStringProperty -Name 'username' -Description ' name that need to be updated.' -Required | ConvertTo-PodeOAParameter -In Path ) - ) -RequestBody (New-PodeOARequestBody -Required -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'StructPart' )) + ) -RequestBody (New-PodeOARequestBody -Required -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'StructPart' )) Add-PodeRoute -PassThru -Method Put -Path '/user/:username' -ScriptBlock { @@ -915,7 +915,7 @@ Some useful links: } | Set-PodeOARouteInfo -Summary 'Update user' -Description 'This can only be done by the logged in user.' -Tags 'user' -OperationId 'updateUser' -PassThru | Set-PodeOARequest -Parameters @( ( New-PodeOAStringProperty -Name 'username' -Description ' name that need to be updated.' -Required | ConvertTo-PodeOAParameter -In Path ) - ) -RequestBody (New-PodeOARequestBody -Required -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | + ) -RequestBody (New-PodeOARequestBody -Required -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | Add-PodeOAResponse -StatusCode 200 -Reference 'UserOpSuccess' -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid username supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'User not found' -PassThru | @@ -928,7 +928,7 @@ Some useful links: } | Set-PodeOARouteInfo -Summary 'Update user' -Description 'This can only be done by the logged in user.' -Tags 'user' -OperationId 'updateUserLink' -PassThru | Set-PodeOARequest -Parameters @( ( New-PodeOAStringProperty -Name 'username' -Description ' name that need to be updated.' -Required | ConvertTo-PodeOAParameter -In Path ) - ) -RequestBody (New-PodeOARequestBody -Required -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | + ) -RequestBody (New-PodeOARequestBody -Required -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | Add-PodeOAResponse -StatusCode 200 -Content @{'application/json' = 'User' } -PassThru ` -Links (New-PodeOAResponseLink -Name address -OperationId 'getUserByName' -Parameters @{'username' = '$request.path.username' } ) | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid username supplied' -PassThru | @@ -944,7 +944,7 @@ Some useful links: } | Set-PodeOARouteInfo -Summary 'Update user' -Description 'This can only be done by the logged in user.' -Tags 'user' -OperationId 'updateUserLinkByRef' -PassThru | Set-PodeOARequest -Parameters @( ( New-PodeOAStringProperty -Name 'username' -Description ' name that need to be updated.' -Required | ConvertTo-PodeOAParameter -In Path ) - ) -RequestBody (New-PodeOARequestBody -Required -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | + ) -RequestBody (New-PodeOARequestBody -Required -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | Add-PodeOAResponse -StatusCode 200 -Content @{'application/json' = 'User' } -PassThru ` -Links (New-PodeOAResponseLink -Name 'address2' -Reference 'address' ) | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid username supplied' -PassThru | @@ -987,7 +987,7 @@ Some useful links: Set-PodeOARequest -PassThru -Parameters @( ( New-PodeOAIntProperty -Name 'orderId' -Format Int64 -Description 'ID of order that needs to be fetched' -Required | ConvertTo-PodeOAParameter -In Path ) ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'Order' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'Order' ) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'Order not found' } diff --git a/examples/PetStore/Petstore-OpenApi.ps1 b/examples/PetStore/Petstore-OpenApi.ps1 index d908b6e62..6ee32927b 100644 --- a/examples/PetStore/Petstore-OpenApi.ps1 +++ b/examples/PetStore/Petstore-OpenApi.ps1 @@ -294,10 +294,10 @@ Some useful links: # Add OpenAPI component request bodies Add-PodeOAComponentRequestBody -Name 'Pet' -Description 'Pet object that needs to be added to the store' -Content ( - New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet') + New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet') Add-PodeOAComponentRequestBody -Name 'UserArray' -Description 'List of user object' -Content ( - New-PodeOAContentMediaType -MediaType 'application/json' -Content 'User' -Array) + New-PodeOAContentMediaType -ContentType 'application/json' -Content 'User' -Array) @@ -343,9 +343,9 @@ Some useful links: } | Set-PodeOARouteInfo -Summary 'Update an existing pet' -Description 'Update an existing pet by Id' -Tags 'pet' -OperationId 'updatePet' -PassThru | Set-PodeOARequest -RequestBody ( New-PodeOARequestBody -Description 'Update an existent pet in the store' -Required -Content ( - New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' ) + New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'Pet not found' -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Validation exception' @@ -381,9 +381,9 @@ Some useful links: } } | Set-PodeOARouteInfo -Summary 'Add a new pet to the store' -Description 'Add a new pet to the store' -Tags 'pet' -OperationId 'addPet' -PassThru | Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Description 'Create a new pet in the store' -Required -Content ( - New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' ) + New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid input' @@ -412,7 +412,7 @@ Some useful links: Set-PodeOARequest -PassThru -Parameters ( New-PodeOAStringProperty -Name 'status' -Description 'Status values that need to be considered for filter' -Default 'available' -Enum @('available', 'pending', 'sold') | ConvertTo-PodeOAParameter -In Query -Explode ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' -Array) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' -Array) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid status value' -PassThru | Add-PodeOAResponse -StatusCode 415 @@ -440,7 +440,7 @@ Some useful links: Set-PodeOARequest -PassThru -Parameters ( New-PodeOAStringProperty -Name 'tags' -Description 'Tags to filter by' -Array | ConvertTo-PodeOAParameter -In Query -Explode ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' -Array) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' -Array) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid tag value' -PassThru | Add-PodeOAResponse -StatusCode 415 @@ -473,7 +473,7 @@ Some useful links: Set-PodeOARequest -PassThru -Parameters ( New-PodeOAIntProperty -Name 'petId' -Description 'ID of pet to return' -Format Int64 | ConvertTo-PodeOAParameter -In Path -Required ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet') -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet') -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'Pet not found' -PassThru | Add-PodeOAResponse -StatusCode 415 @@ -550,7 +550,7 @@ Some useful links: ( New-PodeOAIntProperty -Name 'petId' -Format Int64 -Description 'ID of pet to update' -Required | ConvertTo-PodeOAParameter -In Path ), ( New-PodeOAStringProperty -Name 'additionalMetadata' -Description 'Additional Metadata' | ConvertTo-PodeOAParameter -In Query ) ) -RequestBody ( - New-PodeOARequestBody -Content ( New-PodeOAContentMediaType -MediaType 'application/octet-stream' -Upload ) + New-PodeOARequestBody -Content ( New-PodeOAContentMediaType -ContentType 'application/octet-stream' -Upload ) ) -PassThru | Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content @{'application/json' = 'ApiResponse' } @@ -598,7 +598,7 @@ Some useful links: Write-PodeHtmlResponse -StatusCode 405 -Value ($Validate.message -join ', ') } } | Set-PodeOARouteInfo -Summary 'Place an order for a pet' -Description 'Place a new order in the store' -Tags 'store' -OperationId 'placeOrder' -PassThru | - Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'Order' )) -PassThru | + Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'Order' )) -PassThru | Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (@{ 'application/json' = 'Order' }) -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' @@ -628,7 +628,7 @@ Some useful links: Set-PodeOARequest -PassThru -Parameters @( ( New-PodeOAIntProperty -Name 'orderId' -Format Int64 -Description 'ID of order that needs to be fetched' -Required | ConvertTo-PodeOAParameter -In Path ) ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Order' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Order' ) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'Order not found' @@ -696,9 +696,9 @@ Some useful links: Write-PodeHtmlResponse -StatusCode 405 -Value ($Validate.message -join ', ') } } | Set-PodeOARouteInfo -Summary 'Create user.' -Description 'This can only be done by the logged in user.' -Tags 'user' -OperationId 'createUser' -PassThru | - Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | + Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' -PassThru | - Add-PodeOAResponse -Default -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'User' ) + Add-PodeOAResponse -Default -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'User' ) <# @@ -742,8 +742,8 @@ Some useful links: default { Write-PodeHtmlResponse -StatusCode 415 } } } | Set-PodeOARouteInfo -Summary 'Creates list of users with given input array.' -Description 'Creates list of users with given input array.' -Tags 'user' -OperationId 'createUsersWithListInput' -PassThru | - Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -MediaType 'application/json' -Content 'User' -Array)) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'User' -Array ) -PassThru | + Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -ContentType 'application/json' -Content 'User' -Array)) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'User' -Array ) -PassThru | Add-PodeOAResponse -Default -Description 'successful operation' @@ -776,7 +776,7 @@ Some useful links: } | Set-PodeOARouteInfo -Summary 'Logs user into the system.' -Tags 'user' -OperationId 'loginUser' -PassThru | Set-PodeOARequest -Parameters ( New-PodeOAStringProperty -Name 'username' -Description 'The user name for login' | ConvertTo-PodeOAParameter -In Query ), ( New-PodeOAStringProperty -Name 'password' -Description 'The password for login in clear text' -Format Password | ConvertTo-PodeOAParameter -In Query ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'string' ) ` + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'string' ) ` -Headers (New-PodeOAIntProperty -Name 'X-Rate-Limit' -Description 'calls per hour allowed by the user' -Format Int32), (New-PodeOAStringProperty -Name 'X-Expires-After' -Description 'date in UTC when token expires' -Format Date-Time) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid username/password supplied' @@ -814,7 +814,7 @@ Some useful links: } } | Set-PodeOARouteInfo -Summary 'Get user by user name' -Tags 'user' -OperationId 'getUserByName' -PassThru | Set-PodeOARequest -Parameters ( New-PodeOAStringProperty -Name 'username' -Description 'The name that needs to be fetched. Use user1 for testing.' -Required | ConvertTo-PodeOAParameter -In Path ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'User' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'User' ) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid username supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'User not found' @@ -863,7 +863,7 @@ Some useful links: } | Set-PodeOARouteInfo -Summary 'Update user' -Description 'This can only be done by the logged in user.' -Tags 'user' -OperationId 'updateUser' -PassThru | Set-PodeOARequest -Parameters ( New-PodeOAStringProperty -Name 'username' -Description ' name that need to be updated.' -Required | ConvertTo-PodeOAParameter -In Path ) ` -RequestBody ( New-PodeOARequestBody -Required -Description 'Update an existent user in the store' -Content ( - New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' + New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'User not found' -PassThru | diff --git a/examples/PetStore/Petstore-OpenApiMultiTag.ps1 b/examples/PetStore/Petstore-OpenApiMultiTag.ps1 index d0eafc33a..c3a351f48 100644 --- a/examples/PetStore/Petstore-OpenApiMultiTag.ps1 +++ b/examples/PetStore/Petstore-OpenApiMultiTag.ps1 @@ -293,10 +293,10 @@ Some useful links: Add-PodeOAComponentSchema -Name 'ApiResponse' - New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' | Add-PodeOAComponentRequestBody -Name 'Pet' -Description 'Pet object that needs to be added to the store' + New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' | Add-PodeOAComponentRequestBody -Name 'Pet' -Description 'Pet object that needs to be added to the store' Add-PodeOAComponentRequestBody -Name 'UserArray' -Description 'List of user object' -Content ( - New-PodeOAContentMediaType -MediaType 'application/json' -Content 'User' -Array) + New-PodeOAContentMediaType -ContentType 'application/json' -Content 'User' -Array) @@ -342,9 +342,9 @@ Some useful links: } | Set-PodeOARouteInfo -Summary 'Update an existing pet' -Description 'Update an existing pet by Id' -Tags 'pet' -OperationId 'updatePet' -PassThru | Set-PodeOARequest -RequestBody ( New-PodeOARequestBody -Description 'Update an existent pet in the store' -Required -Content ( - New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' ) + New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'Pet not found' -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Validation exception' @@ -380,9 +380,9 @@ Some useful links: } } | Set-PodeOARouteInfo -Summary 'Add a new pet to the store' -Description 'Add a new pet to the store' -Tags 'pet' -OperationId 'addPet' -PassThru | Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Description 'Create a new pet in the store' -Required -Content ( - New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' ) + New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid input' @@ -411,7 +411,7 @@ Some useful links: Set-PodeOARequest -PassThru -Parameters ( New-PodeOAStringProperty -Name 'status' -Description 'Status values that need to be considered for filter' -Default 'available' -Enum @('available', 'pending', 'sold') | ConvertTo-PodeOAParameter -In Query -Explode ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' -Array) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' -Array) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid status value' -PassThru | Add-PodeOAResponse -StatusCode 415 @@ -439,7 +439,7 @@ Some useful links: Set-PodeOARequest -PassThru -Parameters ( New-PodeOAStringProperty -Name 'tags' -Description 'Tags to filter by' -Array | ConvertTo-PodeOAParameter -In Query -Explode ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' -Array) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' -Array) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid tag value' -PassThru | Add-PodeOAResponse -StatusCode 415 @@ -472,7 +472,7 @@ Some useful links: Set-PodeOARequest -PassThru -Parameters ( New-PodeOAIntProperty -Name 'petId' -Description 'ID of pet to return' -Format Int64 | ConvertTo-PodeOAParameter -In Path -Required ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet') -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet') -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'Pet not found' -PassThru | Add-PodeOAResponse -StatusCode 415 @@ -549,7 +549,7 @@ Some useful links: ( New-PodeOAIntProperty -Name 'petId' -Format Int64 -Description 'ID of pet to update' -Required | ConvertTo-PodeOAParameter -In Path ), ( New-PodeOAStringProperty -Name 'additionalMetadata' -Description 'Additional Metadata' | ConvertTo-PodeOAParameter -In Query ) ) -RequestBody ( - New-PodeOARequestBody -Content ( New-PodeOAContentMediaType -MediaType 'application/octet-stream' -Upload ) + New-PodeOARequestBody -Content ( New-PodeOAContentMediaType -ContentType 'application/octet-stream' -Upload ) ) -PassThru | Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content @{'application/json' = 'ApiResponse' } @@ -597,7 +597,7 @@ Some useful links: Write-PodeHtmlResponse -StatusCode 405 -Value ($Validate.message -join ', ') } } | Set-PodeOARouteInfo -Summary 'Place an order for a pet' -Description 'Place a new order in the store' -Tags 'store' -OperationId 'placeOrder' -PassThru | - Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'Order' )) -PassThru | + Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'Order' )) -PassThru | Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (@{ 'application/json' = 'Order' }) -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' @@ -627,7 +627,7 @@ Some useful links: Set-PodeOARequest -PassThru -Parameters @( ( New-PodeOAIntProperty -Name 'orderId' -Format Int64 -Description 'ID of order that needs to be fetched' -Required | ConvertTo-PodeOAParameter -In Path ) ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Order' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Order' ) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'Order not found' @@ -695,9 +695,9 @@ Some useful links: Write-PodeHtmlResponse -StatusCode 405 -Value ($Validate.message -join ', ') } } | Set-PodeOARouteInfo -Summary 'Create user.' -Description 'This can only be done by the logged in user.' -Tags 'user' -OperationId 'createUser' -PassThru | - Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | + Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' -PassThru | - Add-PodeOAResponse -Default -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'User' ) + Add-PodeOAResponse -Default -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'User' ) <# @@ -741,8 +741,8 @@ Some useful links: default { Write-PodeHtmlResponse -StatusCode 415 } } } | Set-PodeOARouteInfo -Summary 'Creates list of users with given input array.' -Description 'Creates list of users with given input array.' -Tags 'user' -OperationId 'createUsersWithListInput' -PassThru | - Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -MediaType 'application/json' -Content 'User' -Array)) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'User' -Array ) -PassThru | + Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -ContentType 'application/json' -Content 'User' -Array)) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'User' -Array ) -PassThru | Add-PodeOAResponse -Default -Description 'successful operation' @@ -775,7 +775,7 @@ Some useful links: } | Set-PodeOARouteInfo -Summary 'Logs user into the system.' -Tags 'user' -OperationId 'loginUser' -PassThru | Set-PodeOARequest -Parameters ( New-PodeOAStringProperty -Name 'username' -Description 'The user name for login' | ConvertTo-PodeOAParameter -In Query ), ( New-PodeOAStringProperty -Name 'password' -Description 'The password for login in clear text' -Format Password | ConvertTo-PodeOAParameter -In Query ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'string' ) ` + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'string' ) ` -Headers (New-PodeOAIntProperty -Name 'X-Rate-Limit' -Description 'calls per hour allowed by the user' -Format Int32), (New-PodeOAStringProperty -Name 'X-Expires-After' -Description 'date in UTC when token expires' -Format Date-Time) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid username/password supplied' @@ -813,7 +813,7 @@ Some useful links: } } | Set-PodeOARouteInfo -Summary 'Get user by user name' -Tags 'user' -OperationId 'getUserByName' -PassThru | Set-PodeOARequest -Parameters ( New-PodeOAStringProperty -Name 'username' -Description 'The name that needs to be fetched. Use user1 for testing.' -Required | ConvertTo-PodeOAParameter -In Path ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'User' ) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'User' ) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid username supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'User not found' @@ -862,7 +862,7 @@ Some useful links: } | Set-PodeOARouteInfo -Summary 'Update user' -Description 'This can only be done by the logged in user.' -Tags 'user' -OperationId 'updateUser' -PassThru | Set-PodeOARequest -Parameters ( New-PodeOAStringProperty -Name 'username' -Description ' name that need to be updated.' -Required | ConvertTo-PodeOAParameter -In Path ) ` -RequestBody ( New-PodeOARequestBody -Required -Description 'Update an existent user in the store' -Content ( - New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' + New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'User not found' -PassThru | diff --git a/src/Public/OAComponents.ps1 b/src/Public/OAComponents.ps1 index b0ccca20c..6d6aa4ed1 100644 --- a/src/Public/OAComponents.ps1 +++ b/src/Public/OAComponents.ps1 @@ -604,7 +604,7 @@ You can use this tag to reference the specific API documentation, schema, or ver Add-PodeOAComponentCallBack -Title 'test' -Path '{$request.body#/id}' -Method Post ` -RequestBody (New-PodeOARequestBody -Content @{'*/*' = (New-PodeOAStringProperty -Name 'id')}) ` -Response ( - New-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentMediaType 'application/json','application/xml' -Content 'Pet' -Array) + New-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json','application/xml' -Content 'Pet' -Array) New-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' | New-PodeOAResponse -StatusCode 404 -Description 'Pet not found' | New-PodeOAResponse -Default -Description 'Something is wrong' diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index 77dd0a4d4..22f7dfef8 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -2237,50 +2237,50 @@ function Add-PodeOAInfo { <# .SYNOPSIS -Creates a new OpenAPI example. + Creates a new OpenAPI example. .DESCRIPTION -Creates a new OpenAPI example. + Creates a new OpenAPI example. -.PARAMETER ParamsList -Used to pipeline multiple properties + .PARAMETER ParamsList + Used to pipeline multiple properties -.PARAMETER MediaType -The Media Type associated with the Example. +.PARAMETER ContentType + The Media Content Type associated with the Example. + + Alias: MediaType .PARAMETER Name -The Name of the Example. + The Name of the Example. .PARAMETER Summary -Short description for the example + Short description for the example - -.PARAMETER Description -Long description for the example. + .PARAMETER Description + Long description for the example. .PARAMETER Reference -A reference to a reusable component example + A reference to a reusable component example .PARAMETER Value -Embedded literal example. The value Parameter and ExternalValue parameter are mutually exclusive. -To represent examples of media types that cannot naturally represented in JSON or YAML, use a string value to contain the example, escaping where necessary. + Embedded literal example. The value Parameter and ExternalValue parameter are mutually exclusive. + To represent examples of media types that cannot naturally represented in JSON or YAML, use a string value to contain the example, escaping where necessary. .PARAMETER ExternalValue -A URL that points to the literal example. This provides the capability to reference examples that cannot easily be included in JSON or YAML documents. -The -Value parameter and -ExternalValue parameter are mutually exclusive. | + A URL that points to the literal example. This provides the capability to reference examples that cannot easily be included in JSON or YAML documents. + The -Value parameter and -ExternalValue parameter are mutually exclusive. | .PARAMETER DefinitionTag -An Array of strings representing the unique tag for the API specification. -This tag helps distinguish between different versions or types of API specifications within the application. -You can use this tag to reference the specific API documentation, schema, or version that your function interacts with. + An Array of strings representing the unique tag for the API specification. + This tag helps distinguish between different versions or types of API specifications within the application. + You can use this tag to reference the specific API documentation, schema, or version that your function interacts with. .EXAMPLE -New-PodeOAExample -ContentMediaType 'text/plain' -Name 'user' -Summary = 'User Example in Plain text' -ExternalValue = 'http://foo.bar/examples/user-example.txt' + New-PodeOAExample -ContentType 'text/plain' -Name 'user' -Summary = 'User Example in Plain text' -ExternalValue = 'http://foo.bar/examples/user-example.txt' .EXAMPLE -$example = - New-PodeOAExample -ContentMediaType 'application/json' -Name 'user' -Summary = 'User Example' -ExternalValue = 'http://foo.bar/examples/user-example.json' | - New-PodeOAExample -ContentMediaType 'application/xml' -Name 'user' -Summary = 'User Example in XML' -ExternalValue = 'http://foo.bar/examples/user-example.xml' - + $example = + New-PodeOAExample -ContentType 'application/json' -Name 'user' -Summary = 'User Example' -ExternalValue = 'http://foo.bar/examples/user-example.json' | + New-PodeOAExample -ContentType 'application/xml' -Name 'user' -Summary = 'User Example in XML' -ExternalValue = 'http://foo.bar/examples/user-example.xml' #> function New-PodeOAExample { [CmdletBinding(DefaultParameterSetName = 'Inbuilt')] @@ -2292,8 +2292,10 @@ function New-PodeOAExample { [System.Collections.Specialized.OrderedDictionary ] $ParamsList, + [Parameter()] + [Alias('MediaType')] [string] - $MediaType, + $ContentType, [Parameter(Mandatory = $true, ParameterSetName = 'Inbuilt')] [ValidatePattern('^[a-zA-Z0-9\.\-_]+$')] @@ -2359,8 +2361,8 @@ function New-PodeOAExample { } } $param = [ordered]@{} - if ($MediaType) { - $param.$MediaType = [ordered]@{ + if ($ContentType) { + $param.$ContentType = [ordered]@{ $Name = $Example } } @@ -2548,7 +2550,7 @@ If supplied, the route passed in will be returned for further chaining. Add-PodeOACallBack -Title 'test' -Path '{$request.body#/id}' -Method Post ` -RequestBody (New-PodeOARequestBody -Content @{'*/*' = (New-PodeOAStringProperty -Name 'id')}) ` -Response ( - New-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentMediaType 'application/json','application/xml' -Content 'Pet' -Array) + New-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json','application/xml' -Content 'Pet' -Array) New-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' | New-PodeOAResponse -StatusCode 404 -Description 'Pet not found' | New-PodeOAResponse -Default -Description 'Something is wrong' @@ -2683,7 +2685,7 @@ This tag helps distinguish between different versions or types of API specificat You can use this tag to reference the specific API documentation, schema, or version that your function interacts with. .EXAMPLE -New-PodeOAResponse -StatusCode 200 -Content ( New-PodeOAContentMediaType -ContentMediaType 'application/json' -Content(New-PodeOAIntProperty -Name 'userId' -Object) ) +New-PodeOAResponse -StatusCode 200 -Content ( New-PodeOAContentMediaType -ContentType 'application/json' -Content(New-PodeOAIntProperty -Name 'userId' -Object) ) .EXAMPLE New-PodeOAResponse -StatusCode 200 -Content @{ 'application/json' = 'UserIdSchema' } @@ -2693,10 +2695,10 @@ New-PodeOAResponse -StatusCode 200 -Reference 'OKResponse' .EXAMPLE Add-PodeOACallBack -Title 'test' -Path '$request.body#/id' -Method Post -RequestBody ( - New-PodeOARequestBody -Content (New-PodeOAContentMediaType -ContentMediaType '*/*' -Content (New-PodeOAStringProperty -Name 'id')) + New-PodeOARequestBody -Content (New-PodeOAContentMediaType -ContentType '*/*' -Content (New-PodeOAStringProperty -Name 'id')) ) ` -Response ( - New-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentMediaType 'application/json','application/xml' -Content 'Pet' -Array) | + New-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json','application/xml' -Content 'Pet' -Array) | New-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' | New-PodeOAResponse -StatusCode 404 -Description 'Pet not found' | New-PodeOAResponse -Default -Description 'Something is wrong' @@ -2798,9 +2800,11 @@ function New-PodeOAResponse { .DESCRIPTION The New-PodeOAContentMediaType function generates media content type definitions suitable for use in OpenAPI specifications. It supports various media types and allows for the specification of content as either a single object or an array of objects. -.PARAMETER MediaType +.PARAMETER ContentType An array of strings specifying the media types to be defined. Media types should conform to standard MIME types (e.g., 'application/json', 'image/png'). The function validates these media types against a regular expression to ensure they are properly formatted. + Alias: MediaType + .PARAMETER Content The content definition for the media type. This could be an object representing the structure of the content expected for the specified media types. @@ -2835,20 +2839,20 @@ function New-PodeOAResponse { Set-PodeOARequest -PassThru -Parameters @( (New-PodeOAStringProperty -Name 'status' -Description 'Status values that need to be considered for filter' -Default 'available' -Enum @('available', 'pending', 'sold') | ConvertTo-PodeOAParameter -In Query) ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentMediaType 'application/json','application/xml' -Content 'Pet' -Array -UniqueItems) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json','application/xml' -Content 'Pet' -Array -UniqueItems) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid status value' This example demonstrates the use of New-PodeOAContentMediaType in defining a GET route '/pet/findByStatus' in an OpenAPI specification. The route includes request parameters and responses with media content types for 'application/json' and 'application/xml'. .EXAMPLE $content = @{ type = 'string' } $mediaType = 'application/json' - New-PodeOAContentMediaType -MediaType $mediaType -Content $content + New-PodeOAContentMediaType -ContentType $mediaType -Content $content This example creates a media content type definition for 'application/json' with a simple string content type. .EXAMPLE $content = @{ type = 'object'; properties = @{ name = @{ type = 'string' } } } $mediaTypes = 'application/json', 'application/xml' - New-PodeOAContentMediaType -MediaType $mediaTypes -Content $content -Array -MinItems 1 -MaxItems 5 -Title 'UserList' + New-PodeOAContentMediaType -ContentType $mediaTypes -Content $content -Array -MinItems 1 -MaxItems 5 -Title 'UserList' This example demonstrates defining an array of objects for both 'application/json' and 'application/xml' media types, with a specified range for the number of items and a title. .EXAMPLE @@ -2858,7 +2862,7 @@ function New-PodeOAResponse { Set-PodeOARequest -PassThru -Parameters @( (New-PodeOAStringProperty -Name 'status' -Description 'Status values that need to be considered for filter' -Default 'available' -Enum @('available', 'pending', 'sold') | ConvertTo-PodeOAParameter -In Query) ) | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentMediaType 'application/json','application/xml' -Content 'Pet' -Array -UniqueItems) -PassThru | + Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json','application/xml' -Content 'Pet' -Array -UniqueItems) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid status value' This example demonstrates the use of New-PodeOAContentMediaType in defining a GET route '/pet/findByStatus' in an OpenAPI specification. The route includes request parameters and responses with media content types for 'application/json' and 'application/xml'. @@ -2870,8 +2874,10 @@ function New-PodeOAContentMediaType { [CmdletBinding(DefaultParameterSetName = 'inbuilt')] [OutputType([System.Collections.Specialized.OrderedDictionary])] param ( + [Parameter()] + [Alias('MediaType')] [string[]] - $MediaType = '*/*', + $ContentType = '*/*', [object] $Content, @@ -2913,7 +2919,7 @@ function New-PodeOAContentMediaType { $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag $props = [ordered]@{} - foreach ($media in $MediaType) { + foreach ($media in $ContentType) { if ($media -inotmatch '^(application|audio|image|message|model|multipart|text|video|\*)\/[\w\.\-\*]+(;[\s]*(charset|boundary)=[\w\.\-\*]+)*$') { # Invalid 'content-type' found for schema: $media throw ($PodeLocale.invalidContentTypeForSchemaExceptionMessage -f $media) @@ -3411,7 +3417,7 @@ Select-PodeOADefinition -Tag 'v3', 'v3.1' -Script { New-PodeOAObjectProperty -XmlName 'order' | Add-PodeOAComponentSchema -Name 'Order' -New-PodeOAContentMediaType -ContentMediaType 'application/json', 'application/xml' -Content 'Pet' | +New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' | Add-PodeOAComponentRequestBody -Name 'Pet' -Description 'Pet object that needs to be added to the store' } diff --git a/tests/unit/OpenApi.Tests.ps1 b/tests/unit/OpenApi.Tests.ps1 index aab9ca389..1698312f7 100644 --- a/tests/unit/OpenApi.Tests.ps1 +++ b/tests/unit/OpenApi.Tests.ps1 @@ -2869,7 +2869,7 @@ Describe 'OpenApi' { } it 'default' { - Add-PodeOAComponentRequestBody -Name 'PetBodySchema' -Required -Description 'Pet in the store' -Content ( New-PodeOAContentMediaType -MediaType 'application/json' , 'application/xml', 'application/x-www-form-urlencoded' -Content 'Cat' ) + Add-PodeOAComponentRequestBody -Name 'PetBodySchema' -Required -Description 'Pet in the store' -Content ( New-PodeOAContentMediaType -ContentType 'application/json' , 'application/xml', 'application/x-www-form-urlencoded' -Content 'Cat' ) $result = $PodeContext.Server.OpenAPI.Definitions['default'].components.requestBodies['PetBodySchema'] $result | Should -Not -BeNullOrEmpty $result | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] @@ -2965,13 +2965,13 @@ Describe 'OpenApi' { # Test return type It 'Returns an OrderedHashtable' { - $example = New-PodeOAExample -MediaType 'application/json' -Name 'user' -Summary 'JSON Example' -ExternalValue 'http://external.com' + $example = New-PodeOAExample -ContentType 'application/json' -Name 'user' -Summary 'JSON Example' -ExternalValue 'http://external.com' $example | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] } # Test output for a single MediaType It 'Correctly creates example for a single MediaType' { - $example = New-PodeOAExample -MediaType 'application/json' -Name 'user' -Summary 'JSON Example' -ExternalValue 'http://external.com' + $example = New-PodeOAExample -ContentType 'application/json' -Name 'user' -Summary 'JSON Example' -ExternalValue 'http://external.com' $example['application/json'].Keys -Contains 'user' | Should -Be $true $example['application/json']['user'].summary -eq 'JSON Example' | Should -Be $true $example['application/json']['user'].externalValue -eq 'http://external.com' | Should -Be $true @@ -2979,8 +2979,8 @@ Describe 'OpenApi' { # Test merging behavior It 'Correctly merges examples for multiple MediaTypes' { - $result = New-PodeOAExample -MediaType 'application/json' -Name 'user' -Summary 'JSON Example' -Value '[]' | - New-PodeOAExample -MediaType 'application/xml' -Name 'user' -Summary 'XML Example' -Value '<>' + $result = New-PodeOAExample -ContentType 'application/json' -Name 'user' -Summary 'JSON Example' -Value '[]' | + New-PodeOAExample -ContentType 'application/xml' -Name 'user' -Summary 'XML Example' -Value '<>' $result.Count -eq 2 | Should -Be $true $result['application/json']['user'].summary -eq 'JSON Example' | Should -Be $true From 798c05d52ec05694f00b53c92ef7006b676f374b Mon Sep 17 00:00:00 2001 From: mdaneri Date: Mon, 9 Sep 2024 07:13:46 -0700 Subject: [PATCH 146/177] OpenApi fixes - Fix : `Remove-PodeRoute` doesn't remove the OpenAPI `operationId` associated to the route -Fix: `Add-PodeOAComponentPathItem` and `Add-PodeOAWebhook` `DefinitionTag` is null. This issue is aside effect of a previous OpenAPI fix --- examples/OpenApi-TuttiFrutti.ps1 | 5 ++--- src/Public/OAComponents.ps1 | 17 ++++++++------- src/Public/OpenApi.ps1 | 10 +++++---- src/Public/Routes.ps1 | 14 +++++++------ tests/unit/Routes.Tests.ps1 | 36 ++++++++++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 20 deletions(-) diff --git a/examples/OpenApi-TuttiFrutti.ps1 b/examples/OpenApi-TuttiFrutti.ps1 index 9b0c91e1e..cddd5d735 100644 --- a/examples/OpenApi-TuttiFrutti.ps1 +++ b/examples/OpenApi-TuttiFrutti.ps1 @@ -951,7 +951,7 @@ Some useful links: Add-PodeOAResponse -StatusCode 404 -Description 'User not found' -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' - +#region Test remove route Add-PodeRoute -PassThru -Method Delete -Path '/usera/:username' -ScriptBlock { Write-PodeJsonResponse -Value 'done' -StatusCode 200 @@ -966,7 +966,6 @@ Some useful links: Remove-PodeRoute -Method Delete -Path '/api/v3/usera/:username' - Add-PodeRoute -PassThru -Method Delete -Path '/user/:username' -ScriptBlock { Write-PodeJsonResponse -Value 'done' -StatusCode 200 } | Set-PodeOARouteInfo -Summary 'Delete user' -Description 'This can only be done by the logged in user.' -Tags 'user' -OperationId 'deleteUser' -PassThru | @@ -976,7 +975,7 @@ Some useful links: Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid username supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'User not found' - +#endregion Add-PodeOAExternalRoute -Method Get -Path '/stores/order/:orderId' -Servers ( diff --git a/src/Public/OAComponents.ps1 b/src/Public/OAComponents.ps1 index 6d6aa4ed1..04b924dbc 100644 --- a/src/Public/OAComponents.ps1 +++ b/src/Public/OAComponents.ps1 @@ -728,20 +728,23 @@ function Add-PodeOAComponentPathItem { $DefinitionTag ) - $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + $_definitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag $refRoute = @{ Method = $Method.ToLower() NotPrepared = $true OpenApi = @{ - Responses = $null - Parameters = $null - RequestBody = $null - callbacks = [ordered]@{} - Authentication = @() + Responses = $null + Parameters = $null + RequestBody = $null + callbacks = @{} + Authentication = @() + Servers = @() + DefinitionTag = $_definitionTag + IsDefTagConfigured = ($null -ne $DefinitionTag) #Definition Tag has been configured (Not default) } } - foreach ($tag in $DefinitionTag) { + foreach ($tag in $_definitionTag) { if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $tag ) { # The 'pathItems' reusable component feature is not available in OpenAPI v3.0. throw ($PodeLocale.reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage) diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index 22f7dfef8..7f0f7744a 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -1584,7 +1584,7 @@ function Set-PodeOARouteInfo { $r.OpenApi.IsDefTagConfigured = $true } } - + if ($Summary) { $r.OpenApi.Summary = $Summary } @@ -3364,7 +3364,7 @@ function Add-PodeOAWebhook { $DefinitionTag ) - $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag + $_definitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag $refRoute = @{ Method = $Method.ToLower() @@ -3373,11 +3373,13 @@ function Add-PodeOAWebhook { Responses = @{} Parameters = $null RequestBody = $null - callbacks = [ordered]@{} + callbacks = @{} Authentication = @() + DefinitionTag = $_definitionTag + IsDefTagConfigured = ($null -ne $DefinitionTag) #Definition Tag has been configured (Not default) } } - foreach ($tag in $DefinitionTag) { + foreach ($tag in $_definitionTag) { if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $tag ) { # The Webhooks feature is not supported in OpenAPI v3.0.x throw ($PodeLocale.webhooksFeatureNotSupportedInOpenApi30ExceptionMessage) diff --git a/src/Public/Routes.ps1 b/src/Public/Routes.ps1 index ffed8e91f..f23dccd88 100644 --- a/src/Public/Routes.ps1 +++ b/src/Public/Routes.ps1 @@ -1695,14 +1695,16 @@ function Remove-PodeRoute { # select the candidate route for deletion $route = @($PodeContext.Server.Routes[$Method][$Path] | Where-Object { - $_.Endpoint.Name -ine $EndpointName + $_.Endpoint.Name -ieq $EndpointName }) - # remove the operationId from the openapi operationId list - if ($route.OpenAPI) { - foreach ( $tag in $route.OpenAPI.DefinitionTag) { - if ($tag -and ($PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.operationId -ccontains $route.OpenAPI.OperationId)) { - $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.operationId = $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.operationId | Where-Object { $_ -ne $route.OpenAPI.OperationId } + foreach ($r in $route) { + # remove the operationId from the openapi operationId list + if ($r.OpenAPI) { + foreach ( $tag in $r.OpenAPI.DefinitionTag) { + if ($tag -and ($PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.operationId -ccontains $route.OpenAPI.OperationId)) { + $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.operationId = $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.operationId | Where-Object { $_ -ne $route.OpenAPI.OperationId } + } } } } diff --git a/tests/unit/Routes.Tests.ps1 b/tests/unit/Routes.Tests.ps1 index dc5aff5ca..dc33e797a 100644 --- a/tests/unit/Routes.Tests.ps1 +++ b/tests/unit/Routes.Tests.ps1 @@ -153,6 +153,42 @@ Describe 'Remove-PodeRoute' { $routes.ContainsKey('/users') | Should -Be $true $routes['/users'].Length | Should -Be 1 } + + It 'Removes a route and cleans up OpenAPI operationId' { + Add-PodeRoute -PassThru -Method Get -Path '/users' -ScriptBlock { Write-Host 'hello' } | Set-PodeOARouteInfo -Summary 'Test user' -OperationId 'getUsers' + + $routes = $PodeContext.Server.Routes['GET'] + $routes | Should -Not -Be $null + $routes.ContainsKey('/users') | Should -Be $true + $routes['/users'].Length | Should -Be 1 + + Remove-PodeRoute -Method Get -Path '/users' + + $routes = $PodeContext.Server.Routes['GET'] + $routes | Should -Not -Be $null + $routes.ContainsKey('/users') | Should -Be $false + $PodeContext.Server.OpenAPI.Definitions.default.hiddenComponents.operationId | Should -Not -Contain 'getUsers' + } + + It 'Adds two routes and removes on route and cleans up OpenAPI operationId' { + Add-PodeEndpoint -Address '127.0.0.1' -Port 8080 -Protocol Http -Name user + + Add-PodeRoute -PassThru -Method Get -Path '/users' -ScriptBlock { Write-Host 'hello' } | Set-PodeOARouteInfo -Summary 'Test user' -OperationId 'getUsers' + Add-PodeRoute -PassThru -Method Get -Path '/users' -EndpointName user -ScriptBlock { Write-Host 'hello' } | Set-PodeOARouteInfo -Summary 'Test user2' -OperationId 'getUsers2' + + $routes = $PodeContext.Server.Routes['GET'] + $routes | Should -Not -Be $null + $routes.ContainsKey('/users') | Should -Be $true + $routes['/users'].Length | Should -Be 2 + + Remove-PodeRoute -Method Get -Path '/users' -EndpointName 'user' + + $routes = $PodeContext.Server.Routes['GET'] + $routes | Should -Not -Be $null + $routes.ContainsKey('/users') | Should -Be $true + $routes['/users'].Length | Should -Be 1 + $PodeContext.Server.OpenAPI.Definitions.default.hiddenComponents.operationId | Should -Not -Contain 'getUsers2' + } } Describe 'Remove-PodeStaticRoute' { From 07c58ea3229a30f9048f9eff94bc5d6185814e44 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 13 Sep 2024 10:25:56 -0700 Subject: [PATCH 147/177] Fix 5.1 issues with ordered hashtable New OpenAPI integration test --- examples/OpenApi-TuttiFrutti.ps1 | 54 +- examples/PetStore/Petstore-OpenApi.ps1 | 4 +- .../PetStore/Petstore-OpenApiMultiTag.ps1 | 12 +- src/Private/Helpers.ps1 | 17 + src/Private/OpenApi.ps1 | 50 +- src/Public/OAComponents.ps1 | 2 +- src/Public/OpenApi.ps1 | 73 +- src/Public/Routes.ps1 | 4 +- tests/integration/OpenApi.Tests.ps1 | 194 ++ .../specs/OpenApi-TuttiFrutti_3.0.3.json | 2868 +++++++++++++++++ .../specs/OpenApi-TuttiFrutti_3.1.0.json | 2837 ++++++++++++++++ tests/unit/OpenApi.Tests.ps1 | 24 +- tests/unit/PrivateOpenApi.Tests.ps1 | 4 +- 13 files changed, 6050 insertions(+), 93 deletions(-) create mode 100644 tests/integration/OpenApi.Tests.ps1 create mode 100644 tests/integration/specs/OpenApi-TuttiFrutti_3.0.3.json create mode 100644 tests/integration/specs/OpenApi-TuttiFrutti_3.1.0.json diff --git a/examples/OpenApi-TuttiFrutti.ps1 b/examples/OpenApi-TuttiFrutti.ps1 index cddd5d735..358906a22 100644 --- a/examples/OpenApi-TuttiFrutti.ps1 +++ b/examples/OpenApi-TuttiFrutti.ps1 @@ -7,6 +7,18 @@ It includes multiple endpoints, OpenAPI documentation, various route definitions, authentication schemes, and middleware for enhanced API functionality. +.PARAMETER PortV3 + The port on which the Pode server will listen for OpenAPI v3. Default is 8080. + +.PARAMETER PortV3_1 + The port on which the Pode server will listen for OpenAPI v3_1. Default is 8081. + +.PARAMETER Quiet + Suppresses output when the server is running. + +.PARAMETER DisableTermination + Prevents the server from being terminated. + .EXAMPLE To run the sample: ./OpenApi-TuttiFrutti.ps1 @@ -24,6 +36,20 @@ Author: Pode Team License: MIT License #> +param( + [Parameter()] + [int] + $PortV3 = 8080, + + [int] + $PortV3_1 = 8081, + + [switch] + $Quiet, + + [switch] + $DisableTermination +) try { # Determine the script path and Pode module path @@ -40,9 +66,9 @@ try { } catch { throw } -Start-PodeServer -Threads 2 -ScriptBlock { - Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http -Default -Name 'endpoint_v3' - Add-PodeEndpoint -Address localhost -Port 8082 -Protocol Http -Default -Name 'endpoint_v3.1' +Start-PodeServer -Threads 1 -Quiet:$Quiet -DisableTermination:$DisableTermination -ScriptBlock { + Add-PodeEndpoint -Address localhost -Port $PortV3 -Protocol Http -Default -Name 'endpoint_v3' + Add-PodeEndpoint -Address localhost -Port $PortV3_1 -Protocol Http -Default -Name 'endpoint_v3.1' New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging $InfoDescription = @' This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about Swagger at [http://swagger.io](http://swagger.io). @@ -55,8 +81,8 @@ Some useful links: - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml) '@ - Enable-PodeOpenApi -Path '/docs/openapi/v3.0' -OpenApiVersion '3.0.3' -EnableSchemaValidation -DisableMinimalDefinitions -NoDefaultResponses -DefinitionTag 'v3' -EndpointName 'endpoint_v3' - Enable-PodeOpenApi -Path '/docs/openapi/v3.1' -OpenApiVersion '3.1.0' -EnableSchemaValidation -DisableMinimalDefinitions -NoDefaultResponses -DefinitionTag 'v3.1' -EndpointName 'endpoint_v3.1' + Enable-PodeOpenApi -Path '/docs/openapi/v3.0' -OpenApiVersion '3.0.3' -EnableSchemaValidation:($PSVersionTable.PSEdition -eq 'Core') -DisableMinimalDefinitions -NoDefaultResponses -DefinitionTag 'v3' -EndpointName 'endpoint_v3' + Enable-PodeOpenApi -Path '/docs/openapi/v3.1' -OpenApiVersion '3.1.0' -EnableSchemaValidation:($PSVersionTable.PSEdition -eq 'Core') -DisableMinimalDefinitions -NoDefaultResponses -DefinitionTag 'v3.1' -EndpointName 'endpoint_v3.1' $swaggerDocs = New-PodeOAExternalDoc -Description 'Find out more about Swagger' -Url 'http://swagger.io' $swaggerDocs | Add-PodeOAExternalDoc -DefinitionTag 'v3', 'v3.1' @@ -531,6 +557,12 @@ Some useful links: } Add-PodeAuthMiddleware -Name test -Authentication 'test' -Route '/api/*' Select-PodeOADefinition -Tag 'v3.1', 'v3' -Scriptblock { + + Add-PodeRoute -Method 'Post' -Path '/close' -ScriptBlock { + Close-PodeServer + } -PassThru | Set-PodeOARouteInfo -Summary 'Shutdown the server' -PassThru | Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' + + Add-PodeRouteGroup -Path '/api/v3' -Routes { #PUT Add-PodeRoute -PassThru -Method Put -Path '/pet' -ScriptBlock { @@ -649,14 +681,6 @@ Some useful links: Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentType 'application/json', 'application/xml' -Content 'Pet' -Array) -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid status value' - - - - - - - - Add-PodeRoute -PassThru -Method get -Path '/pet/findByTag' -Authentication 'test' -Scope 'read' -ScriptBlock { Write-PodeJsonResponse -Value 'done' -StatusCode 200 } | Set-PodeOARouteInfo -Summary 'Finds Pets by tags' -Description 'Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.' -Tags 'pet' -OperationId 'findPetsByTags' -PassThru | @@ -951,7 +975,7 @@ Some useful links: Add-PodeOAResponse -StatusCode 404 -Description 'User not found' -PassThru | Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' -#region Test remove route + #region Test remove route Add-PodeRoute -PassThru -Method Delete -Path '/usera/:username' -ScriptBlock { Write-PodeJsonResponse -Value 'done' -StatusCode 200 @@ -975,7 +999,7 @@ Some useful links: Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -PassThru | Add-PodeOAResponse -StatusCode 400 -Description 'Invalid username supplied' -PassThru | Add-PodeOAResponse -StatusCode 404 -Description 'User not found' -#endregion + #endregion Add-PodeOAExternalRoute -Method Get -Path '/stores/order/:orderId' -Servers ( diff --git a/examples/PetStore/Petstore-OpenApi.ps1 b/examples/PetStore/Petstore-OpenApi.ps1 index 6ee32927b..bf2578bf5 100644 --- a/examples/PetStore/Petstore-OpenApi.ps1 +++ b/examples/PetStore/Petstore-OpenApi.ps1 @@ -118,7 +118,7 @@ Start-PodeServer -Threads 1 -ScriptBlock { # Enable OpenAPI documentation - Enable-PodeOpenApi -Path '/docs/openapi' -OpenApiVersion '3.0.3' -EnableSchemaValidation -DisableMinimalDefinitions -NoDefaultResponses + Enable-PodeOpenApi -Path '/docs/openapi' -OpenApiVersion '3.0.3' -EnableSchemaValidation:($PSVersionTable.PSEdition -eq 'Core') -DisableMinimalDefinitions -NoDefaultResponses # Add external documentation link for Swagger $swaggerDocs = New-PodeOAExternalDoc -Description 'Find out more about Swagger' -Url 'http://swagger.io' @@ -137,7 +137,7 @@ Some useful links: '@ - Add-PodeOAInfo -Title 'Swagger Petstore - OpenAPI 3.0' -Version 1.0.17 -Description $InfoDescription -TermsOfService 'http://swagger.io/terms/' -LicenseName 'Apache 2.0' ` + Add-PodeOAInfo -Title 'Swagger Petstore - OpenAPI 3.0.3' -Version 1.0.17 -Description $InfoDescription -TermsOfService 'http://swagger.io/terms/' -LicenseName 'Apache 2.0' ` -LicenseUrl 'http://www.apache.org/licenses/LICENSE-2.0.html' -ContactName 'API Support' -ContactEmail 'apiteam@swagger.io' Add-PodeOAServerEndpoint -url '/api/v3' -Description 'default endpoint' diff --git a/examples/PetStore/Petstore-OpenApiMultiTag.ps1 b/examples/PetStore/Petstore-OpenApiMultiTag.ps1 index c3a351f48..932b3b0aa 100644 --- a/examples/PetStore/Petstore-OpenApiMultiTag.ps1 +++ b/examples/PetStore/Petstore-OpenApiMultiTag.ps1 @@ -107,8 +107,8 @@ Start-PodeServer -Threads 1 -ScriptBlock { - Enable-PodeOpenApi -Path '/docs/openapi/v3.0' -OpenApiVersion '3.0.2' -EnableSchemaValidation -DisableMinimalDefinitions -NoDefaultResponses -EndpointName 'endpoint_v3' - Enable-PodeOpenApi -Path '/docs/openapi/v3.1' -OpenApiVersion '3.1.0' -EnableSchemaValidation -DisableMinimalDefinitions -NoDefaultResponses -DefinitionTag 'v3.1' -EndpointName 'endpoint_v3.1' + Enable-PodeOpenApi -Path '/docs/openapi/v3.0' -OpenApiVersion '3.0.3' -EnableSchemaValidation:($PSVersionTable.PSEdition -eq 'Core') -DisableMinimalDefinitions -NoDefaultResponses -EndpointName 'endpoint_v3' + Enable-PodeOpenApi -Path '/docs/openapi/v3.1' -OpenApiVersion '3.1.0' -EnableSchemaValidation:($PSVersionTable.PSEdition -eq 'Core') -DisableMinimalDefinitions -NoDefaultResponses -DefinitionTag 'v3.1' -EndpointName 'endpoint_v3.1' $swaggerDocs = New-PodeOAExternalDoc -Description 'Find out more about Swagger' -Url 'http://swagger.io' $swaggerDocs | Add-PodeOAExternalDoc -DefinitionTag 'v3.0.3', 'v3.1' @@ -126,13 +126,15 @@ Some useful links: '@ - Add-PodeOAInfo -Title 'Swagger Petstore - OpenAPI 3.0' -Version 1.0.17 -Description $InfoDescription -TermsOfService 'http://swagger.io/terms/' -LicenseName 'Apache 2.0' ` + Add-PodeOAInfo -Title 'Swagger Petstore - OpenAPI 3.0.3' -Version 1.0.17 -Description $InfoDescription -TermsOfService 'http://swagger.io/terms/' -LicenseName 'Apache 2.0' ` -LicenseUrl 'http://www.apache.org/licenses/LICENSE-2.0.html' -ContactName 'API Support' -ContactEmail 'apiteam@swagger.io' -DefinitionTag 'v3.0.3' - Add-PodeOAInfo -Title 'Swagger Petstore - OpenAPI 3.1' -Version 1.0.17 -Description $InfoDescription -TermsOfService 'http://swagger.io/terms/' -LicenseName 'Apache 2.0' ` + Add-PodeOAInfo -Title 'Swagger Petstore - OpenAPI 3.1.0' -Version 1.0.17 -Description $InfoDescription -TermsOfService 'http://swagger.io/terms/' -LicenseName 'Apache 2.0' ` -LicenseUrl 'http://www.apache.org/licenses/LICENSE-2.0.html' -ContactName 'API Support' -ContactEmail 'apiteam@swagger.io' -DefinitionTag 'v3.1' - Add-PodeOAServerEndpoint -url '/api/v3' -Description 'default endpoint' -DefinitionTag 'v3.0.3', 'v3.1' + Add-PodeOAServerEndpoint -url '/api/v3' -Description 'V3 Endpoint' -DefinitionTag 'v3.0.3' + Add-PodeOAServerEndpoint -url '/api/v3' -Description 'V3.1 Endpoint' -DefinitionTag 'v3.1' + Add-PodeOAServerEndpoint -url '/api' -Description 'Default Endpoint' -DefinitionTag 'v3.0.3','v3.1' #OpenAPI 3.0 Enable-PodeOAViewer -Type Swagger -Path '/docs/swagger' -DefinitionTag 'v3.0.3' diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index d9d09ded0..8c08abd96 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -4035,4 +4035,21 @@ function Resolve-PodeObjectArray { # For any other type, convert it to a PowerShell object return New-Object psobject -Property $Property } +} + + +function Get-PodeOrderedDictionaryClone { + param ( + [System.Collections.Specialized.OrderedDictionary]$Original + ) + + # Create a new ordered dictionary to hold the clone + $clone = [System.Collections.Specialized.OrderedDictionary]::new() + + # Copy each key-value pair from the original to the clone + foreach ($key in $Original.Keys) { + $clone.Add($key, $Original[$key]) + } + + return $clone } \ No newline at end of file diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index 81be1e4e0..d2ccc13c6 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -53,7 +53,7 @@ function ConvertTo-PodeOAObjectSchema { } # convert each schema to OpenAPI format # Initialize an empty hashtable for the schema - $obj = @{} + $obj = [ordered]@{} # Process each content type $types = [string[]]$Content.Keys @@ -162,12 +162,12 @@ function ConvertTo-PodeOAObjectSchema { } else { # Create an empty content - $obj[$type] = @{} + $obj[$type] = [ordered]@{} } } else { if ($item.Count -eq 0) { - $result = @{} + $result = [ordered]@{} } else { $result = ($item | ConvertTo-PodeOASchemaProperty -DefinitionTag $DefinitionTag) @@ -608,7 +608,7 @@ function ConvertTo-PodeOASchemaProperty { } if ($Property.type -ieq 'object') { - $schema['properties'] = @{} + $schema['properties'] = [ordered]@{} foreach ($prop in $Property.properties) { if ( @('allOf', 'oneOf', 'anyOf') -icontains $prop.type) { switch ($prop.type.ToLower()) { @@ -696,7 +696,7 @@ function ConvertTo-PodeOASchemaObjectProperty { ) # Initialize an empty hashtable for the schema - $schema = @{} + $schema = [ordered]@{} # Iterate over each property and convert to OpenAPI schema property if applicable foreach ($prop in $Properties) { @@ -790,7 +790,7 @@ function Set-PodeOpenApiRouteValue { } elseif ($sct -eq '%_allowanon_%') { #allow anonymous access - $pm.security += @{} + $pm.security += [ordered]@{} } else { $pm.security += @{$sct = @() } @@ -988,7 +988,7 @@ function Get-PodeOpenApiDefinitionInternal { $authType = (Find-PodeAuth -Name $authName).Scheme $_authName = ($authName -replace '\s+', '') - $_authObj = @{} + $_authObj = [ordered]@{} if ($authType.Scheme -ieq 'apikey') { $_authObj = [ordered]@{ @@ -1035,7 +1035,7 @@ function Get-PodeOpenApiDefinitionInternal { $_authObj.flows.$oAuthFlow.refreshUrl = $authType.Arguments.Urls.Refresh } - $_authObj.flows.$oAuthFlow.scopes = @{} + $_authObj.flows.$oAuthFlow.scopes = [ordered]@{} if ($authType.Arguments.Scopes ) { foreach ($scope in $authType.Arguments.Scopes) { if ($PodeContext.Server.Authorisations.Methods.ContainsKey($scope) -and $PodeContext.Server.Authorisations.Methods[$scope].Scheme.Type -ieq 'Scope' -and $PodeContext.Server.Authorisations.Methods[$scope].Description) { @@ -1107,7 +1107,7 @@ function Get-PodeOpenApiDefinitionInternal { # add path to defintion if ($null -eq $def.paths[$_route.OpenApi.Path]) { - $def.paths[$_route.OpenApi.Path] = @{} + $def.paths[$_route.OpenApi.Path] = [ordered]@{} } # add path's http method to defintition @@ -1163,7 +1163,7 @@ function Get-PodeOpenApiDefinitionInternal { foreach ($method in $extPath.keys) { $_route = $extPath[$method] if (! ( $def.paths.keys -ccontains $_route.Path)) { - $def.paths[$_route.OpenAPI.Path] = @{} + $def.paths[$_route.OpenAPI.Path] = [ordered]@{} } $pm = Set-PodeOpenApiRouteValue -Route $_route -DefinitionTag $DefinitionTag # add path's http method to defintition @@ -1267,19 +1267,19 @@ function Get-PodeOABaseObject { schemaJson = @{} viewer = @{} postValidation = @{ - schemas = @{} - responses = @{} - parameters = @{} - examples = @{} - requestBodies = @{} - headers = @{} - securitySchemes = @{} - links = @{} - callbacks = @{} - pathItems = @{} + schemas = [ordered]@{} + responses = [ordered]@{} + parameters = [ordered]@{} + examples = [ordered]@{} + requestBodies = [ordered]@{} + headers = [ordered]@{} + securitySchemes = [ordered]@{} + links = [ordered]@{} + callbacks = [ordered]@{} + pathItems = [ordered]@{} } externalPath = [ordered]@{} - defaultResponses = @{ + defaultResponses = [ordered]@{ '200' = @{ description = 'OK' } 'default' = @{ description = 'Internal server error' } } @@ -1736,7 +1736,7 @@ function New-PodeOAPropertyInternal { if ($Params.XmlName -or $Params.XmlNamespace -or $Params.XmlPrefix -or $Params.XmlAttribute.IsPresent -or $Params.XmlWrapped.IsPresent) { - $param.xml = @{} + $param.xml = [ordered]@{} if ($Params.XmlName) { $param.xml.name = $Params.XmlName } @@ -1794,12 +1794,12 @@ function ConvertTo-PodeOAHeaderProperty { $Headers ) - $elems = @{} + $elems = [ordered]@{} foreach ($e in $Headers) { # Ensure each header has a name if ($e.name) { - $elems.$($e.name) = @{} + $elems.$($e.name) = [ordered]@{} # Add description if present if ($e.description) { $elems.$($e.name).description = $e.description @@ -1961,7 +1961,7 @@ function New-PodeOResponseInternal { $_headers = ConvertTo-PodeOAHeaderProperty -Headers $Params.Headers } else { - $_headers = @{} + $_headers = [ordered]@{} foreach ($h in $Params.Headers) { Test-PodeOAComponentInternal -Field headers -DefinitionTag $DefinitionTag -Name $h -PostValidation $_headers[$h] = @{ diff --git a/src/Public/OAComponents.ps1 b/src/Public/OAComponents.ps1 index 04b924dbc..136650fde 100644 --- a/src/Public/OAComponents.ps1 +++ b/src/Public/OAComponents.ps1 @@ -751,7 +751,7 @@ function Add-PodeOAComponentPathItem { } #add the default OpenApi responses if ( $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses) { - $refRoute.OpenApi.Responses = $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses.Clone() + $refRoute.OpenApi.Responses = Get-PodeOrderedDictionaryClone -Source $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses } $PodeContext.Server.OpenAPI.Definitions[$tag].components.pathItems[$Name] = $refRoute } diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index 7f0f7744a..b8bdd8efe 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -318,7 +318,7 @@ function Enable-PodeOpenApi { #set new DefaultResponses if ($NoDefaultResponses.IsPresent) { - $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.defaultResponses = @{} + $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.defaultResponses = [ordered]@{} } elseif ($DefaultResponses) { $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.defaultResponses = $DefaultResponses @@ -645,7 +645,7 @@ function Add-PodeOAResponse { foreach ($r in @($Route)) { foreach ($tag in $DefinitionTag) { if (! $r.OpenApi.Responses.$tag) { - $r.OpenApi.Responses.$tag = @{} + $r.OpenApi.Responses.$tag = [ordered]@{} } $r.OpenApi.Responses.$tag[$code] = New-PodeOResponseInternal -DefinitionTag $tag -Params $PSBoundParameters } @@ -895,7 +895,7 @@ function New-PodeOARequestBody { $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag - $result = @{} + $result = [ordered]@{} foreach ($tag in $DefinitionTag) { switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 'builtin' { @@ -914,10 +914,10 @@ function New-PodeOARequestBody { $Examples.Remove('*/*') } foreach ($k in $Examples.Keys ) { - if (!$param.content.ContainsKey($k)) { - $param.content[$k] = @{} + if (!($param.content.Keys -contains $k)) { + $param.content[$k] = [ordered]@{} } - $param.content.$k.examples = $Examples.$k + $param.content[$k].examples = $Examples.$k } } } @@ -931,10 +931,10 @@ function New-PodeOARequestBody { } if ($Encoding) { if (([string]$Content.keys[0]) -match '(?i)^(multipart.*|application\/x-www-form-urlencoded)$' ) { - $r = @{} + $r = [ordered]@{} foreach ( $e in $Encoding) { $key = [string]$e.Keys - $elems = @{} + $elems = [ordered]@{} foreach ($v in $e[$key].Keys) { if ($v -ieq 'headers') { $elems.headers = ConvertTo-PodeOAHeaderProperty -Headers $e[$key].headers @@ -1008,6 +1008,11 @@ function Test-PodeOAJsonSchemaCompliance { $DefinitionTag = $PodeContext.Server.Web.OpenApi.DefaultDefinitionTag } + # if Powershell edition is Desktop the test cannot be done. By default everything is good + if ($PSVersionTable.PSEdition -eq 'Desktop') { + return $true + } + if ($Json -isnot [string]) { $json = ConvertTo-Json -InputObject $Json -Depth $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.depth } @@ -1584,7 +1589,7 @@ function Set-PodeOARouteInfo { $r.OpenApi.IsDefTagConfigured = $true } } - + if ($Summary) { $r.OpenApi.Summary = $Summary } @@ -2327,11 +2332,11 @@ function New-PodeOAExample { $DefinitionTag ) begin { + $pipelineValue = [ordered]@{} if (Test-PodeIsEmpty -Value $DefinitionTag) { $DefinitionTag = $PodeContext.Server.OpenAPI.SelectedDefinitionTag } - if ($PSCmdlet.ParameterSetName -ieq 'Reference') { Test-PodeOAComponentInternal -Field examples -DefinitionTag $DefinitionTag -Name $Reference -PostValidation $Name = $Reference @@ -2369,22 +2374,32 @@ function New-PodeOAExample { else { $param.$Name = $Example } + } process { + if ($_) { + $pipelineValue += $_ + } } end { - if ($ParamsList) { - if ($ParamsList.keys -contains $param.Keys[0]) { - $param.Values[0].GetEnumerator() | ForEach-Object { $ParamsList[$param.Keys[0]].$($_.Key) = $_.Value } - } - else { - $param.GetEnumerator() | ForEach-Object { $ParamsList[$_.Key] = $_.Value } - } - return $ParamsList + $examples = [ordered]@{} + if ($pipelineValue.Count -gt 0) { + # foreach ($p in $pipelineValue) { + $examples = $pipelineValue + # } + } + else { + return $param + } + + $key = [string]$param.Keys[0] + if ($examples.Keys -contains $key) { + $examples[$key] += $param[$key] } else { - return [System.Collections.Specialized.OrderedDictionary] $param + $examples += $param } + return $examples } } @@ -2767,7 +2782,7 @@ function New-PodeOAResponse { else { $code = "$($StatusCode)" } - $response = @{} + $response = [ordered]@{} } process { foreach ($tag in $DefinitionTag) { @@ -2942,7 +2957,7 @@ function New-PodeOAContentMediaType { } else { if ($null -eq $Content ) { - $Content = @{} + $Content = [ordered]@{} } } if ($Array.IsPresent) { @@ -3223,10 +3238,10 @@ function Add-PodeOAExternalRoute { foreach ($tag in $DefinitionTag) { #add the default OpenApi responses if ( $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses) { - $extRoute.OpenApi.Responses = $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses.Clone() + $extRoute.OpenApi.Responses = Get-PodeOrderedDictionaryClone -Source $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses } if (! (Test-PodeOAComponentExternalPath -DefinitionTag $tag -Name $Path)) { - $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.externalPath[$Path] = @{} + $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.externalPath[$Path] = [ordered]@{} } $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.externalPath.$Path[$Method] = $extRoute @@ -3370,11 +3385,11 @@ function Add-PodeOAWebhook { Method = $Method.ToLower() NotPrepared = $true OpenApi = @{ - Responses = @{} - Parameters = $null - RequestBody = $null - callbacks = @{} - Authentication = @() + Responses = [ordered]@{} + Parameters = $null + RequestBody = $null + callbacks = [ordered]@{} + Authentication = @() DefinitionTag = $_definitionTag IsDefTagConfigured = ($null -ne $DefinitionTag) #Definition Tag has been configured (Not default) } @@ -3607,7 +3622,7 @@ function Test-PodeOADefinition { $result.issues[$tag] = @{ title = [string]::IsNullOrWhiteSpace( $PodeContext.Server.OpenAPI.Definitions[$tag].info.title) version = [string]::IsNullOrWhiteSpace( $PodeContext.Server.OpenAPI.Definitions[$tag].info.version) - components = @{} + components = [ordered]@{} definition = '' } foreach ($field in $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.postValidation.keys) { diff --git a/src/Public/Routes.ps1 b/src/Public/Routes.ps1 index f23dccd88..4f138f4a9 100644 --- a/src/Public/Routes.ps1 +++ b/src/Public/Routes.ps1 @@ -397,9 +397,9 @@ function Add-PodeRoute { #add the default OpenApi responses if ( $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.defaultResponses) { - $DefaultResponse = @{} + $DefaultResponse = [ordered]@{} foreach ($tag in $DefinitionTag) { - $DefaultResponse[$tag] = $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses.Clone() + $DefaultResponse[$tag] = Get-PodeOrderedDictionaryClone -Source $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses } } diff --git a/tests/integration/OpenApi.Tests.ps1 b/tests/integration/OpenApi.Tests.ps1 new file mode 100644 index 000000000..bdf2c8053 --- /dev/null +++ b/tests/integration/OpenApi.Tests.ps1 @@ -0,0 +1,194 @@ +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseUsingScopeModifierInNewRunspaces', '')] +param() + +Describe 'OpenAPI integration tests' { + + BeforeAll { + $mindyCommonHeaders = @{ + 'accept' = 'application/json' + 'X-API-KEY' = 'test2-api-key' + 'Authorization' = 'Basic bWluZHk6cGlja2xl' + } + + $mortyCommonHeaders = @{ + 'accept' = 'application/json' + 'X-API-KEY' = 'test-api-key' + 'Authorization' = 'Basic bW9ydHk6cGlja2xl' + } + $PortV3 = 8080 + $PortV3_1 = 8081 + $Endpoint = "http://127.0.0.1:$($PortV3)" + $scriptPath = "$($PSScriptRoot)\..\..\examples\OpenApi-TuttiFrutti.ps1" + if ($PSVersionTable.PsVersion -gt [version]'6.0') { + Start-Process 'pwsh' -ArgumentList "-NoProfile -File `"$scriptPath`" -Quiet -PortV3 $PortV3 -PortV3_1 $PortV3_1 -DisableTermination" -NoNewWindow + } + else { + Start-Process 'powershell' -ArgumentList "-NoProfile -File `"$scriptPath`" -Quiet -PortV3 $PortV3 -PortV3_1 $PortV3_1 -DisableTermination" -NoNewWindow + } + + function Convert-PsCustomObjectToOrderedHashtable { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [PSCustomObject]$InputObject + ) + begin { + # Define a recursive function within the process block + function Convert-ObjectRecursively { + param ( + [Parameter(Mandatory = $true)] + [System.Object] + $InputObject + ) + + # Initialize an ordered dictionary + $orderedHashtable = [ordered]@{} + + # Loop through each property of the PSCustomObject + foreach ($property in $InputObject.PSObject.Properties) { + # Check if the property value is a PSCustomObject + if ($property.Value -is [PSCustomObject]) { + # Recursively convert the nested PSCustomObject + $orderedHashtable[$property.Name] = Convert-ObjectRecursively -InputObject $property.Value + } + elseif ($property.Value -is [System.Collections.IEnumerable] -and -not ($property.Value -is [string])) { + # If the value is a collection, check each element + $convertedCollection = @() + foreach ($item in $property.Value) { + if ($item -is [PSCustomObject]) { + $convertedCollection += Convert-ObjectRecursively -InputObject $item + } + else { + $convertedCollection += $item + } + } + $orderedHashtable[$property.Name] = $convertedCollection + } + else { + # Add the property name and value to the ordered hashtable + $orderedHashtable[$property.Name] = $property.Value + } + } + + # Return the resulting ordered hashtable + return $orderedHashtable + } + } + process { + # Call the recursive helper function for each input object + Convert-ObjectRecursively -InputObject $InputObject + } + } + + function Compare-Hashtable { + param ( + [object]$Hashtable1, + [object]$Hashtable2 + ) + + # Function to compare two hashtable values + function Compare-Value($value1, $value2) { + # Check if both values are hashtables + if ((($value1 -is [hashtable] -or $value1 -is [System.Collections.Specialized.OrderedDictionary]) -and + ($value2 -is [hashtable] -or $value2 -is [System.Collections.Specialized.OrderedDictionary]))) { + return Compare-Hashtable -Hashtable1 $value1 -Hashtable2 $value2 + } + # Check if both values are arrays + elseif (($value1 -is [Object[]]) -and ($value2 -is [Object[]])) { + if ($value1.Count -ne $value2.Count) { + return $false + } + for ($i = 0; $i -lt $value1.Count; $i++) { + $found = $false + for ($j = 0; $j -lt $value2.Count; $j++) { + if ( Compare-Value $value1[$i] $value2[$j]) { + $found = $true + } + } + if ($found -eq $false) { + return $false + } + } + return $true + } + else { + # Check if the values are equal + return $value1 -eq $value2 + } + } + + $keys1 = $Hashtable1.Keys + $keys2 = $Hashtable2.Keys + + # Check if both hashtables have the same keys + if ($keys1.Count -ne $keys2.Count) { + return $false + } + + foreach ($key in $keys1) { + if (! ($Hashtable2.Keys -contains $key)) { + return $false + } + + if ($Hashtable2[$key] -is [hashtable] -or $Hashtable2[$key] -is [System.Collections.Specialized.OrderedDictionary]) { + if (! (Compare-Hashtable -Hashtable1 $Hashtable1[$key] -Hashtable2 $Hashtable2[$key])) { + return $false + } + } + elseif (!(Compare-Value $Hashtable1[$key] $Hashtable2[$key])) { + return $false + } + } + + return $true + } + + Start-Sleep -Seconds 5 + } + + AfterAll { + Start-Sleep -Seconds 5 + Invoke-RestMethod -Uri "$($Endpoint)/close" -Method Post | Out-Null + + } + + Describe 'OpenAPI' { + it 'Open API v3.0.3' { + + Start-Sleep -Seconds 10 + $fileContent = Get-Content -Path "$PSScriptRoot/specs/OpenApi-TuttiFrutti_3.0.3.json" + + $webResponse = Invoke-WebRequest -Uri "http://localhost:$($PortV3)/docs/openapi/v3.0" -Method Get + $json = $webResponse.Content + if ( $PSVersionTable.PSEdition -eq 'Desktop') { + $expected = $fileContent | ConvertFrom-Json | Convert-PsCustomObjectToOrderedHashtable + $response = $json | ConvertFrom-Json | Convert-PsCustomObjectToOrderedHashtable + } + else { + $expected = $fileContent | ConvertFrom-Json -AsHashtable + $response = $json | ConvertFrom-Json -AsHashtable + } + + Compare-Hashtable $response $expected | Should -BeTrue + + } + + it 'Open API v3.1.0' { + $fileContent = Get-Content -Path "$PSScriptRoot/specs/OpenApi-TuttiFrutti_3.1.0.json" + + $webResponse = Invoke-WebRequest -Uri "http://localhost:$($PortV3_1)/docs/openapi/v3.1" -Method Get + $json = $webResponse.Content + if ( $PSVersionTable.PSEdition -eq 'Desktop') { + $expected = $fileContent | ConvertFrom-Json | Convert-PsCustomObjectToOrderedHashtable + $response = $json | ConvertFrom-Json | Convert-PsCustomObjectToOrderedHashtable + } + else { + $expected = $fileContent | ConvertFrom-Json -AsHashtable + $response = $json | ConvertFrom-Json -AsHashtable + } + Compare-Hashtable $response $expected | Should -BeTrue + } + } + +} \ No newline at end of file diff --git a/tests/integration/specs/OpenApi-TuttiFrutti_3.0.3.json b/tests/integration/specs/OpenApi-TuttiFrutti_3.0.3.json new file mode 100644 index 000000000..4edacfd8d --- /dev/null +++ b/tests/integration/specs/OpenApi-TuttiFrutti_3.0.3.json @@ -0,0 +1,2868 @@ +{ + "openapi": "3.0.3", + "info": { + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "title": "Swagger Petstore - OpenAPI 3.0", + "version": "1.0.17", + "description": "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about Swagger at [http://swagger.io](http://swagger.io).\r\nIn the third iteration of the pet store, we've switched to the design first approach!\r\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\r\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\r\n\r\nSome useful links:\r\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\r\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)", + "termsOfService": "http://swagger.io/terms/", + "contact": { + "name": "API Support", + "email": "apiteam@swagger.io" + } + }, + "externalDocs": { + "description": "Find out more about Swagger", + "url": "http://swagger.io" + }, + "servers": [ + { + "url": "/api/v3", + "description": "default endpoint" + } + ], + "tags": [ + { + "name": "user", + "description": "Operations about user", + "externalDocs": { + "description": "Find out more about Swagger", + "url": "http://swagger.io" + } + }, + { + "name": "store", + "description": "Access to Petstore orders", + "externalDocs": { + "description": "Find out more about Swagger", + "url": "http://swagger.io" + } + }, + { + "name": "pet", + "description": "Everything about your Pets", + "externalDocs": { + "description": "Find out more about Swagger", + "url": "http://swagger.io" + } + } + ], + "paths": { + "/pet": { + "put": { + "tags": [ + "pet" + ], + "summary": "Update an existing pet", + "description": "Update an existing pet by Id", + "operationId": "updatePet", + "requestBody": { + "$ref": "#/components/requestBodies/PetBodySchema" + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + }, + "405": { + "description": "Validation exception", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "result": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + }, + "post": { + "tags": [ + "pet" + ], + "summary": "Add a new pet to the store", + "description": "Add a new pet to the store", + "operationId": "addPet", + "requestBody": { + "$ref": "#/components/requestBodies/PetBodySchema" + }, + "security": [ + { + "Login-OAuth2": [ + "write" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "405": { + "description": "Validation exception", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "result": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/user/{username}": { + "put": { + "tags": [ + "user" + ], + "summary": "Update user", + "description": "This can only be done by the logged in user.", + "operationId": "updateUser", + "parameters": [ + { + "description": " name that need to be updated.", + "name": "username", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "responses": { + "200": { + "$ref": "#/components/responses/UserOpSuccess" + }, + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + }, + "405": { + "description": "Invalid Input" + } + } + }, + "delete": { + "tags": [ + "user" + ], + "summary": "Delete user", + "description": "This can only be done by the logged in user.", + "operationId": "deleteUser", + "parameters": [ + { + "description": "The name that needs to be deleted.", + "name": "username", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + } + } + }, + "get": { + "tags": [ + "user" + ], + "summary": "Get user by user name", + "description": "Get user by user name.", + "operationId": "getUserByName", + "parameters": [ + { + "description": "The name that needs to be fetched. Use user1 for testing.", + "name": "username", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/UserOpSuccess" + }, + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + } + } + } + }, + "/user_1/{username}": { + "put": { + "tags": [ + "user" + ], + "summary": "Update user", + "description": "This can only be done by the logged in user.", + "operationId": "updateUser_1", + "parameters": [ + { + "description": " name that need to be updated.", + "name": "username", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StructPart" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/StructPart" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/StructPart" + } + } + }, + "required": true + }, + "responses": { + "200": { + "$ref": "#/components/responses/UserOpSuccess" + }, + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/userLink/{username}": { + "put": { + "tags": [ + "user" + ], + "summary": "Update user", + "description": "This can only be done by the logged in user.", + "operationId": "updateUserLink", + "parameters": [ + { + "description": " name that need to be updated.", + "name": "username", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "links": { + "address": { + "operationId": "getUserByName", + "parameters": { + "username": "$request.path.username" + } + } + } + }, + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/userLinkByRef/{username}": { + "put": { + "tags": [ + "user" + ], + "summary": "Update user", + "description": "This can only be done by the logged in user.", + "operationId": "updateUserLinkByRef", + "parameters": [ + { + "description": " name that need to be updated.", + "name": "username", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "links": { + "address2": { + "$ref": "#/components/links/address" + } + } + }, + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/api/v4/paet/{petId}": { + "put": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store with form data", + "operationId": "updatepaet", + "parameters": [ + { + "examples": { + "user": { + "summary": "User Example", + "value": "http://foo.bar/examples/user-example.json" + }, + "user1": { + "summary": "User Example in XML", + "value": "http://foo.bar/examples/user-example.xml" + }, + "user2": { + "summary": "User Example in Plain text", + "value": "http://foo.bar/examples/user-example.txt" + }, + "user3": { + "summary": "User example in other forma", + "value": "http://foo.bar/examples/user-example.whatever" + } + }, + "name": "petId", + "in": "path", + "required": true, + "description": "ID of pet that needs to be updated", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Updated name of the pet" + }, + "status": { + "type": "string", + "description": "Updated status of the pet" + } + }, + "required": [ + "status" + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Pet updated.", + "content": { + "application/json": {}, + "application/xml": {} + } + }, + "405": { + "description": "Method Not Allowed", + "content": { + "application/json": {}, + "application/xml": {} + } + } + } + } + }, + "/api/v4/paet2/{petId}": { + "put": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store with form data", + "operationId": "updatepaet2", + "parameters": [ + { + "description": "ID of pet that needs to be updated", + "name": "petId", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "requestBody": { + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "description": "user to add to the system" + }, + "responses": { + "200": { + "description": "Pet updated.", + "content": { + "application/json": {}, + "application/xml": {} + } + }, + "405": { + "description": "Method Not Allowed", + "content": { + "application/json": {}, + "application/xml": {} + } + } + } + } + }, + "/api/v4/paet3/{petId}": { + "put": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store with form data", + "operationId": "updatepaet3", + "parameters": [ + { + "description": "ID of pet that needs to be updated", + "name": "petId", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewCat" + }, + "examples": { + "cat": { + "summary": "An example of a cat", + "value": { + "color": "White", + "name": "Fluffy", + "petType": "Cat", + "gender": "male", + "breed": "Persian" + } + }, + "dog": { + "summary": "An example of a dog with a cat's name", + "value": { + "color": "Black", + "name": "Puma", + "petType": "Dog", + "gender": "Female", + "breed": "Mixed" + } + }, + "frog-example": { + "$ref": "#/components/examples/frog-example" + } + } + } + }, + "description": "user to add to the system" + }, + "responses": { + "200": { + "description": "Pet updated.", + "content": { + "application/json": {}, + "application/xml": {} + } + }, + "4XX": { + "description": "Method Not Allowed", + "content": { + "application/json": {}, + "application/xml": {} + } + } + } + } + }, + "/api/v4/paet4/{petId}": { + "put": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store with form data", + "operationId": "updatepaet4", + "parameters": [ + { + "description": "ID of pet that needs to be updated", + "name": "petId", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "required": true, + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + }, + "examples": { + "cat": { + "summary": "An example of a cat", + "value": { + "color": "White", + "name": "Fluffy", + "petType": "Cat", + "gender": "male", + "breed": "Persian" + } + }, + "dog": { + "summary": "An example of a dog with a cat's name", + "value": { + "color": "Black", + "name": "Puma", + "petType": "Dog", + "gender": "Female", + "breed": "Mixed" + } + }, + "frog-example": { + "$ref": "#/components/examples/frog-example" + } + } + } + }, + "description": "user to add to the system" + }, + "responses": { + "200": { + "description": "Pet updated.", + "content": { + "application/xml": {}, + "application/json": {} + } + }, + "405": { + "description": "Method Not Allowed", + "content": { + "application/json": {}, + "application/xml": {} + } + } + } + } + }, + "/api/v4/pat/{petId}": { + "put": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store with form data", + "operationId": "updatePasdadaetWithForm", + "parameters": [ + { + "description": "ID of pet that needs to be updated", + "name": "petId", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + }, + "examples": { + "user": { + "summary": "User Example", + "externalValue": "http://foo.bar/examples/user-example.json" + } + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + }, + "examples": { + "user": { + "summary": "User Example in XML", + "externalValue": "http://foo.bar/examples/user-example.xml" + } + } + }, + "text/plain": { + "examples": { + "user": { + "summary": "User Example in Plain text", + "externalValue": "http://foo.bar/examples/user-example.txt" + } + } + }, + "\"*/*\"": { + "examples": { + "user": { + "summary": "User example in other forma", + "externalValue": "http://foo.bar/examples/user-example.whatever" + } + } + } + }, + "description": "user to add to the system" + }, + "responses": { + "200": { + "description": "Pet updated.", + "content": { + "application/json": {}, + "application/xml": {} + } + }, + "405": { + "description": "Method Not Allowed", + "content": { + "application/json": {}, + "application/xml": {} + } + } + } + } + }, + "/pet/{petId}": { + "delete": { + "tags": [ + "pet" + ], + "summary": "Deletes a pet", + "description": "Deletes a pet.", + "operationId": "deletePet", + "parameters": [ + { + "$ref": "#/components/parameters/PetIdParam" + } + ], + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + } + } + }, + "get": { + "tags": [ + "pet" + ], + "summary": "Find pet by ID", + "description": "Returns a single pet.", + "operationId": "getPetById", + "parameters": [ + { + "$ref": "#/components/parameters/PetIdParam" + } + ], + "security": [ + { + "Login-OAuth2": [ + "read" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + } + } + }, + "post": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store", + "description": "Updates a pet in the store with form data", + "operationId": "updatePetWithForm", + "parameters": [ + { + "$ref": "#/components/parameters/PetIdParam" + }, + { + "description": "Name of pet that needs to be updated", + "name": "name", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "description": "Status of pet that needs to be updated", + "name": "status", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "properties": { + "file": { + "type": "array", + "items": { + "type": "string", + "format": "binary" + } + } + } + } + } + } + }, + "security": [ + { + "Login-OAuth2": [ + "write" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Invalid ID supplied" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/store/order/{orderId}": { + "delete": { + "tags": [ + "store" + ], + "summary": "Delete purchase order by ID", + "description": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors.", + "operationId": "deleteOrder", + "parameters": [ + { + "description": " ID of the order that needs to be deleted", + "name": "orderId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + } + ], + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Order not found" + } + } + }, + "get": { + "tags": [ + "store" + ], + "summary": "Find purchase order by ID", + "description": "For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.", + "operationId": "getOrderById", + "parameters": [ + { + "description": "ID of order that needs to be fetched", + "name": "orderId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + } + ], + "servers": [ + { + "description": "ext test server", + "url": "http://ext.server.com/api/v12" + }, + { + "description": "ext test server 13", + "url": "http://ext13.server.com/api/v12" + }, + { + "description": "ext test server 14", + "url": "http://ext14.server.com/api/v12" + }, + { + "url": "/api/v3", + "description": "default endpoint" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Order not found" + } + } + } + }, + "/pet/findByStatus": { + "get": { + "tags": [ + "pet" + ], + "summary": "Finds Pets by status", + "description": "Multiple status values can be provided with comma separated strings", + "operationId": "findPetsByStatus", + "parameters": [ + { + "description": "Status values that need to be considered for filter", + "name": "status", + "schema": { + "type": "string", + "default": "available", + "enum": [ + "available", + "pending", + "sold" + ] + }, + "in": "query" + } + ], + "security": [ + {}, + { + "Login-OAuth2": [ + "read" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "400": { + "description": "Invalid status value" + } + } + } + }, + "/pet/findByTag": { + "get": { + "tags": [ + "pet" + ], + "summary": "Finds Pets by tags", + "description": "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", + "operationId": "findPetsByTags", + "parameters": [ + { + "description": "Tags to filter by", + "name": "tag", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + }, + "in": "query" + } + ], + "security": [ + { + "Login-OAuth2": [ + "read" + ] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "400": { + "description": "Invalid status value" + }, + "default": { + "description": "Unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + } + } + } + } + }, + "/store/inventory": { + "get": { + "tags": [ + "store" + ], + "summary": "Returns pet inventories by status", + "description": "Returns a map of status codes to quantities", + "operationId": "getInventory", + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "none": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/user/login": { + "get": { + "tags": [ + "user" + ], + "summary": "Logs user into the system.", + "description": "Logs user into the system.", + "operationId": "loginUser", + "parameters": [ + { + "description": "The user name for login", + "name": "username", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "description": "The password for login in clear text", + "name": "password", + "schema": { + "type": "string", + "format": "password" + }, + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "headers": { + "X-Rate-Limit": { + "$ref": "#/components/headers/X-Rate-Limit" + }, + "X-Expires-After": { + "$ref": "#/components/headers/X-Expires-After" + } + }, + "content": { + "application/xml": { + "schema": { + "type": "string" + } + }, + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "Invalid username/password supplied" + } + } + } + }, + "/user/logout": { + "get": { + "tags": [ + "user" + ], + "summary": "Logs out current logged in user session.", + "description": "Logs out current logged in user session.", + "operationId": "logoutUser", + "responses": { + "200": { + "description": "Successful operation" + } + } + } + }, + "/peta/{id}": { + "get": { + "summary": "Find pets by ID", + "description": "Returns pets based on ID", + "operationId": "getPetsById", + "parameters": [ + { + "style": "simple", + "name": "id", + "in": "path", + "required": true, + "description": "ID of pet to use", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "pet response", + "content": { + "\"*/*\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "default": { + "description": "error payload", + "content": { + "text/html": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + } + } + } + }, + "/pet/{petId}/uploadImage2": { + "post": { + "tags": [ + "pet" + ], + "summary": "Uploads an image", + "description": "Updates a pet in the store with a new image", + "operationId": "uploadFile2", + "parameters": [ + { + "description": "ID of pet that needs to be updated", + "name": "petId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + }, + { + "description": "Additional Metadata", + "name": "additionalMetadata", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "image": { + "type": "string", + "format": "binary" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "A simple string response", + "headers": { + "X-Rate-Limit-Limit": { + "description": "The number of allowed requests in the current period", + "schema": { + "type": "integer" + } + }, + "X-Rate-Limit-Remaining": { + "description": "The number of remaining requests in the current period", + "schema": { + "type": "integer" + } + }, + "X-Rate-Limit-Reset": { + "description": "The number of seconds left in the current period", + "schema": { + "type": "integer", + "maximum": 3 + } + } + }, + "content": { + "text/plain": { + "schema": { + "type": "string", + "example": "whoa!" + } + } + } + } + } + } + }, + "/pet/{petId}/uploadImageOctet": { + "post": { + "tags": [ + "pet" + ], + "summary": "Uploads an image", + "description": "Updates a pet in the store with a new image", + "operationId": "uploadFileOctet", + "parameters": [ + { + "description": "ID of pet that needs to be updated", + "name": "petId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + }, + { + "description": "Additional Metadata", + "name": "additionalMetadata", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "requestBody": { + "content": { + "application/octet-stream": { + "schema": {} + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/pet/{petId}/uploadmultiImage": { + "post": { + "tags": [ + "pet" + ], + "summary": "Uploads an image", + "description": "Updates a pet in the store with a new image", + "operationId": "uploadFilemulti", + "parameters": [ + { + "description": "ID of pet that needs to be updated", + "name": "petId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + }, + { + "description": "Additional Metadata", + "name": "additionalMetadata", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "orderId": { + "type": "integer" + }, + "image": { + "type": "string" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/pet2/{petId}": { + "post": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store", + "description": "Updates a pet in the store with form data", + "operationId": "updatePet2WithForm", + "parameters": [ + { + "$ref": "#/components/parameters/PetIdParam" + }, + { + "description": "Name of pet that needs to be updated", + "name": "name", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "description": "Status of pet that needs to be updated", + "name": "status", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "address": { + "type": "object", + "properties": {} + } + } + } + } + } + }, + "security": [ + { + "Login-OAuth2": [ + "write" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Invalid ID supplied" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/pet3/{petId}": { + "post": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store", + "description": "Updates a pet in the store with form data", + "operationId": "updatePet3WithForm", + "parameters": [ + { + "$ref": "#/components/parameters/PetIdParam" + }, + { + "description": "Name of pet that needs to be updated", + "name": "name", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "description": "Status of pet that needs to be updated", + "name": "status", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "address": { + "type": "object", + "properties": {} + }, + "children": { + "type": "array", + "items": { + "type": "string" + } + }, + "addresses": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Address" + } + } + } + } + } + } + }, + "security": [ + { + "Login-OAuth2": [ + "write" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Invalid ID supplied" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/pet4/{petId}": { + "post": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store", + "description": "Updates a pet in the store with form data", + "operationId": "updatePet4WithForm", + "parameters": [ + { + "$ref": "#/components/parameters/PetIdParam" + }, + { + "description": "Name of pet that needs to be updated", + "name": "name", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "description": "Status of pet that needs to be updated", + "name": "status", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "encoding": { + "historyMetadata": { + "contentType": "application/xml; charset=utf-8" + }, + "profileImage": { + "contentType": "image/png, image/jpeg", + "headers": { + "X-Rate-Limit-Limit": { + "description": "The number of allowed requests in the current period", + "schema": { + "enum": [ + 1, + 2, + 3 + ], + "default": 3, + "type": "integer", + "maximum": 3 + } + }, + "X-Rate-Limit-Reset": { + "description": "The number of seconds left in the current period", + "schema": { + "type": "integer", + "minimum": 2 + } + } + } + } + }, + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "address": { + "type": "object", + "properties": {} + }, + "historyMetadata": { + "type": "object", + "description": "metadata in XML format", + "properties": {} + }, + "profileImage": { + "type": "string", + "format": "binary" + } + } + } + } + } + }, + "security": [ + { + "Login-OAuth2": [ + "write" + ] + } + ], + "responses": { + "200": { + "description": "A simple string response", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/petcallback": { + "post": { + "tags": [ + "pet" + ], + "summary": "Add a new pet to the store", + "description": "Add a new pet to the store", + "operationId": "addPetcallback", + "requestBody": { + "$ref": "#/components/requestBodies/PetBodySchema" + }, + "callbacks": { + "test": { + "'{$request.body#/id}'": { + "post": { + "requestBody": { + "content": { + "\"*/*\"": { + "schema": { + "type": "string" + } + } + } + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + }, + "default": { + "description": "Something is wrong" + } + } + } + } + } + }, + "security": [ + { + "Login-OAuth2": [ + "write" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "405": { + "description": "Validation exception", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "result": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/petcallbackReference": { + "post": { + "tags": [ + "pet" + ], + "summary": "Add a new pet to the store", + "description": "Add a new pet to the store", + "operationId": "petcallbackReference", + "requestBody": { + "$ref": "#/components/requestBodies/PetBodySchema" + }, + "callbacks": { + "test1": { + "$ref": "#/components/callbacks/test" + } + }, + "security": [ + { + "Login-OAuth2": [ + "write" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "405": { + "description": "Validation exception", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "result": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/store/order": { + "post": { + "deprecated": true, + "tags": [ + "store" + ], + "summary": "Place an order for a pet", + "description": "Place a new order in the store", + "operationId": "placeOrder", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + } + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/user": { + "post": { + "tags": [ + "user" + ], + "summary": "Create user.", + "description": "This can only be done by the logged in user.", + "operationId": "createUser", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "responses": { + "200": { + "$ref": "#/components/responses/UserOpSuccess" + }, + "405": { + "description": "Invalid Input", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "result": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/user/createWithList": { + "post": { + "tags": [ + "user" + ], + "summary": "Creates list of users with given input array.", + "description": "Creates list of users with given input array.", + "operationId": "createUsersWithListInput", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "responses": { + "200": { + "$ref": "#/components/responses/UserOpSuccess" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/close": { + "post": { + "summary": "Shutdown the server", + "responses": { + "200": { + "description": "Successful operation" + } + } + } + }, + "/stores/order/{orderId}": { + "get": { + "tags": [ + "store" + ], + "summary": "Find purchase order by ID", + "description": "For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.", + "operationId": "getOrderExternalById", + "parameters": [ + { + "description": "ID of order that needs to be fetched", + "name": "orderId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + } + ], + "servers": [ + { + "description": "ext test server", + "url": "http://ext.server.com/api/v12" + }, + { + "description": "ext test server 13", + "url": "http://ext13.server.com/api/v12" + }, + { + "description": "ext test server 14", + "url": "http://ext14.server.com/api/v12" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Order not found" + } + } + } + } + }, + "components": { + "schemas": { + "Address": { + "type": "object", + "description": "Shipping Address", + "xml": { + "name": "address" + }, + "properties": { + "street": { + "type": "string", + "example": "437 Lytton" + }, + "city": { + "type": "string", + "example": "Palo Alto" + }, + "state": { + "type": "string", + "example": "CA" + }, + "zip": { + "type": "string", + "example": "94031" + } + }, + "required": [ + "street", + "city", + "state", + "zip" + ] + }, + "Order": { + "type": "object", + "xml": { + "name": "order" + }, + "properties": { + "id": { + "type": "integer", + "readOnly": true, + "example": 10, + "format": "int64" + }, + "petId": { + "type": "integer", + "example": 198772, + "format": "int64" + }, + "quantity": { + "type": "integer", + "example": 7, + "format": "int32" + }, + "shipDate": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string", + "description": "Order Status", + "example": "approved", + "enum": [ + "placed", + "approved", + "delivered" + ] + }, + "complete": { + "type": "boolean" + }, + "Address": { + "$ref": "#/components/schemas/Address" + } + }, + "additionalProperties": { + "type": "string" + } + }, + "Category": { + "type": "object", + "xml": { + "name": "category" + }, + "properties": { + "id": { + "type": "integer", + "example": 1, + "format": "int64" + }, + "name": { + "type": "string", + "example": "Dogs" + } + } + }, + "User": { + "type": "object", + "xml": { + "name": "user" + }, + "properties": { + "id": { + "type": "integer", + "readOnly": true, + "example": 1, + "format": "int64" + }, + "username": { + "type": "string", + "example": "theUser" + }, + "firstName": { + "type": "string", + "example": "John" + }, + "lastName": { + "type": "string", + "example": "James" + }, + "email": { + "type": "string", + "example": "john@email.com", + "format": "email" + }, + "password": { + "type": "string", + "example": "12345", + "format": "password" + }, + "phone": { + "type": "string", + "example": "12345" + }, + "userStatus": { + "type": "integer", + "description": "User Status", + "example": 1, + "format": "int32" + } + }, + "required": [ + "username", + "password" + ] + }, + "aaaaa": { + "allOf": [ + { + "$ref": "#/components/schemas/Address" + }, + { + "$ref": "#/components/schemas/User" + } + ] + }, + "Tag": { + "type": "object", + "xml": { + "name": "tag" + }, + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + } + } + }, + "Pet": { + "type": "object", + "xml": { + "name": "pet" + }, + "properties": { + "id": { + "type": "integer", + "readOnly": true, + "example": [ + 10, + 2, + 4 + ], + "format": "int64" + }, + "name": { + "type": "string", + "example": "doggie" + }, + "category": { + "$ref": "#/components/schemas/Category" + }, + "petType": { + "type": "string", + "example": "dog" + }, + "photoUrls": { + "type": "array", + "items": { + "type": "string" + } + }, + "tags": { + "$ref": "#/components/schemas/Tag" + }, + "status": { + "type": "string", + "description": "pet status in the store", + "enum": [ + "available", + "pending", + "sold" + ] + } + }, + "required": [ + "name", + "petType" + ] + }, + "NewCat": { + "allOf": [ + { + "$ref": "#/components/schemas/Pet" + }, + { + "type": "object", + "properties": { + "huntingSkill": { + "type": "string", + "description": "The measured skill for hunting", + "enum": [ + "clueless", + "lazy", + "adventurous", + "aggressive" + ] + } + } + } + ] + }, + "XmlPrefixAndNamespace": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "xml": { + "attribute": true + }, + "format": "int32" + }, + "name": { + "type": "string", + "xml": { + "namespace": "http://example.com/schema/sample", + "prefix": "sample" + } + } + } + }, + "animals": { + "type": "array", + "items": { + "type": "string", + "xml": { + "name": "animal" + } + } + }, + "AnimalsNoAliens": { + "type": "array", + "xml": { + "name": "aliens" + }, + "items": { + "type": "string", + "xml": { + "name": "animal" + } + } + }, + "WrappedAnimals": { + "type": "array", + "xml": { + "wrapped": true + }, + "items": { + "type": "string" + } + }, + "WrappedAnimal": { + "type": "array", + "xml": { + "wrapped": true + }, + "items": { + "type": "string", + "xml": { + "name": "animal" + } + } + }, + "WrappedAliens": { + "type": "array", + "xml": { + "name": "aliens", + "wrapped": true + }, + "items": { + "type": "string", + "xml": { + "name": "animal" + } + } + }, + "WrappedAliensWithItems": { + "type": "array", + "xml": { + "name": "aliens", + "wrapped": true + }, + "items": { + "type": "string" + } + }, + "StructPart": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "children": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StructPart" + } + } + } + }, + "Pet2": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "petType": { + "type": "string" + } + }, + "discriminator": { + "propertyName": "petType" + } + }, + "Cat2": { + "allOf": [ + { + "$ref": "#/components/schemas/Pet2" + }, + { + "properties": { + "huntingSkill": { + "type": "string", + "description": "The measured skill for hunting", + "default": "lazy", + "enum": [ + "clueless", + "lazy", + "adventurous", + "aggressive" + ] + } + }, + "type": "object", + "required": [ + "huntingSkill" + ] + } + ], + "description": "A representation of a cat. Note that Cat will be used as the discriminator value." + }, + "Dog2": { + "allOf": [ + { + "$ref": "#/components/schemas/Pet2" + }, + { + "properties": { + "packSize": { + "type": "integer", + "description": "the size of the pack the dog is from", + "minimum": 0, + "format": "int32" + } + }, + "type": "object", + "required": [ + "packSize" + ] + } + ], + "description": "A representation of a dog. Note that Dog will be used as the discriminator value." + }, + "ExtendedErrorModel": { + "allOf": [ + { + "$ref": "#/components/schemas/Pet" + }, + { + "properties": { + "rootCause": { + "type": "string" + } + }, + "type": "object", + "required": [ + "rootCause" + ] + } + ] + }, + "Cat": { + "type": "object", + "description": "Type of cat", + "properties": { + "breed": { + "type": "string", + "description": "Type of Breed", + "enum": [ + "Abyssinian", + "Balinese-Javanese", + "Burmese", + "British Shorthair" + ] + } + }, + "allOf": [ + { + "$ref": "#/components/schemas/Pet" + }, + { + "properties": { + "huntingSkill": { + "type": "string", + "description": "The measured skill for hunting", + "enum": [ + "clueless", + "lazy", + "adventurous", + "aggressive" + ] + } + }, + "type": "object" + } + ] + }, + "Dog": { + "allOf": [ + { + "$ref": "#/components/schemas/Pet" + }, + { + "type": "object", + "properties": { + "breed": { + "type": "string", + "description": "Type of Breed", + "enum": [ + "Dingo", + "Husky", + "Retriever", + "Shepherd" + ] + }, + "bark": { + "type": "boolean" + } + } + } + ] + }, + "Pets": { + "oneOf": [ + { + "$ref": "#/components/schemas/Cat" + }, + { + "$ref": "#/components/schemas/Dog" + } + ], + "discriminator": { + "propertyName": "petType" + } + }, + "ApiResponse": { + "type": "object", + "xml": { + "name": "##default" + }, + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "type": { + "type": "string", + "example": "doggie" + }, + "message": { + "type": "string" + } + } + }, + "ErrorModel": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": "integer", + "format": "int32" + } + } + } + }, + "responses": { + "UserOpSuccess": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + } + }, + "parameters": { + "PetIdParam": { + "description": "ID of the pet", + "name": "petId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + } + }, + "examples": { + "frog-example": { + "summary": "An example of a frog with a cat's name", + "value": { + "color": "Lion", + "name": "Jaguar", + "petType": "Panthera", + "gender": "Male", + "breed": "Mantella Baroni" + } + } + }, + "requestBodies": { + "PetBodySchema": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pets" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Pets" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pets" + } + } + }, + "required": true, + "description": "Pet in the store" + } + }, + "headers": { + "X-Rate-Limit": { + "schema": { + "type": "integer", + "format": "int32" + } + }, + "X-Expires-After": { + "schema": { + "type": "string", + "format": "date-time" + } + } + }, + "links": { + "address": { + "operationId": "getUserByName", + "parameters": { + "username": "$request.path.username" + } + } + }, + "callbacks": { + "test": { + "'{$request.body#/id}'": { + "post": { + "requestBody": { + "content": { + "\"*/*\"": { + "schema": { + "type": "string" + } + } + } + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + }, + "default": { + "description": "Something is wrong" + } + } + } + } + } + }, + "securitySchemes": { + "Login": { + "scheme": "basic", + "type": "http" + }, + "LoginApiKey": { + "type": "apiKey", + "in": "header", + "name": "X-API-KEY" + }, + "api_key": { + "type": "apiKey", + "in": "header", + "name": "api_key" + }, + "Jwt": { + "scheme": "bearer", + "type": "http" + }, + "Login-OAuth2": { + "type": "oauth2", + "flows": { + "authorizationCode": { + "tokenUrl": "http://example.org/api/oauth/token", + "authorizationUrl": "http://example.org/api/oauth/dialog", + "scopes": { + "read": "Grant read-only access to all your data except for the account and user info", + "write": "Grant write-only access to all your data except for the account and user info" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/integration/specs/OpenApi-TuttiFrutti_3.1.0.json b/tests/integration/specs/OpenApi-TuttiFrutti_3.1.0.json new file mode 100644 index 000000000..c3a5d1de2 --- /dev/null +++ b/tests/integration/specs/OpenApi-TuttiFrutti_3.1.0.json @@ -0,0 +1,2837 @@ +{ + "openapi": "3.1.0", + "jsonSchemaDialect": "https://spec.openapis.org/oas/3.1/dialect/base", + "info": { + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "title": "Swagger Petstore - OpenAPI 3.1", + "version": "1.0.17", + "description": "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about Swagger at [http://swagger.io](http://swagger.io).\r\nIn the third iteration of the pet store, we've switched to the design first approach!\r\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\r\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\r\n\r\nSome useful links:\r\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\r\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)", + "termsOfService": "http://swagger.io/terms/", + "contact": { + "name": "API Support", + "email": "apiteam@swagger.io" + } + }, + "externalDocs": { + "description": "Find out more about Swagger", + "url": "http://swagger.io" + }, + "servers": [ + { + "url": "/api/v3", + "description": "default endpoint" + } + ], + "tags": [ + { + "name": "user", + "description": "Operations about user", + "externalDocs": { + "description": "Find out more about Swagger", + "url": "http://swagger.io" + } + }, + { + "name": "store", + "description": "Access to Petstore orders", + "externalDocs": { + "description": "Find out more about Swagger", + "url": "http://swagger.io" + } + }, + { + "name": "pet", + "description": "Everything about your Pets", + "externalDocs": { + "description": "Find out more about Swagger", + "url": "http://swagger.io" + } + } + ], + "paths": { + "/pet": { + "put": { + "tags": [ + "pet" + ], + "summary": "Update an existing pet", + "description": "Update an existing pet by Id", + "operationId": "updatePet", + "requestBody": { + "$ref": "#/components/requestBodies/PetBodySchema" + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + }, + "405": { + "description": "Validation exception", + "content": { + "application/json": { + "schema": { + "type": [ + "object" + ], + "properties": { + "result": { + "type": [ + "string" + ] + }, + "message": { + "type": [ + "string" + ] + } + } + } + } + } + } + } + }, + "post": { + "tags": [ + "pet" + ], + "summary": "Add a new pet to the store", + "description": "Add a new pet to the store", + "operationId": "addPet", + "requestBody": { + "$ref": "#/components/requestBodies/PetBodySchema" + }, + "security": [ + { + "Login-OAuth2": [ + "write" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "405": { + "description": "Validation exception", + "content": { + "application/json": { + "schema": { + "type": [ + "object" + ], + "properties": { + "result": { + "type": [ + "string" + ] + }, + "message": { + "type": [ + "string" + ] + } + } + } + } + } + } + } + } + }, + "/user/{username}": { + "put": { + "tags": [ + "user" + ], + "summary": "Update user", + "description": "This can only be done by the logged in user.", + "operationId": "updateUser", + "parameters": [ + { + "description": " name that need to be updated.", + "name": "username", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "responses": { + "200": { + "$ref": "#/components/responses/UserOpSuccess" + }, + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + }, + "405": { + "description": "Invalid Input" + } + } + }, + "delete": { + "tags": [ + "user" + ], + "summary": "Delete user", + "description": "This can only be done by the logged in user.", + "operationId": "deleteUser", + "parameters": [ + { + "description": "The name that needs to be deleted.", + "name": "username", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + } + } + }, + "get": { + "tags": [ + "user" + ], + "summary": "Get user by user name", + "description": "Get user by user name.", + "operationId": "getUserByName", + "parameters": [ + { + "description": "The name that needs to be fetched. Use user1 for testing.", + "name": "username", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/UserOpSuccess" + }, + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + } + } + } + }, + "/user_1/{username}": { + "put": { + "tags": [ + "user" + ], + "summary": "Update user", + "description": "This can only be done by the logged in user.", + "operationId": "updateUser_1", + "parameters": [ + { + "description": " name that need to be updated.", + "name": "username", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StructPart" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/StructPart" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/StructPart" + } + } + }, + "required": true + }, + "responses": { + "200": { + "$ref": "#/components/responses/UserOpSuccess" + }, + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/userLink/{username}": { + "put": { + "tags": [ + "user" + ], + "summary": "Update user", + "description": "This can only be done by the logged in user.", + "operationId": "updateUserLink", + "parameters": [ + { + "description": " name that need to be updated.", + "name": "username", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "links": { + "address": { + "operationId": "getUserByName", + "parameters": { + "username": "$request.path.username" + } + } + } + }, + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/userLinkByRef/{username}": { + "put": { + "tags": [ + "user" + ], + "summary": "Update user", + "description": "This can only be done by the logged in user.", + "operationId": "updateUserLinkByRef", + "parameters": [ + { + "description": " name that need to be updated.", + "name": "username", + "required": true, + "schema": { + "type": "string" + }, + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "links": { + "address2": { + "$ref": "#/components/links/address" + } + } + }, + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/pet/{petId}": { + "delete": { + "tags": [ + "pet" + ], + "summary": "Deletes a pet", + "description": "Deletes a pet.", + "operationId": "deletePet", + "parameters": [ + { + "$ref": "#/components/parameters/PetIdParam" + } + ], + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + } + } + }, + "get": { + "tags": [ + "pet" + ], + "summary": "Find pet by ID", + "description": "Returns a single pet.", + "operationId": "getPetById", + "parameters": [ + { + "$ref": "#/components/parameters/PetIdParam" + } + ], + "security": [ + { + "Login-OAuth2": [ + "read" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + } + } + }, + "post": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store", + "description": "Updates a pet in the store with form data", + "operationId": "updatePetWithForm", + "parameters": [ + { + "$ref": "#/components/parameters/PetIdParam" + }, + { + "description": "Name of pet that needs to be updated", + "name": "name", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "description": "Status of pet that needs to be updated", + "name": "status", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "properties": { + "file": { + "type": "array", + "items": { + "type": [ + "string" + ], + "format": "binary" + } + } + } + } + } + } + }, + "security": [ + { + "Login-OAuth2": [ + "write" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Invalid ID supplied" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/store/order/{orderId}": { + "delete": { + "tags": [ + "store" + ], + "summary": "Delete purchase order by ID", + "description": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors.", + "operationId": "deleteOrder", + "parameters": [ + { + "description": " ID of the order that needs to be deleted", + "name": "orderId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + } + ], + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Order not found" + } + } + }, + "get": { + "tags": [ + "store" + ], + "summary": "Find purchase order by ID", + "description": "For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.", + "operationId": "getOrderById", + "parameters": [ + { + "description": "ID of order that needs to be fetched", + "name": "orderId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + } + ], + "servers": [ + { + "description": "ext test server", + "url": "http://ext.server.com/api/v12" + }, + { + "description": "ext test server 13", + "url": "http://ext13.server.com/api/v12" + }, + { + "description": "ext test server 14", + "url": "http://ext14.server.com/api/v12" + }, + { + "url": "/api/v3", + "description": "default endpoint" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Order not found" + } + } + } + }, + "/pet/findByStatus": { + "get": { + "tags": [ + "pet" + ], + "summary": "Finds Pets by status", + "description": "Multiple status values can be provided with comma separated strings", + "operationId": "findPetsByStatus", + "parameters": [ + { + "description": "Status values that need to be considered for filter", + "name": "status", + "schema": { + "type": "string", + "default": "available", + "enum": [ + "available", + "pending", + "sold" + ] + }, + "in": "query" + } + ], + "security": [ + {}, + { + "Login-OAuth2": [ + "read" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "400": { + "description": "Invalid status value" + } + } + } + }, + "/pet/findByTag": { + "get": { + "tags": [ + "pet" + ], + "summary": "Finds Pets by tags", + "description": "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", + "operationId": "findPetsByTags", + "parameters": [ + { + "description": "Tags to filter by", + "name": "tag", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + }, + "in": "query" + } + ], + "security": [ + { + "Login-OAuth2": [ + "read" + ] + }, + { + "api_key": [] + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "400": { + "description": "Invalid status value" + }, + "default": { + "description": "Unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorModel" + } + } + } + } + } + } + }, + "/store/inventory": { + "get": { + "tags": [ + "store" + ], + "summary": "Returns pet inventories by status", + "description": "Returns a map of status codes to quantities", + "operationId": "getInventory", + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "type": [ + "object" + ], + "properties": { + "none": { + "type": [ + "string" + ] + } + } + } + } + } + } + } + } + }, + "/user/login": { + "get": { + "tags": [ + "user" + ], + "summary": "Logs user into the system.", + "description": "Logs user into the system.", + "operationId": "loginUser", + "parameters": [ + { + "description": "The user name for login", + "name": "username", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "description": "The password for login in clear text", + "name": "password", + "schema": { + "type": "string", + "format": "password" + }, + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "headers": { + "X-Rate-Limit": { + "$ref": "#/components/headers/X-Rate-Limit" + }, + "X-Expires-After": { + "$ref": "#/components/headers/X-Expires-After" + } + }, + "content": { + "application/xml": { + "schema": { + "type": "string" + } + }, + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "Invalid username/password supplied" + } + } + } + }, + "/user/logout": { + "get": { + "tags": [ + "user" + ], + "summary": "Logs out current logged in user session.", + "description": "Logs out current logged in user session.", + "operationId": "logoutUser", + "responses": { + "200": { + "description": "Successful operation" + } + } + } + }, + "/peta/{id}": { + "get": { + "summary": "Find pets by ID", + "description": "Returns pets based on ID", + "operationId": "getPetsById", + "parameters": [ + { + "style": "simple", + "name": "id", + "in": "path", + "required": true, + "description": "ID of pet to use", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "pet response", + "content": { + "\"*/*\"": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "default": { + "description": "error payload", + "content": { + "text/html": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + } + } + } + }, + "/pet/{petId}/uploadImage2": { + "post": { + "tags": [ + "pet" + ], + "summary": "Uploads an image", + "description": "Updates a pet in the store with a new image", + "operationId": "uploadFile2", + "parameters": [ + { + "description": "ID of pet that needs to be updated", + "name": "petId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + }, + { + "description": "Additional Metadata", + "name": "additionalMetadata", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": [ + "object" + ], + "properties": { + "image": { + "type": [ + "string" + ], + "format": "binary" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "A simple string response", + "headers": { + "X-Rate-Limit-Limit": { + "description": "The number of allowed requests in the current period", + "schema": { + "type": "integer" + } + }, + "X-Rate-Limit-Remaining": { + "description": "The number of remaining requests in the current period", + "schema": { + "type": "integer" + } + }, + "X-Rate-Limit-Reset": { + "description": "The number of seconds left in the current period", + "schema": { + "type": "integer", + "maximum": 3 + } + } + }, + "content": { + "text/plain": { + "schema": { + "type": [ + "string" + ], + "examples": [ + "whoa!" + ] + } + } + } + } + } + } + }, + "/pet/{petId}/uploadImageOctet": { + "post": { + "tags": [ + "pet" + ], + "summary": "Uploads an image", + "description": "Updates a pet in the store with a new image", + "operationId": "uploadFileOctet", + "parameters": [ + { + "description": "ID of pet that needs to be updated", + "name": "petId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + }, + { + "description": "Additional Metadata", + "name": "additionalMetadata", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "requestBody": { + "content": { + "application/octet-stream": { + "schema": {} + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/pet/{petId}/uploadmultiImage": { + "post": { + "tags": [ + "pet" + ], + "summary": "Uploads an image", + "description": "Updates a pet in the store with a new image", + "operationId": "uploadFilemulti", + "parameters": [ + { + "description": "ID of pet that needs to be updated", + "name": "petId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + }, + { + "description": "Additional Metadata", + "name": "additionalMetadata", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": [ + "object" + ], + "properties": { + "orderId": { + "type": [ + "integer" + ] + }, + "image": { + "type": [ + "string" + ] + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiResponse" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/pet2/{petId}": { + "post": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store", + "description": "Updates a pet in the store with form data", + "operationId": "updatePet2WithForm", + "parameters": [ + { + "$ref": "#/components/parameters/PetIdParam" + }, + { + "description": "Name of pet that needs to be updated", + "name": "name", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "description": "Status of pet that needs to be updated", + "name": "status", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "type": [ + "object" + ], + "properties": { + "id": { + "type": [ + "string" + ], + "format": "uuid" + }, + "address": { + "type": [ + "object" + ], + "properties": {} + } + } + } + } + } + }, + "security": [ + { + "Login-OAuth2": [ + "write" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Invalid ID supplied" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/pet3/{petId}": { + "post": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store", + "description": "Updates a pet in the store with form data", + "operationId": "updatePet3WithForm", + "parameters": [ + { + "$ref": "#/components/parameters/PetIdParam" + }, + { + "description": "Name of pet that needs to be updated", + "name": "name", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "description": "Status of pet that needs to be updated", + "name": "status", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": [ + "object" + ], + "properties": { + "id": { + "type": [ + "string" + ], + "format": "uuid" + }, + "address": { + "type": [ + "object" + ], + "properties": {} + }, + "children": { + "type": "array", + "items": { + "type": [ + "string" + ] + } + }, + "addresses": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Address" + } + } + } + } + } + } + }, + "security": [ + { + "Login-OAuth2": [ + "write" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation" + }, + "400": { + "description": "Invalid ID supplied" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/pet4/{petId}": { + "post": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store", + "description": "Updates a pet in the store with form data", + "operationId": "updatePet4WithForm", + "parameters": [ + { + "$ref": "#/components/parameters/PetIdParam" + }, + { + "description": "Name of pet that needs to be updated", + "name": "name", + "schema": { + "type": "string" + }, + "in": "query" + }, + { + "description": "Status of pet that needs to be updated", + "name": "status", + "schema": { + "type": "string" + }, + "in": "query" + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "encoding": { + "historyMetadata": { + "contentType": "application/xml; charset=utf-8" + }, + "profileImage": { + "contentType": "image/png, image/jpeg", + "headers": { + "X-Rate-Limit-Limit": { + "description": "The number of allowed requests in the current period", + "schema": { + "enum": [ + 1, + 2, + 3 + ], + "default": 3, + "type": "integer", + "maximum": 3 + } + }, + "X-Rate-Limit-Reset": { + "description": "The number of seconds left in the current period", + "schema": { + "type": "integer", + "minimum": 2 + } + } + } + } + }, + "schema": { + "type": [ + "object" + ], + "properties": { + "id": { + "type": [ + "string" + ], + "format": "uuid" + }, + "address": { + "type": [ + "object" + ], + "properties": {} + }, + "historyMetadata": { + "type": [ + "object" + ], + "description": "metadata in XML format", + "properties": {} + }, + "profileImage": { + "type": [ + "string" + ], + "format": "binary" + } + } + } + } + } + }, + "security": [ + { + "Login-OAuth2": [ + "write" + ] + } + ], + "responses": { + "200": { + "description": "A simple string response", + "content": { + "text/plain": { + "schema": { + "type": [ + "string" + ] + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/petcallback": { + "post": { + "tags": [ + "pet" + ], + "summary": "Add a new pet to the store", + "description": "Add a new pet to the store", + "operationId": "addPetcallback", + "requestBody": { + "$ref": "#/components/requestBodies/PetBodySchema" + }, + "callbacks": { + "test": { + "'{$request.body#/id}'": { + "post": { + "requestBody": { + "content": { + "\"*/*\"": { + "schema": { + "type": [ + "string" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + }, + "default": { + "description": "Something is wrong" + } + } + } + } + } + }, + "security": [ + { + "Login-OAuth2": [ + "write" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "405": { + "description": "Validation exception", + "content": { + "application/json": { + "schema": { + "type": [ + "object" + ], + "properties": { + "result": { + "type": [ + "string" + ] + }, + "message": { + "type": [ + "string" + ] + } + } + } + } + } + } + } + } + }, + "/petcallbackReference": { + "post": { + "tags": [ + "pet" + ], + "summary": "Add a new pet to the store", + "description": "Add a new pet to the store", + "operationId": "petcallbackReference", + "requestBody": { + "$ref": "#/components/requestBodies/PetBodySchema" + }, + "callbacks": { + "test1": { + "$ref": "#/components/callbacks/test" + } + }, + "security": [ + { + "Login-OAuth2": [ + "write" + ] + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "405": { + "description": "Validation exception", + "content": { + "application/json": { + "schema": { + "type": [ + "object" + ], + "properties": { + "result": { + "type": [ + "string" + ] + }, + "message": { + "type": [ + "string" + ] + } + } + } + } + } + } + } + } + }, + "/store/order": { + "post": { + "deprecated": true, + "tags": [ + "store" + ], + "summary": "Place an order for a pet", + "description": "Place a new order in the store", + "operationId": "placeOrder", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + } + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/user": { + "post": { + "tags": [ + "user" + ], + "summary": "Create user.", + "description": "This can only be done by the logged in user.", + "operationId": "createUser", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "responses": { + "200": { + "$ref": "#/components/responses/UserOpSuccess" + }, + "405": { + "description": "Invalid Input", + "content": { + "application/json": { + "schema": { + "type": [ + "object" + ], + "properties": { + "result": { + "type": [ + "string" + ] + }, + "message": { + "type": [ + "string" + ] + } + } + } + } + } + } + } + } + }, + "/user/createWithList": { + "post": { + "tags": [ + "user" + ], + "summary": "Creates list of users with given input array.", + "description": "Creates list of users with given input array.", + "operationId": "createUsersWithListInput", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "required": true + }, + "responses": { + "200": { + "$ref": "#/components/responses/UserOpSuccess" + }, + "405": { + "description": "Invalid Input" + } + } + } + }, + "/close": { + "post": { + "summary": "Shutdown the server", + "responses": { + "200": { + "description": "Successful operation" + } + } + } + }, + "/stores/order/{orderId}": { + "get": { + "tags": [ + "store" + ], + "summary": "Find purchase order by ID", + "description": "For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.", + "operationId": "getOrderExternalById", + "parameters": [ + { + "description": "ID of order that needs to be fetched", + "name": "orderId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + } + ], + "servers": [ + { + "description": "ext test server", + "url": "http://ext.server.com/api/v12" + }, + { + "description": "ext test server 13", + "url": "http://ext13.server.com/api/v12" + }, + { + "description": "ext test server 14", + "url": "http://ext14.server.com/api/v12" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Order" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Order" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Order not found" + } + } + } + } + }, + "webhooks": { + "newPet": { + "post": { + "description": "Information about a new pet in the system", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pets" + } + } + } + }, + "responses": { + "200": { + "description": "Return a 200 status to indicate that the data was received successfully" + } + } + } + } + }, + "components": { + "schemas": { + "Address": { + "type": [ + "object" + ], + "description": "Shipping Address", + "xml": { + "name": "address" + }, + "properties": { + "street": { + "type": [ + "string" + ], + "examples": [ + "437 Lytton" + ] + }, + "city": { + "type": [ + "string" + ], + "examples": [ + "Palo Alto" + ] + }, + "state": { + "type": [ + "string" + ], + "examples": [ + "CA" + ] + }, + "zip": { + "type": [ + "string" + ], + "examples": [ + "94031" + ] + } + }, + "required": [ + "street", + "city", + "state", + "zip" + ] + }, + "Order": { + "type": [ + "object" + ], + "xml": { + "name": "order" + }, + "properties": { + "id": { + "type": [ + "integer" + ], + "readOnly": true, + "examples": [ + 10 + ], + "format": "int64" + }, + "petId": { + "type": [ + "integer" + ], + "examples": [ + 198772 + ], + "format": "int64" + }, + "quantity": { + "type": [ + "integer" + ], + "examples": [ + 7 + ], + "format": "int32" + }, + "shipDate": { + "type": [ + "string" + ], + "format": "date-time" + }, + "status": { + "type": [ + "string" + ], + "description": "Order Status", + "examples": [ + "approved" + ], + "enum": [ + "placed", + "approved", + "delivered" + ] + }, + "complete": { + "type": [ + "boolean" + ] + }, + "Address": { + "$ref": "#/components/schemas/Address" + } + }, + "additionalProperties": { + "type": [ + "string" + ] + } + }, + "Category": { + "type": [ + "object" + ], + "xml": { + "name": "category" + }, + "properties": { + "id": { + "type": [ + "integer" + ], + "examples": [ + 1 + ], + "format": "int64" + }, + "name": { + "type": [ + "string" + ], + "examples": [ + "Dogs" + ] + } + } + }, + "User": { + "type": [ + "object" + ], + "xml": { + "name": "user" + }, + "properties": { + "id": { + "type": [ + "integer" + ], + "readOnly": true, + "examples": [ + 1 + ], + "format": "int64" + }, + "username": { + "type": [ + "string" + ], + "examples": [ + "theUser" + ] + }, + "firstName": { + "type": [ + "string" + ], + "examples": [ + "John" + ] + }, + "lastName": { + "type": [ + "string" + ], + "examples": [ + "James" + ] + }, + "email": { + "type": [ + "string" + ], + "examples": [ + "john@email.com" + ], + "format": "email" + }, + "password": { + "type": [ + "string" + ], + "examples": [ + "12345" + ], + "format": "password" + }, + "phone": { + "type": [ + "string" + ], + "examples": [ + "12345" + ] + }, + "userStatus": { + "type": [ + "integer" + ], + "description": "User Status", + "examples": [ + 1 + ], + "format": "int32" + } + }, + "required": [ + "username", + "password" + ] + }, + "aaaaa": { + "allOf": [ + { + "$ref": "#/components/schemas/Address" + }, + { + "$ref": "#/components/schemas/User" + } + ] + }, + "Tag": { + "type": [ + "object" + ], + "xml": { + "name": "tag" + }, + "properties": { + "id": { + "type": [ + "integer" + ], + "format": "int64" + }, + "name": { + "type": [ + "string" + ] + } + } + }, + "Pet": { + "type": [ + "object" + ], + "xml": { + "name": "pet" + }, + "properties": { + "id": { + "type": [ + "integer" + ], + "readOnly": true, + "examples": [ + 10, + 2, + 4 + ], + "format": "int64" + }, + "name": { + "type": [ + "string" + ], + "examples": [ + "doggie" + ] + }, + "category": { + "$ref": "#/components/schemas/Category" + }, + "petType": { + "type": [ + "string" + ], + "examples": [ + "dog" + ] + }, + "photoUrls": { + "type": "array", + "items": { + "type": [ + "string" + ] + } + }, + "tags": { + "$ref": "#/components/schemas/Tag" + }, + "status": { + "type": [ + "string" + ], + "description": "pet status in the store", + "enum": [ + "available", + "pending", + "sold" + ] + } + }, + "required": [ + "name", + "petType" + ] + }, + "NewCat": { + "allOf": [ + { + "$ref": "#/components/schemas/Pet" + }, + { + "type": [ + "object" + ], + "properties": { + "huntingSkill": { + "type": [ + "string" + ], + "description": "The measured skill for hunting", + "enum": [ + "clueless", + "lazy", + "adventurous", + "aggressive" + ] + } + } + } + ] + }, + "XmlPrefixAndNamespace": { + "type": [ + "object" + ], + "properties": { + "id": { + "type": [ + "integer" + ], + "xml": { + "attribute": true + }, + "format": "int32" + }, + "name": { + "type": [ + "string" + ], + "xml": { + "namespace": "http://example.com/schema/sample", + "prefix": "sample" + } + } + } + }, + "animals": { + "type": "array", + "items": { + "type": [ + "string" + ], + "xml": { + "name": "animal" + } + } + }, + "AnimalsNoAliens": { + "type": "array", + "xml": { + "name": "aliens" + }, + "items": { + "type": [ + "string" + ], + "xml": { + "name": "animal" + } + } + }, + "WrappedAnimals": { + "type": "array", + "xml": { + "wrapped": true + }, + "items": { + "type": [ + "string" + ] + } + }, + "WrappedAnimal": { + "type": "array", + "xml": { + "wrapped": true + }, + "items": { + "type": [ + "string" + ], + "xml": { + "name": "animal" + } + } + }, + "WrappedAliens": { + "type": "array", + "xml": { + "name": "aliens", + "wrapped": true + }, + "items": { + "type": [ + "string" + ], + "xml": { + "name": "animal" + } + } + }, + "WrappedAliensWithItems": { + "type": "array", + "xml": { + "name": "aliens", + "wrapped": true + }, + "items": { + "type": [ + "string" + ] + } + }, + "StructPart": { + "type": [ + "object" + ], + "properties": { + "name": { + "type": [ + "string" + ] + }, + "type": { + "type": [ + "string" + ] + }, + "children": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StructPart" + } + } + } + }, + "Pet2": { + "type": [ + "object" + ], + "properties": { + "name": { + "type": [ + "string" + ] + }, + "petType": { + "type": [ + "string" + ] + } + }, + "discriminator": { + "propertyName": "petType" + } + }, + "Cat2": { + "allOf": [ + { + "$ref": "#/components/schemas/Pet2" + }, + { + "properties": { + "huntingSkill": { + "type": [ + "string" + ], + "description": "The measured skill for hunting", + "default": "lazy", + "enum": [ + "clueless", + "lazy", + "adventurous", + "aggressive" + ] + } + }, + "type": "object", + "required": [ + "huntingSkill" + ] + } + ], + "description": "A representation of a cat. Note that Cat will be used as the discriminator value." + }, + "Dog2": { + "allOf": [ + { + "$ref": "#/components/schemas/Pet2" + }, + { + "properties": { + "packSize": { + "type": [ + "integer" + ], + "description": "the size of the pack the dog is from", + "minimum": 0, + "format": "int32" + } + }, + "type": "object", + "required": [ + "packSize" + ] + } + ], + "description": "A representation of a dog. Note that Dog will be used as the discriminator value." + }, + "ExtendedErrorModel": { + "allOf": [ + { + "$ref": "#/components/schemas/Pet" + }, + { + "properties": { + "rootCause": { + "type": [ + "string" + ] + } + }, + "type": "object", + "required": [ + "rootCause" + ] + } + ] + }, + "Cat": { + "type": [ + "object" + ], + "description": "Type of cat", + "properties": { + "breed": { + "type": [ + "string" + ], + "description": "Type of Breed", + "enum": [ + "Abyssinian", + "Balinese-Javanese", + "Burmese", + "British Shorthair" + ] + } + }, + "allOf": [ + { + "$ref": "#/components/schemas/Pet" + }, + { + "properties": { + "huntingSkill": { + "type": [ + "string" + ], + "description": "The measured skill for hunting", + "enum": [ + "clueless", + "lazy", + "adventurous", + "aggressive" + ] + } + }, + "type": "object" + } + ] + }, + "Dog": { + "allOf": [ + { + "$ref": "#/components/schemas/Pet" + }, + { + "type": [ + "object" + ], + "properties": { + "breed": { + "type": [ + "string" + ], + "description": "Type of Breed", + "enum": [ + "Dingo", + "Husky", + "Retriever", + "Shepherd" + ] + }, + "bark": { + "type": [ + "boolean" + ] + } + } + } + ] + }, + "Pets": { + "oneOf": [ + { + "$ref": "#/components/schemas/Cat" + }, + { + "$ref": "#/components/schemas/Dog" + } + ], + "discriminator": { + "propertyName": "petType" + } + }, + "ApiResponse": { + "type": [ + "object" + ], + "xml": { + "name": "##default" + }, + "properties": { + "code": { + "type": [ + "integer" + ], + "format": "int32" + }, + "type": { + "type": [ + "string" + ], + "examples": [ + "doggie" + ] + }, + "message": { + "type": [ + "string" + ] + } + } + }, + "ErrorModel": { + "type": [ + "object" + ], + "properties": { + "message": { + "type": [ + "string" + ] + }, + "code": { + "type": [ + "integer" + ], + "format": "int32" + } + } + } + }, + "responses": { + "UserOpSuccess": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + } + } + }, + "parameters": { + "PetIdParam": { + "description": "ID of the pet", + "name": "petId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + } + }, + "requestBodies": { + "PetBodySchema": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pets" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Pets" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pets" + } + } + }, + "required": true, + "description": "Pet in the store" + } + }, + "headers": { + "X-Rate-Limit": { + "schema": { + "type": [ + "integer" + ], + "format": "int32" + } + }, + "X-Expires-After": { + "schema": { + "type": [ + "string" + ], + "format": "date-time" + } + } + }, + "links": { + "address": { + "operationId": "getUserByName", + "parameters": { + "username": "$request.path.username" + } + } + }, + "callbacks": { + "test": { + "'{$request.body#/id}'": { + "post": { + "requestBody": { + "content": { + "\"*/*\"": { + "schema": { + "type": [ + "string" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + }, + "default": { + "description": "Something is wrong" + } + } + } + } + } + }, + "pathItems": { + "GetPetByIdWithRef": { + "get": { + "tags": [ + "pet" + ], + "summary": "Find pet by ID", + "description": "Returns a single pet.", + "operationId": "getPetByIdWithRef", + "parameters": [ + { + "description": "ID of pet to return", + "name": "petId", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + }, + "in": "path" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + }, + "415": { + "description": "Unsupported Media Type" + } + } + } + } + }, + "securitySchemes": { + "Login": { + "scheme": "basic", + "type": "http" + }, + "LoginApiKey": { + "type": "apiKey", + "in": "header", + "name": "X-API-KEY" + }, + "api_key": { + "type": "apiKey", + "in": "header", + "name": "api_key" + }, + "Jwt": { + "scheme": "bearer", + "type": "http" + }, + "Login-OAuth2": { + "type": "oauth2", + "flows": { + "authorizationCode": { + "tokenUrl": "http://example.org/api/oauth/token", + "authorizationUrl": "http://example.org/api/oauth/dialog", + "scopes": { + "read": "Grant read-only access to all your data except for the account and user info", + "write": "Grant write-only access to all your data except for the account and user info" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/unit/OpenApi.Tests.ps1 b/tests/unit/OpenApi.Tests.ps1 index 1698312f7..448be69c8 100644 --- a/tests/unit/OpenApi.Tests.ps1 +++ b/tests/unit/OpenApi.Tests.ps1 @@ -1680,10 +1680,10 @@ Describe 'OpenApi' { $result.Count | Should -Be 3 $result.type | Should -Be 'object' $result.xml | Should -Not -BeNullOrEmpty - $result.xml | Should -BeOfType [hashtable] + $result.xml | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.xml.Count | Should -Be 1 $result.properties | Should -Not -BeNullOrEmpty - $result.properties | Should -BeOfType [hashtable] + $result.properties | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.properties.Count | Should -Be 2 $result.properties.name | Should -Not -BeNullOrEmpty $result.properties.name | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] @@ -1709,10 +1709,10 @@ Describe 'OpenApi' { $result.Count | Should -Be 3 $result.type | Should -Be 'object' $result.xml | Should -Not -BeNullOrEmpty - $result.xml | Should -BeOfType [hashtable] + $result.xml | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.xml.Count | Should -Be 1 $result.properties | Should -Not -BeNullOrEmpty - $result.properties | Should -BeOfType [hashtable] + $result.properties | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.properties.Count | Should -Be 2 $result.properties.name | Should -Not -BeNullOrEmpty $result.properties.name | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] @@ -1745,10 +1745,10 @@ Describe 'OpenApi' { $result.Count | Should -Be 3 $result.type | Should -Be 'object' $result.xml | Should -Not -BeNullOrEmpty - $result.xml | Should -BeOfType [hashtable] + $result.xml | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.xml.Count | Should -Be 1 $result.properties | Should -Not -BeNullOrEmpty - $result.properties | Should -BeOfType [hashtable] + $result.properties | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.properties.Count | Should -Be 2 $result.properties.name | Should -Not -BeNullOrEmpty $result.properties.name | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] @@ -1775,10 +1775,10 @@ Describe 'OpenApi' { $result.Count | Should -Be 3 $result.type | Should -Be 'object' $result.xml | Should -Not -BeNullOrEmpty - $result.xml | Should -BeOfType [hashtable] + $result.xml | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.xml.Count | Should -Be 1 $result.properties | Should -Not -BeNullOrEmpty - $result.properties | Should -BeOfType [hashtable] + $result.properties | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.properties.Count | Should -Be 2 $result.properties.name | Should -Not -BeNullOrEmpty $result.properties.name | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] @@ -2875,7 +2875,7 @@ Describe 'OpenApi' { $result | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.Count | Should -Be 3 $result.description | Should -Be 'Pet in the store' - $result.content | Should -BeOfType [hashtable] + $result.content | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.Count | Should -Be 3 $result.content.'application/json' | Should -BeOfType [hashtable] $result.content.'application/json'.Count | Should -Be 1 @@ -2902,7 +2902,7 @@ Describe 'OpenApi' { $result | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.Count | Should -Be 3 $result.description | Should -Be 'Pet in the store' - $result.content | Should -BeOfType [hashtable] + $result.content | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.Count | Should -Be 3 $result.content.'application/json' | Should -BeOfType [hashtable] $result.content.'application/json'.Count | Should -Be 1 @@ -3198,7 +3198,7 @@ Describe 'OpenApi' { (New-PodeOAStringProperty -Name 'status' -Description 'pet status in the store' -Enum @('available', 'pending', 'sold')) ) $Pet.type | Should -be 'object' - $Pet.xml | Should -BeOfType [hashtable] + $Pet.xml | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $Pet.xml.Count | Should -Be 1 $Pet.xml.name | Should -Be 'pet' $Pet.name | Should -Be 'Pet' @@ -3253,7 +3253,7 @@ Describe 'OpenApi' { New-PodeOAStringProperty -Name 'status' -Description 'pet status in the store' -Enum @('available', 'pending', 'sold') | New-PodeOAObjectProperty -Name 'Pet' -XmlName 'pet' $Pet.type | Should -be 'object' - $Pet.xml | Should -BeOfType [hashtable] + $Pet.xml | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $Pet.xml.Count | Should -Be 1 $Pet.xml.name | Should -Be 'pet' $Pet.name | Should -Be 'Pet' diff --git a/tests/unit/PrivateOpenApi.Tests.ps1 b/tests/unit/PrivateOpenApi.Tests.ps1 index ff07225a1..4a6b807fe 100644 --- a/tests/unit/PrivateOpenApi.Tests.ps1 +++ b/tests/unit/PrivateOpenApi.Tests.ps1 @@ -373,7 +373,7 @@ Describe 'PrivateOpenApi' { $result.Count | Should -Be 2 $result['prop1'].processed | Should -Be $true $result['prop2'].processed | Should -Be $true - $result.ContainsKey('prop3') | Should -Be $false + $result.keys -contains 'prop3' | Should -Be $false } It 'Forms valid schema object for non-excluded properties' { @@ -400,7 +400,7 @@ Describe 'PrivateOpenApi' { } $result = ConvertTo-PodeOAObjectSchema -Content $content -DefinitionTag 'myTag' - $result.ContainsKey('application/json') | Should -Be $true + $result.Keys -contains 'application/json' | Should -Be $true $result['application/json'].schema.type | Should -Be 'string' } From a316b88b8b4d60f279e7be6d8a2264c489c74eff Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 13 Sep 2024 12:24:45 -0700 Subject: [PATCH 148/177] fix linux test --- tests/integration/OpenApi.Tests.ps1 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/integration/OpenApi.Tests.ps1 b/tests/integration/OpenApi.Tests.ps1 index bdf2c8053..c37b12ad3 100644 --- a/tests/integration/OpenApi.Tests.ps1 +++ b/tests/integration/OpenApi.Tests.ps1 @@ -27,6 +27,14 @@ Describe 'OpenAPI integration tests' { Start-Process 'powershell' -ArgumentList "-NoProfile -File `"$scriptPath`" -Quiet -PortV3 $PortV3 -PortV3_1 $PortV3_1 -DisableTermination" -NoNewWindow } + function Compare-StringRnLn { + param ( + [string]$InputString1, + [string]$InputString2 + ) + return ($InputString1.Trim() -replace "`r`n|`n|`r", "`n") -eq ($InputString2.Trim() -replace "`r`n|`n|`r", "`n") + } + function Convert-PsCustomObjectToOrderedHashtable { [CmdletBinding()] param ( @@ -113,6 +121,9 @@ Describe 'OpenAPI integration tests' { return $true } else { + if($value1 -is [string] -and $value2 -is [string]){ + return Compare-StringRnLn $value1 $value2 + } # Check if the values are equal return $value1 -eq $value2 } From e7beffe57f7836815e8e7b7d975637815ea877dc Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 13 Sep 2024 13:04:39 -0700 Subject: [PATCH 149/177] Update OpenApi.Tests.ps1 --- tests/integration/OpenApi.Tests.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/integration/OpenApi.Tests.ps1 b/tests/integration/OpenApi.Tests.ps1 index c37b12ad3..62cf921ad 100644 --- a/tests/integration/OpenApi.Tests.ps1 +++ b/tests/integration/OpenApi.Tests.ps1 @@ -18,7 +18,6 @@ Describe 'OpenAPI integration tests' { } $PortV3 = 8080 $PortV3_1 = 8081 - $Endpoint = "http://127.0.0.1:$($PortV3)" $scriptPath = "$($PSScriptRoot)\..\..\examples\OpenApi-TuttiFrutti.ps1" if ($PSVersionTable.PsVersion -gt [version]'6.0') { Start-Process 'pwsh' -ArgumentList "-NoProfile -File `"$scriptPath`" -Quiet -PortV3 $PortV3 -PortV3_1 $PortV3_1 -DisableTermination" -NoNewWindow @@ -160,7 +159,7 @@ Describe 'OpenAPI integration tests' { AfterAll { Start-Sleep -Seconds 5 - Invoke-RestMethod -Uri "$($Endpoint)/close" -Method Post | Out-Null + Invoke-RestMethod -Uri "http://localhost:$($PortV3)/close" -Method Post | Out-Null } From def1f1daf0282b5786bf7a7d9cfdc6a55f822d46 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 13 Sep 2024 13:47:08 -0700 Subject: [PATCH 150/177] migration to [ordered] hashtable --- src/Private/OpenApi.ps1 | 78 ++++++++++++++++++------------------ src/Public/OAComponents.ps1 | 2 +- src/Public/OAProperties.ps1 | 10 ++--- src/Public/OpenApi.ps1 | 18 ++++----- tests/unit/OpenApi.Tests.ps1 | 24 +++++------ 5 files changed, 66 insertions(+), 66 deletions(-) diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index d2ccc13c6..915cdfed1 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -59,7 +59,7 @@ function ConvertTo-PodeOAObjectSchema { $types = [string[]]$Content.Keys foreach ($type in $types) { # Initialize schema structure for the type - $obj[$type] = @{ } + $obj[$type] = [ordered]@{ } # Handle upload content, array structures, and shared component schema references if ($Content[$type].__upload) { @@ -136,12 +136,12 @@ function ConvertTo-PodeOAObjectSchema { #Check for empty reference if (@('string', 'integer' , 'number', 'boolean' ) -icontains $item) { if ($isArray) { - $obj[$type].schema.items = @{ + $obj[$type].schema.items = [ordered]@{ 'type' = $item.ToLower() } } else { - $obj[$type].schema = @{ + $obj[$type].schema = [ordered]@{ 'type' = $item.ToLower() } } @@ -149,12 +149,12 @@ function ConvertTo-PodeOAObjectSchema { else { Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $item -PostValidation if ($isArray) { - $obj[$type].schema.items = @{ + $obj[$type].schema.items = [ordered]@{ '$ref' = "#/components/schemas/$($item)" } } else { - $obj[$type].schema = @{ + $obj[$type].schema = [ordered]@{ '$ref' = "#/components/schemas/$($item)" } } @@ -174,8 +174,8 @@ function ConvertTo-PodeOAObjectSchema { } if ($Properties) { if ($item.Name) { - $obj[$type].schema = @{ - 'properties' = @{ + $obj[$type].schema = [ordered]@{ + 'properties' = [ordered]@{ $item.Name = $result } } @@ -324,7 +324,7 @@ function ConvertTo-PodeOAOfProperty { # Initialize the schema with the 'Of' type if ($Property.name) { $schema = [ordered]@{ - $Property.name = @{ + $Property.name = [ordered]@{ $Property.type = @() } } @@ -345,10 +345,10 @@ function ConvertTo-PodeOAOfProperty { # Validate the schema component and add a reference to it Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $prop -PostValidation if ($Property.name) { - $schema[$Property.name][$Property.type] += @{ '$ref' = "#/components/schemas/$prop" } + $schema[$Property.name][$Property.type] += [ordered]@{ '$ref' = "#/components/schemas/$prop" } } else { - $schema[$Property.type] += @{ '$ref' = "#/components/schemas/$prop" } + $schema[$Property.type] += [ordered]@{ '$ref' = "#/components/schemas/$prop" } } } else { @@ -390,7 +390,7 @@ function ConvertTo-PodeOAOfProperty { A mandatory string parameter specifying the definition context used for schema validation and compatibility checks with OpenAPI versions. .EXAMPLE - $propertyDetails = @{ + $propertyDetails = [ordered]@{ type = 'string'; description = 'A sample property'; } @@ -554,7 +554,7 @@ function ConvertTo-PodeOASchemaProperty { $schema['type'] = 'array' if ($Property.type -ieq 'schema') { Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $Property['schema'] -PostValidation - $schema['items'] = @{ '$ref' = "#/components/schemas/$($Property['schema'])" } + $schema['items'] = [ordered]@{ '$ref' = "#/components/schemas/$($Property['schema'])" } } else { $Property.array = $false @@ -569,7 +569,7 @@ function ConvertTo-PodeOASchemaProperty { } if ($Property.xmlItemName) { - $schema.items.xml = @{'name' = $Property.xmlItemName } + $schema.items.xml = [ordered]@{'name' = $Property.xmlItemName } } } return $schema @@ -583,7 +583,7 @@ function ConvertTo-PodeOASchemaProperty { # schema refs if ($Property.type -ieq 'schema') { Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $Property['schema'] -PostValidation - $schema = @{ + $schema = [ordered]@{ '$ref' = "#/components/schemas/$($Property['schema'])" } } @@ -597,7 +597,7 @@ function ConvertTo-PodeOASchemaProperty { # are we using an object? $Property.object = $false - $schema = @{ + $schema = [ordered]@{ type = 'object' properties = (ConvertTo-PodeOASchemaObjectProperty -DefinitionTag $DefinitionTag -Properties $Property) } @@ -786,14 +786,14 @@ function Set-PodeOpenApiRouteValue { #if scope is empty means 'any role' => assign an empty array $sctValue = @() } - $pm.security += @{ $sct = $sctValue } + $pm.security += [ordered]@{ $sct = $sctValue } } elseif ($sct -eq '%_allowanon_%') { #allow anonymous access $pm.security += [ordered]@{} } else { - $pm.security += @{$sct = @() } + $pm.security += [ordered]@{$sct = @() } } } } @@ -802,7 +802,7 @@ function Set-PodeOpenApiRouteValue { } else { # Set responses or default to '204 No Content' if not specified - $pm.responses = @{'204' = @{'description' = (Get-PodeStatusDescription -StatusCode 204) } } + $pm.responses = [ordered]@{'204' = [ordered]@{'description' = (Get-PodeStatusDescription -StatusCode 204) } } } # Return the processed route properties return $pm @@ -830,7 +830,7 @@ Mandatory. A tag that identifies the specific OpenAPI definition to be generated Ordered dictionary representing the OpenAPI definition, which can be further processed into JSON or YAML format. .EXAMPLE -$metaInfo = @{ +$metaInfo = [ordered]@{ Title = "My API"; Version = "v1"; Description = "This is my API description." @@ -923,7 +923,7 @@ function Get-PodeOpenApiDefinitionInternal { $keys = [string[]]$Definition.webhooks.Keys foreach ($key in $keys) { if ($Definition.webhooks[$key].NotPrepared) { - $Definition.webhooks[$key] = @{ + $Definition.webhooks[$key] = [ordered]@{ $Definition.webhooks[$key].Method = Set-PodeOpenApiRouteValue -Route $Definition.webhooks[$key] -DefinitionTag $DefinitionTag } } @@ -971,7 +971,7 @@ function Get-PodeOpenApiDefinitionInternal { $keys = [string[]]$components.pathItems.Keys foreach ($key in $keys) { if ($components.pathItems[$key].NotPrepared) { - $components.pathItems[$key] = @{ + $components.pathItems[$key] = [ordered]@{ $components.pathItems[$key].Method = Set-PodeOpenApiRouteValue -Route $components.pathItems[$key] -DefinitionTag $DefinitionTag } } @@ -1020,7 +1020,7 @@ function Get-PodeOpenApiDefinitionInternal { if ($authType.Arguments.Description) { $_authObj.description = $authType.Arguments.Description } - $_authObj.flows = @{ + $_authObj.flows = [ordered]@{ $oAuthFlow = [ordered]@{ } } @@ -1048,7 +1048,7 @@ function Get-PodeOpenApiDefinitionInternal { } } else { - $_authObj = @{ + $_authObj = [ordered]@{ type = $authType.Scheme.ToLowerInvariant() scheme = $authType.Name.ToLowerInvariant() } @@ -1113,8 +1113,8 @@ function Get-PodeOpenApiDefinitionInternal { $pm = Set-PodeOpenApiRouteValue -Route $_route -DefinitionTag $DefinitionTag if ($pm.responses.Count -eq 0) { - $pm.responses += @{ - 'default' = @{'description' = 'No description' } + $pm.responses += [ordered]@{ + 'default' = [ordered]@{'description' = 'No description' } } } $def.paths[$_route.OpenApi.Path][$method] = $pm @@ -1138,12 +1138,12 @@ function Get-PodeOpenApiDefinitionInternal { $serverDef = $null if (![string]::IsNullOrWhiteSpace($_route.Endpoint.Name)) { - $serverDef = @{ + $serverDef = [ordered]@{ url = (Get-PodeEndpointByName -Name $_route.Endpoint.Name).Url } } else { - $serverDef = @{ + $serverDef = [ordered]@{ url = "$($_route.Endpoint.Protocol)://$($_route.Endpoint.Address)" } } @@ -1280,8 +1280,8 @@ function Get-PodeOABaseObject { } externalPath = [ordered]@{} defaultResponses = [ordered]@{ - '200' = @{ description = 'OK' } - 'default' = @{ description = 'Internal server error' } + '200' = [ordered]@{ description = 'OK' } + 'default' = [ordered]@{ description = 'Internal server error' } } operationId = @() } @@ -1400,7 +1400,7 @@ function Set-PodeOAAuth { }) # Add anonymous access if allowed if ($AllowAnon) { - $r.OpenApi.Authentication += @{'%_allowanon_%' = '' } + $r.OpenApi.Authentication += [ordered]@{'%_allowanon_%' = '' } } } } @@ -1472,8 +1472,8 @@ function Set-PodeOAGlobalAuth { } # Update the OpenAPI definition with the authentication information - $PodeContext.Server.OpenAPI.Definitions[$tag].Security += @{ - Definition = @{ "$($authName -replace '\s+', '')" = $Scopes } + $PodeContext.Server.OpenAPI.Definitions[$tag].Security += [ordered]@{ + Definition = [ordered]@{ "$($authName -replace '\s+', '')" = $Scopes } Route = (ConvertTo-PodeRouteRegex -Path $Route) } } @@ -1495,13 +1495,13 @@ function Set-PodeOAGlobalAuth { A string identifier for the specific set of schema definitions under which references should be resolved. .EXAMPLE - $schema = @{ + $schema = [ordered]@{ type = 'object'; - properties = @{ - name = @{ + properties = [ordered]@{ + name = [ordered]@{ type = 'string' }; - details = @{ + details = [ordered]@{ '$ref' = '#/components/schemas/UserDetails' } }; @@ -1805,7 +1805,7 @@ function ConvertTo-PodeOAHeaderProperty { $elems.$($e.name).description = $e.description } # Define the schema, including the type and any additional properties - $elems.$($e.name).schema = @{ + $elems.$($e.name).schema = [ordered]@{ type = $($e.type) } foreach ($k in $e.keys) { @@ -1942,7 +1942,7 @@ function New-PodeOResponseInternal { # Handle response referencing an existing component if ($Params.Reference) { Test-PodeOAComponentInternal -Field responses -DefinitionTag $DefinitionTag -Name $Params.Reference -PostValidation - $response = @{ + $response = [ordered]@{ '$ref' = "#/components/responses/$($Params.Reference)" } } @@ -1964,7 +1964,7 @@ function New-PodeOResponseInternal { $_headers = [ordered]@{} foreach ($h in $Params.Headers) { Test-PodeOAComponentInternal -Field headers -DefinitionTag $DefinitionTag -Name $h -PostValidation - $_headers[$h] = @{ + $_headers[$h] = [ordered]@{ '$ref' = "#/components/headers/$h" } } diff --git a/src/Public/OAComponents.ps1 b/src/Public/OAComponents.ps1 index 136650fde..6602156cd 100644 --- a/src/Public/OAComponents.ps1 +++ b/src/Public/OAComponents.ps1 @@ -737,7 +737,7 @@ function Add-PodeOAComponentPathItem { Responses = $null Parameters = $null RequestBody = $null - callbacks = @{} + callbacks = [ordered]@{} Authentication = @() Servers = @() DefinitionTag = $_definitionTag diff --git a/src/Public/OAProperties.ps1 b/src/Public/OAProperties.ps1 index 778d35139..170ddcbdf 100644 --- a/src/Public/OAProperties.ps1 +++ b/src/Public/OAProperties.ps1 @@ -361,7 +361,7 @@ function New-PodeOAMultiTypeProperty { $param.properties = @() } if ($DiscriminatorProperty) { - $param.discriminator = @{ + $param.discriminator = [ordered]@{ 'propertyName' = $DiscriminatorProperty } if ($DiscriminatorMapping) { @@ -1539,8 +1539,8 @@ New-PodeOAObjectProperty -Name 'user' -Properties @('') .EXAMPLE New-PodeOABoolProperty -Name 'enabled' -Required| New-PodeOAObjectProperty -Name 'extraProperties' -AdditionalProperties [ordered]@{ - "property1" = @{ "type" = "string"; "description" = "Description for property1" }; - "property2" = @{ "type" = "integer"; "format" = "int32" } + "property1" = [ordered]@{ "type" = "string"; "description" = "Description for property1" }; + "property2" = [ordered]@{ "type" = "integer"; "format" = "int32" } } #> function New-PodeOAObjectProperty { @@ -1663,7 +1663,7 @@ function New-PodeOAObjectProperty { $PropertiesFromPipeline = $true } if ($DiscriminatorProperty) { - $param.discriminator = @{ + $param.discriminator = [ordered]@{ 'propertyName' = $DiscriminatorProperty } if ($DiscriminatorMapping) { @@ -1854,7 +1854,7 @@ function Merge-PodeOAProperty { # The parameter 'Discriminator' is incompatible with `allOf` throw ($PodeLocale.discriminatorIncompatibleWithAllOfExceptionMessage) } - $param.discriminator = @{ + $param.discriminator = [ordered]@{ 'propertyName' = $DiscriminatorProperty } if ($DiscriminatorMapping) { diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index b8bdd8efe..26beb45b8 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -899,7 +899,7 @@ function New-PodeOARequestBody { foreach ($tag in $DefinitionTag) { switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { 'builtin' { - $param = @{content = ConvertTo-PodeOAObjectSchema -DefinitionTag $tag -Content $Content -Properties:$Properties } + $param = [ordered]@{content = ConvertTo-PodeOAObjectSchema -DefinitionTag $tag -Content $Content -Properties:$Properties } if ($Required.IsPresent) { $param['required'] = $Required.IsPresent @@ -924,7 +924,7 @@ function New-PodeOARequestBody { 'reference' { Test-PodeOAComponentInternal -Field requestBodies -DefinitionTag $tag -Name $Reference -PostValidation - $param = @{ + $param = [ordered]@{ '$ref' = "#/components/requestBodies/$Reference" } } @@ -1809,7 +1809,7 @@ function Enable-PodeOAViewer { OpenApi = "$($OpenApiUrl)?format=yaml" DarkMode = $DarkMode DefinitionTag = $DefinitionTag - SwaggerEditorDist = 'https://unpkg.com/swagger-editor-dist@4' + SwaggerEditorDist = 'https://unpkg.com/swagger-editor-dist@5' } Add-PodeRoute -Method Get -Path $Path ` -Middleware $Middleware -ArgumentList $meta ` @@ -2641,7 +2641,7 @@ function Add-PodeOACallBack { if (! $r.OpenApi.CallBacks.ContainsKey($tag)) { $r.OpenApi.CallBacks[$tag] = [ordered]@{} } - $r.OpenApi.CallBacks[$tag].$Name = @{ + $r.OpenApi.CallBacks[$tag].$Name = [ordered]@{ '$ref' = "#/components/callbacks/$Reference" } } @@ -2859,13 +2859,13 @@ function New-PodeOAResponse { This example demonstrates the use of New-PodeOAContentMediaType in defining a GET route '/pet/findByStatus' in an OpenAPI specification. The route includes request parameters and responses with media content types for 'application/json' and 'application/xml'. .EXAMPLE - $content = @{ type = 'string' } + $content = [ordered]@{ type = 'string' } $mediaType = 'application/json' New-PodeOAContentMediaType -ContentType $mediaType -Content $content This example creates a media content type definition for 'application/json' with a simple string content type. .EXAMPLE - $content = @{ type = 'object'; properties = @{ name = @{ type = 'string' } } } + $content = [ordered]@{ type = 'object'; properties = [ordered]@{ name = @{ type = 'string' } } } $mediaTypes = 'application/json', 'application/xml' New-PodeOAContentMediaType -ContentType $mediaTypes -Content $content -Array -MinItems 1 -MaxItems 5 -Title 'UserList' This example demonstrates defining an array of objects for both 'application/json' and 'application/xml' media types, with a specified range for the number of items and a title. @@ -2941,14 +2941,14 @@ function New-PodeOAContentMediaType { } if ($Upload.IsPresent) { if ( $media -ieq 'multipart/form-data' -and $Content) { - $Content = @{'__upload' = @{ + $Content = [ordered]@{'__upload' = [ordered]@{ 'content' = $Content 'partContentMediaType' = $PartContentMediaType } } } else { - $Content = @{'__upload' = @{ + $Content = [ordered]@{'__upload' = [ordered]@{ 'contentEncoding' = $ContentEncoding } } @@ -3100,7 +3100,7 @@ function New-PodeOAResponseLink { $Name = $Reference } $link = [ordered]@{ - $Name = @{ + $Name = [ordered]@{ '$ref' = "#/components/links/$Reference" } } diff --git a/tests/unit/OpenApi.Tests.ps1 b/tests/unit/OpenApi.Tests.ps1 index 448be69c8..cbcba6d4b 100644 --- a/tests/unit/OpenApi.Tests.ps1 +++ b/tests/unit/OpenApi.Tests.ps1 @@ -2877,19 +2877,19 @@ Describe 'OpenApi' { $result.description | Should -Be 'Pet in the store' $result.content | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.Count | Should -Be 3 - $result.content.'application/json' | Should -BeOfType [hashtable] + $result.content.'application/json' | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.'application/json'.Count | Should -Be 1 - $result.content.'application/json'.schema | Should -BeOfType [hashtable] + $result.content.'application/json'.schema | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.'application/json'.schema.Count | Should -Be 1 $result.content.'application/json'.schema['$ref'] | Should -Be '#/components/schemas/Cat' - $result.content.'application/xml' | Should -BeOfType [hashtable] + $result.content.'application/xml' | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.'application/xml'.Count | Should -Be 1 - $result.content.'application/xml'.schema | Should -BeOfType [hashtable] + $result.content.'application/xml'.schema | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.'application/xml'.schema.Count | Should -Be 1 $result.content.'application/xml'.schema['$ref'] | Should -Be '#/components/schemas/Cat' - $result.content.'application/x-www-form-urlencoded' | Should -BeOfType [hashtable] + $result.content.'application/x-www-form-urlencoded' | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.'application/x-www-form-urlencoded'.Count | Should -Be 1 - $result.content.'application/x-www-form-urlencoded'.schema | Should -BeOfType [hashtable] + $result.content.'application/x-www-form-urlencoded'.schema | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.'application/x-www-form-urlencoded'.schema.Count | Should -Be 1 $result.content.'application/x-www-form-urlencoded'.schema['$ref'] | Should -Be '#/components/schemas/Cat' $result.required | Should -BeTrue @@ -2904,19 +2904,19 @@ Describe 'OpenApi' { $result.description | Should -Be 'Pet in the store' $result.content | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.Count | Should -Be 3 - $result.content.'application/json' | Should -BeOfType [hashtable] + $result.content.'application/json' | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.'application/json'.Count | Should -Be 1 - $result.content.'application/json'.schema | Should -BeOfType [hashtable] + $result.content.'application/json'.schema | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.'application/json'.schema.Count | Should -Be 1 $result.content.'application/json'.schema['$ref'] | Should -Be '#/components/schemas/Cat' - $result.content.'application/xml' | Should -BeOfType [hashtable] + $result.content.'application/xml' | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.'application/xml'.Count | Should -Be 1 - $result.content.'application/xml'.schema | Should -BeOfType [hashtable] + $result.content.'application/xml'.schema | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.'application/xml'.schema.Count | Should -Be 1 $result.content.'application/xml'.schema['$ref'] | Should -Be '#/components/schemas/Cat' - $result.content.'application/x-www-form-urlencoded' | Should -BeOfType [hashtable] + $result.content.'application/x-www-form-urlencoded' | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.'application/x-www-form-urlencoded'.Count | Should -Be 1 - $result.content.'application/x-www-form-urlencoded'.schema | Should -BeOfType [hashtable] + $result.content.'application/x-www-form-urlencoded'.schema | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $result.content.'application/x-www-form-urlencoded'.schema.Count | Should -Be 1 $result.content.'application/x-www-form-urlencoded'.schema['$ref'] | Should -Be '#/components/schemas/Cat' $result.required | Should -BeTrue From 0cd23f5a5b12842ac07b629a24f549918fc43753 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 13 Sep 2024 14:02:25 -0700 Subject: [PATCH 151/177] revert to https://unpkg.com/swagger-editor-dist@4' --- src/Public/OpenApi.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index 26beb45b8..a128aa139 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -1809,7 +1809,7 @@ function Enable-PodeOAViewer { OpenApi = "$($OpenApiUrl)?format=yaml" DarkMode = $DarkMode DefinitionTag = $DefinitionTag - SwaggerEditorDist = 'https://unpkg.com/swagger-editor-dist@5' + SwaggerEditorDist = 'https://unpkg.com/swagger-editor-dist@4' } Add-PodeRoute -Method Get -Path $Path ` -Middleware $Middleware -ArgumentList $meta ` From 58b19ac647145b6b263942bc13e1bea96bf8e428 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Sat, 14 Sep 2024 16:24:43 +0100 Subject: [PATCH 152/177] Improves the error handling of schedules, tasks, and timers. Also adds support for garbage collection, standardises Task Results to Processes, adds Process get funcs for Schedules/Tasks. Also, removes global: on TimerEvent --- examples/timers.ps1 | 2 +- examples/web-pages.ps1 | 14 +-- src/Locales/ar/Pode.psd1 | 4 +- src/Locales/de/Pode.psd1 | 4 +- src/Locales/en-us/Pode.psd1 | 4 +- src/Locales/en/Pode.psd1 | 2 + src/Locales/es/Pode.psd1 | 4 +- src/Locales/fr/Pode.psd1 | 4 +- src/Locales/it/Pode.psd1 | 4 +- src/Locales/ja/Pode.psd1 | 4 +- src/Locales/ko/Pode.psd1 | 4 +- src/Locales/nl/Pode.psd1 | 2 + src/Locales/pl/Pode.psd1 | 4 +- src/Locales/pt/Pode.psd1 | 4 +- src/Locales/zh/Pode.psd1 | 4 +- src/Pode.psd1 | 3 + src/Private/Context.ps1 | 24 ++-- src/Private/Helpers.ps1 | 12 +- src/Private/Logging.ps1 | 124 ++++++++++-------- src/Private/Schedules.ps1 | 243 +++++++++++++++++++++++++----------- src/Private/Server.ps1 | 8 +- src/Private/Tasks.ps1 | 222 ++++++++++++++++++++++---------- src/Private/Timers.ps1 | 104 +++++++++------ src/Public/Schedules.ps1 | 107 ++++++++++++++++ src/Public/Tasks.ps1 | 142 +++++++++++++++++++-- src/Public/Timers.ps1 | 2 +- src/Public/Utilities.ps1 | 17 +++ tests/unit/Server.Tests.ps1 | 7 +- 28 files changed, 793 insertions(+), 286 deletions(-) diff --git a/examples/timers.ps1 b/examples/timers.ps1 index 257b7d851..def46b987 100644 --- a/examples/timers.ps1 +++ b/examples/timers.ps1 @@ -30,7 +30,7 @@ Start-PodeServer { # runs forever, but skips the first 3 "loops" - is paused for 15secs then loops every 5secs Add-PodeTimer -Name 'pause-first-3' -Interval 5 -ScriptBlock { 'Skip 3 then run' | Out-PodeHost - Write-PodeHost $TimerEvent -Explode -ShowType + Write-PodeHost $TimerEvent -Explode -ShowType } -Skip 3 # runs every 5secs, but only runs for 3 "loops" (ie, 15secs) diff --git a/examples/web-pages.ps1 b/examples/web-pages.ps1 index 2d1dcb53b..76d7bf98d 100644 --- a/examples/web-pages.ps1 +++ b/examples/web-pages.ps1 @@ -10,22 +10,22 @@ Import-Module "$($path)/src/Pode.psm1" -Force -ErrorAction Stop # Import-Module Pode # create a server, and start listening on port 8085 -Start-PodeServer -Threads 2 -Verbose { +Start-PodeServer -Threads 1 -Verbose { # listen on localhost:8085 Add-PodeEndpoint -Address * -Port 8090 -Protocol Http -Name '8090Address' Add-PodeEndpoint -Address * -Port $Port -Protocol Http -Name '8085Address' -RedirectTo '8090Address' # allow the local ip and some other ips - Add-PodeAccessRule -Access Allow -Type IP -Values @('127.0.0.1', '[::1]') - Add-PodeAccessRule -Access Allow -Type IP -Values @('192.169.0.1', '192.168.0.2') + # Add-PodeAccessRule -Access Allow -Type IP -Values @('127.0.0.1', '[::1]') + # Add-PodeAccessRule -Access Allow -Type IP -Values @('192.169.0.1', '192.168.0.2') # deny an ip - Add-PodeAccessRule -Access Deny -Type IP -Values 10.10.10.10 - Add-PodeAccessRule -Access Deny -Type IP -Values '10.10.0.0/24' - Add-PodeAccessRule -Access Deny -Type IP -Values all + # Add-PodeAccessRule -Access Deny -Type IP -Values 10.10.10.10 + # Add-PodeAccessRule -Access Deny -Type IP -Values '10.10.0.0/24' + # Add-PodeAccessRule -Access Deny -Type IP -Values all # limit - Add-PodeLimitRule -Type IP -Values all -Limit 100 -Seconds 5 + # Add-PodeLimitRule -Type IP -Values all -Limit 100 -Seconds 5 # log requests to the terminal New-PodeLoggingMethod -Terminal -Batch 10 -BatchTimeout 10 | Enable-PodeRequestLogging diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 82ec26841..f3c1772f9 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -284,6 +284,8 @@ requestLoggingAlreadyEnabledExceptionMessage = 'تم تمكين تسجيل الطلبات بالفعل.' invalidAccessControlMaxAgeDurationExceptionMessage = 'مدة Access-Control-Max-Age غير صالحة المقدمة: {0}. يجب أن تكون أكبر من 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'تعريف OpenAPI باسم {0} موجود بالفعل.' - renamePodeOADefinitionTagExceptionMessage = "لا يمكن استخدام Rename-PodeOADefinitionTag داخل Select-PodeOADefinition 'ScriptBlock'." + renamePodeOADefinitionTagExceptionMessage = "لا يمكن استخدام Rename-PodeOADefinitionTag داخل Select-PodeOADefinition 'ScriptBlock'." DefinitionTagChangeNotAllowedExceptionMessage = 'لا يمكن تغيير علامة التعريف لمسار.' + taskProcessDoesNotExistExceptionMessage = 'عملية المهمة غير موجودة: {0}' + scheduleProcessDoesNotExistExceptionMessage = 'عملية الجدول الزمني غير موجودة: {0}' } diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index b3c6fca93..786f89669 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -284,6 +284,8 @@ requestLoggingAlreadyEnabledExceptionMessage = 'Die Anforderungsprotokollierung wurde bereits aktiviert.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Ungültige Access-Control-Max-Age-Dauer angegeben: {0}. Sollte größer als 0 sein.' openApiDefinitionAlreadyExistsExceptionMessage = 'Die OpenAPI-Definition mit dem Namen {0} existiert bereits.' - renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag kann nicht innerhalb eines 'ScriptBlock' von Select-PodeOADefinition verwendet werden." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag kann nicht innerhalb eines 'ScriptBlock' von Select-PodeOADefinition verwendet werden." DefinitionTagChangeNotAllowedExceptionMessage = 'Definitionstag für eine Route kann nicht geändert werden.' + taskProcessDoesNotExistExceptionMessage = "Der Aufgabenprozess '{0}' existiert nicht." + scheduleProcessDoesNotExistExceptionMessage = "Der Aufgabenplanerprozess '{0}' existiert nicht." } \ No newline at end of file diff --git a/src/Locales/en-us/Pode.psd1 b/src/Locales/en-us/Pode.psd1 index 570919cb5..5f2274ad5 100644 --- a/src/Locales/en-us/Pode.psd1 +++ b/src/Locales/en-us/Pode.psd1 @@ -284,6 +284,8 @@ requestLoggingAlreadyEnabledExceptionMessage = 'Request Logging has already been enabled.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Invalid Access-Control-Max-Age duration supplied: {0}. Should be greater than 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'OpenAPI definition named {0} already exists.' - renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." DefinitionTagChangeNotAllowedExceptionMessage = 'Definition Tag for a Route cannot be changed.' + taskProcessDoesNotExistExceptionMessage = 'Task process does not exist: {0}' + scheduleProcessDoesNotExistExceptionMessage = 'Schedule process does not exist: {0}' } \ No newline at end of file diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 03d71e7cf..fee82133f 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -286,5 +286,7 @@ openApiDefinitionAlreadyExistsExceptionMessage = 'OpenAPI definition named {0} already exists.' renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." DefinitionTagChangeNotAllowedExceptionMessage = 'Definition Tag for a Route cannot be changed.' + taskProcessDoesNotExistExceptionMessage = 'Task process does not exist: {0}' + scheduleProcessDoesNotExistExceptionMessage = 'Schedule process does not exist: {0}' } diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 80555ccec..8410416ad 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -284,6 +284,8 @@ requestLoggingAlreadyEnabledExceptionMessage = 'El registro de solicitudes ya está habilitado.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Duración inválida para Access-Control-Max-Age proporcionada: {0}. Debe ser mayor que 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'La definición de OpenAPI con el nombre {0} ya existe.' - renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag no se puede usar dentro de un 'ScriptBlock' de Select-PodeOADefinition." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag no se puede usar dentro de un 'ScriptBlock' de Select-PodeOADefinition." DefinitionTagChangeNotAllowedExceptionMessage = 'La etiqueta de definición para una Route no se puede cambiar.' + taskProcessDoesNotExistExceptionMessage = "El proceso de la tarea '{0}' no existe." + scheduleProcessDoesNotExistExceptionMessage = "El proceso del programación '{0}' no existe." } \ No newline at end of file diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index 97a4f2adb..5dd68c962 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -284,7 +284,9 @@ requestLoggingAlreadyEnabledExceptionMessage = 'La journalisation des requêtes est déjà activée.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Durée Access-Control-Max-Age invalide fournie : {0}. Doit être supérieure à 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'La définition OpenAPI nommée {0} existe déjà.' - renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag ne peut pas être utilisé à l'intérieur d'un 'ScriptBlock' de Select-PodeOADefinition." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag ne peut pas être utilisé à l'intérieur d'un 'ScriptBlock' de Select-PodeOADefinition." DefinitionTagChangeNotAllowedExceptionMessage = 'Le tag de définition pour une Route ne peut pas être modifié.' + taskProcessDoesNotExistExceptionMessage = "Le processus de la tâche '{0}' n'existe pas." + scheduleProcessDoesNotExistExceptionMessage = "Le processus de l'horaire '{0}' n'existe pas." } diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index cc77425e3..7cc1a027e 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -284,6 +284,8 @@ requestLoggingAlreadyEnabledExceptionMessage = 'La registrazione delle richieste è già abilitata.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Durata non valida fornita per Access-Control-Max-Age: {0}. Deve essere maggiore di 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'La definizione OpenAPI denominata {0} esiste già.' - renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag non può essere utilizzato all'interno di un 'ScriptBlock' di Select-PodeOADefinition." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag non può essere utilizzato all'interno di un 'ScriptBlock' di Select-PodeOADefinition." DefinitionTagChangeNotAllowedExceptionMessage = 'Il tag di definizione per una Route non può essere cambiato.' + taskProcessDoesNotExistExceptionMessage = "Il processo dell'attività '{0}' non esiste." + scheduleProcessDoesNotExistExceptionMessage = "Il processo della programma '{0}' non esiste." } \ No newline at end of file diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index 788fdad1a..d03260776 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -284,7 +284,9 @@ requestLoggingAlreadyEnabledExceptionMessage = 'リクエストロギングは既に有効になっています。' invalidAccessControlMaxAgeDurationExceptionMessage = '無効な Access-Control-Max-Age 期間が提供されました:{0}。0 より大きくする必要があります。' openApiDefinitionAlreadyExistsExceptionMessage = '名前が {0} の OpenAPI 定義は既に存在します。' - renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag は Select-PodeOADefinition 'ScriptBlock' 内で使用できません。" + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag は Select-PodeOADefinition 'ScriptBlock' 内で使用できません。" DefinitionTagChangeNotAllowedExceptionMessage = 'Routeの定義タグは変更できません。' + taskProcessDoesNotExistExceptionMessage = 'タスクプロセスが存在しません: {0}' + scheduleProcessDoesNotExistExceptionMessage = 'スケジュールプロセスが存在しません: {0}' } diff --git a/src/Locales/ko/Pode.psd1 b/src/Locales/ko/Pode.psd1 index b3d1bd6e9..4c3925af2 100644 --- a/src/Locales/ko/Pode.psd1 +++ b/src/Locales/ko/Pode.psd1 @@ -284,6 +284,8 @@ requestLoggingAlreadyEnabledExceptionMessage = '요청 로깅이 이미 활성화되었습니다.' invalidAccessControlMaxAgeDurationExceptionMessage = '잘못된 Access-Control-Max-Age 기간이 제공되었습니다: {0}. 0보다 커야 합니다.' openApiDefinitionAlreadyExistsExceptionMessage = '이름이 {0}인 OpenAPI 정의가 이미 존재합니다.' - renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag은 Select-PodeOADefinition 'ScriptBlock' 내에서 사용할 수 없습니다." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag은 Select-PodeOADefinition 'ScriptBlock' 내에서 사용할 수 없습니다." DefinitionTagChangeNotAllowedExceptionMessage = 'Route에 대한 정의 태그는 변경할 수 없습니다.' + taskProcessDoesNotExistExceptionMessage = '작업 프로세스가 존재하지 않습니다: {0}' + scheduleProcessDoesNotExistExceptionMessage = '스케줄 프로세스가 존재하지 않습니다: {0}' } diff --git a/src/Locales/nl/Pode.psd1 b/src/Locales/nl/Pode.psd1 index 8ae79d12d..d690364f1 100644 --- a/src/Locales/nl/Pode.psd1 +++ b/src/Locales/nl/Pode.psd1 @@ -286,5 +286,7 @@ openApiDefinitionAlreadyExistsExceptionMessage = 'OpenAPI-definitie met de naam {0} bestaat al.' renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag kan niet worden gebruikt binnen een Select-PodeOADefinition 'ScriptBlock'." DefinitionTagChangeNotAllowedExceptionMessage = 'Definitietag voor een route kan niet worden gewijzigd.' + taskProcessDoesNotExistExceptionMessage = "Taakproces '{0}' bestaat niet." + scheduleProcessDoesNotExistExceptionMessage = "Schema-proces '{0}' bestaat niet." } diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index 474423c48..084ce8147 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -284,7 +284,9 @@ requestLoggingAlreadyEnabledExceptionMessage = 'Rejestrowanie żądań jest już włączone.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Podano nieprawidłowy czas trwania Access-Control-Max-Age: {0}. Powinien być większy niż 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'Definicja OpenAPI o nazwie {0} już istnieje.' - renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag nie może być używany wewnątrz 'ScriptBlock' Select-PodeOADefinition." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag nie może być używany wewnątrz 'ScriptBlock' Select-PodeOADefinition." DefinitionTagChangeNotAllowedExceptionMessage = 'Tag definicji dla Route nie może zostać zmieniony.' + taskProcessDoesNotExistExceptionMessage = "Proces zadania '{0}' nie istnieje." + scheduleProcessDoesNotExistExceptionMessage = "Proces harmonogramu '{0}' nie istnieje." } diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index cf66f4fd0..9021ff8de 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -284,6 +284,8 @@ requestLoggingAlreadyEnabledExceptionMessage = 'O registro de solicitações já está habilitado.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Duração inválida fornecida para Access-Control-Max-Age: {0}. Deve ser maior que 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'A definição OpenAPI com o nome {0} já existe.' - renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag não pode ser usado dentro de um 'ScriptBlock' Select-PodeOADefinition." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag não pode ser usado dentro de um 'ScriptBlock' Select-PodeOADefinition." DefinitionTagChangeNotAllowedExceptionMessage = 'A Tag de definição para uma Route não pode ser alterada.' + taskProcessDoesNotExistExceptionMessage = "O processo da tarefa '{0}' não existe." + scheduleProcessDoesNotExistExceptionMessage = "O processo do cronograma '{0}' não existe." } \ No newline at end of file diff --git a/src/Locales/zh/Pode.psd1 b/src/Locales/zh/Pode.psd1 index 44604e501..074a5e089 100644 --- a/src/Locales/zh/Pode.psd1 +++ b/src/Locales/zh/Pode.psd1 @@ -284,6 +284,8 @@ requestLoggingAlreadyEnabledExceptionMessage = '请求日志记录已启用。' invalidAccessControlMaxAgeDurationExceptionMessage = '提供的 Access-Control-Max-Age 时长无效:{0}。应大于 0。' openApiDefinitionAlreadyExistsExceptionMessage = '名为 {0} 的 OpenAPI 定义已存在。' - renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag 不能在 Select-PodeOADefinition 'ScriptBlock' 内使用。" + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag 不能在 Select-PodeOADefinition 'ScriptBlock' 内使用。" DefinitionTagChangeNotAllowedExceptionMessage = 'Route的定义标签无法更改。' + taskProcessDoesNotExistExceptionMessage = "任务进程 '{0}' 不存在。" + scheduleProcessDoesNotExistExceptionMessage = "计划进程 '{0}' 不存在。" } \ No newline at end of file diff --git a/src/Pode.psd1 b/src/Pode.psd1 index eae7d8c44..2a6d08293 100644 --- a/src/Pode.psd1 +++ b/src/Pode.psd1 @@ -141,6 +141,7 @@ 'ConvertFrom-PodeXml', 'Set-PodeDefaultFolder', 'Get-PodeDefaultFolder', + 'Invoke-PodeGC', # routes 'Add-PodeRoute', @@ -184,6 +185,7 @@ 'Use-PodeSchedules', 'Test-PodeSchedule', 'Clear-PodeSchedules', + 'Get-PodeScheduleProcess', # timers 'Add-PodeTimer', @@ -207,6 +209,7 @@ 'Close-PodeTask', 'Test-PodeTaskCompleted', 'Wait-PodeTask', + 'Get-PodeTaskProcess', # middleware 'Add-PodeMiddleware', diff --git a/src/Private/Context.ps1 b/src/Private/Context.ps1 index 3e3395551..7667d73c0 100644 --- a/src/Private/Context.ps1 +++ b/src/Private/Context.ps1 @@ -116,9 +116,9 @@ function New-PodeContext { } $ctx.Tasks = @{ - Enabled = ($EnablePool -icontains 'tasks') - Items = @{} - Results = @{} + Enabled = ($EnablePool -icontains 'tasks') + Items = @{} + Processes = @{} } $ctx.Fim = @{ @@ -142,6 +142,7 @@ function New-PodeContext { Files = 1 Tasks = 2 WebSockets = 2 + Timers = 1 } # set socket details for pode server @@ -432,6 +433,7 @@ function New-PodeContext { Gui = $null Tasks = $null Files = $null + Timers = $null } # threading locks, etc. @@ -524,15 +526,15 @@ function New-PodeRunspacePool { # setup main runspace pool $threadsCounts = @{ Default = 3 - Timer = 1 + # Timer = 1 Log = 1 Schedule = 1 Misc = 1 } - if (!(Test-PodeTimersExist)) { - $threadsCounts.Timer = 0 - } + # if (!(Test-PodeTimersExist)) { + # $threadsCounts.Timer = 0 + # } if (!(Test-PodeSchedulesExist)) { $threadsCounts.Schedule = 0 @@ -591,6 +593,14 @@ function New-PodeRunspacePool { New-PodeWebSocketReceiver } + # setup timer runspace pool -if we have any timers + if (Test-PodeTimersExist) { + $PodeContext.RunspacePools.Timers = @{ + Pool = [runspacefactory]::CreateRunspacePool(1, $PodeContext.Threads.Timers, $PodeContext.RunspaceState, $Host) + State = 'Waiting' + } + } + # setup schedule runspace pool -if we have any schedules if (Test-PodeSchedulesExist) { $PodeContext.RunspacePools.Schedules = @{ diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index d9d09ded0..92eaa286a 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -554,7 +554,7 @@ function Get-PodeSubnetRange { function Add-PodeRunspace { param( [Parameter(Mandatory = $true)] - [ValidateSet('Main', 'Signals', 'Schedules', 'Gui', 'Web', 'Smtp', 'Tcp', 'Tasks', 'WebSockets', 'Files')] + [ValidateSet('Main', 'Signals', 'Schedules', 'Gui', 'Web', 'Smtp', 'Tcp', 'Tasks', 'WebSockets', 'Files', 'Timers')] [string] $Type, @@ -747,9 +747,9 @@ function Close-PodeRunspace { } # dispose of task runspaces - if ($PodeContext.Tasks.Results.Count -gt 0) { - foreach ($key in $PodeContext.Tasks.Results.Keys.Clone()) { - Close-PodeTaskInternal -Result $PodeContext.Tasks.Results[$key] + if ($PodeContext.Tasks.Processes.Count -gt 0) { + foreach ($key in $PodeContext.Tasks.Processes.Keys.Clone()) { + Close-PodeTaskInternal -Process $PodeContext.Tasks.Processes[$key] } } @@ -774,7 +774,7 @@ function Close-PodeRunspace { } # garbage collect - [GC]::Collect() + Invoke-PodeGC } catch { $_ | Write-PodeErrorLog @@ -1689,7 +1689,7 @@ function ConvertTo-PodeResponseContent { } } - { $_ -match '^(.*\/)?(.*\+)?yaml$' } { + { $_ -match '^(.*\/)?(.*\+)?yaml$' } { if ($InputObject -isnot [string]) { if ($Depth -le 0) { return (ConvertTo-PodeYamlInternal -InputObject $InputObject ) diff --git a/src/Private/Logging.ps1 b/src/Private/Logging.ps1 index 21ad5b56c..f82904db9 100644 --- a/src/Private/Logging.ps1 +++ b/src/Private/Logging.ps1 @@ -375,66 +375,80 @@ function Start-PodeLoggingRunspace { } $script = { - while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { - # if there are no logs to process, just sleep for a few seconds - but after checking the batch - if ($PodeContext.LogsToProcess.Count -eq 0) { - Test-PodeLoggerBatch - Start-Sleep -Seconds 5 - continue - } + try { + while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + try { + # if there are no logs to process, just sleep for a few seconds - but after checking the batch + if ($PodeContext.LogsToProcess.Count -eq 0) { + Test-PodeLoggerBatch + Start-Sleep -Seconds 5 + continue + } - # safely pop off the first log from the array - $log = (Lock-PodeObject -Return -Object $PodeContext.LogsToProcess -ScriptBlock { - $log = $PodeContext.LogsToProcess[0] - $null = $PodeContext.LogsToProcess.RemoveAt(0) - return $log - }) - - # run the log item through the appropriate method - $logger = Get-PodeLogger -Name $log.Name - $now = [datetime]::Now - - # if the log is null, check batch then sleep and skip - if ($null -eq $log) { - Start-Sleep -Milliseconds 100 - continue - } + # safely pop off the first log from the array + $log = (Lock-PodeObject -Return -Object $PodeContext.LogsToProcess -ScriptBlock { + $log = $PodeContext.LogsToProcess[0] + $null = $PodeContext.LogsToProcess.RemoveAt(0) + return $log + }) + + # run the log item through the appropriate method + $logger = Get-PodeLogger -Name $log.Name + $now = [datetime]::Now + + # if the log is null, check batch then sleep and skip + if ($null -eq $log) { + Start-Sleep -Milliseconds 100 + continue + } - # convert to log item into a writable format - $rawItems = $log.Item - $_args = @($log.Item) + @($logger.Arguments) - $result = @(Invoke-PodeScriptBlock -ScriptBlock $logger.ScriptBlock -Arguments $_args -UsingVariables $logger.UsingVariables -Return -Splat) - - # check batching - $batch = $logger.Method.Batch - if ($batch.Size -gt 1) { - # add current item to batch - $batch.Items += $result - $batch.RawItems += $log.Item - $batch.LastUpdate = $now - - # if the current amount of items matches the batch, write - $result = $null - if ($batch.Items.Length -ge $batch.Size) { - $result = $batch.Items - $rawItems = $batch.RawItems - } + # convert to log item into a writable format + $rawItems = $log.Item + $_args = @($log.Item) + @($logger.Arguments) + $result = @(Invoke-PodeScriptBlock -ScriptBlock $logger.ScriptBlock -Arguments $_args -UsingVariables $logger.UsingVariables -Return -Splat) + + # check batching + $batch = $logger.Method.Batch + if ($batch.Size -gt 1) { + # add current item to batch + $batch.Items += $result + $batch.RawItems += $log.Item + $batch.LastUpdate = $now + + # if the current amount of items matches the batch, write + $result = $null + if ($batch.Items.Length -ge $batch.Size) { + $result = $batch.Items + $rawItems = $batch.RawItems + } + + # if we're writing, reset the items + if ($null -ne $result) { + $batch.Items = @() + $batch.RawItems = @() + } + } - # if we're writing, reset the items - if ($null -ne $result) { - $batch.Items = @() - $batch.RawItems = @() - } - } + # send the writable log item off to the log writer + if ($null -ne $result) { + $_args = @(, $result) + @($logger.Method.Arguments) + @(, $rawItems) + $null = Invoke-PodeScriptBlock -ScriptBlock $logger.Method.ScriptBlock -Arguments $_args -UsingVariables $logger.Method.UsingVariables -Splat + } - # send the writable log item off to the log writer - if ($null -ne $result) { - $_args = @(, $result) + @($logger.Method.Arguments) + @(, $rawItems) - $null = Invoke-PodeScriptBlock -ScriptBlock $logger.Method.ScriptBlock -Arguments $_args -UsingVariables $logger.Method.UsingVariables -Splat + # small sleep to lower cpu usage + Start-Sleep -Milliseconds 100 + } + catch { + $_ | Write-PodeErrorLog + } } - - # small sleep to lower cpu usage - Start-Sleep -Milliseconds 100 + } + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } + catch { + $_ | Write-PodeErrorLog + throw $_.Exception } } diff --git a/src/Private/Schedules.ps1 b/src/Private/Schedules.ps1 index 79b365b92..dd031017d 100644 --- a/src/Private/Schedules.ps1 +++ b/src/Private/Schedules.ps1 @@ -18,53 +18,43 @@ function Start-PodeScheduleRunspace { return } - Add-PodeSchedule -Name '__pode_schedule_housekeeper__' -Cron '@minutely' -ScriptBlock { - if ($PodeContext.Schedules.Processes.Count -eq 0) { - return - } + Add-PodeTimer -Name '__pode_schedule_housekeeper__' -Interval 30 -ScriptBlock { + try { + if ($PodeContext.Schedules.Processes.Count -eq 0) { + return + } - foreach ($key in $PodeContext.Schedules.Processes.Keys.Clone()) { - $process = $PodeContext.Schedules.Processes[$key] + $now = [datetime]::UtcNow - # is it completed? - if (!$process.Runspace.Handler.IsCompleted) { - continue + foreach ($key in $PodeContext.Schedules.Processes.Keys.Clone()) { + try { + $process = $PodeContext.Schedules.Processes[$key] + + # if it's completed or expired, dispose and remove + if ($process.Runspace.Handler.IsCompleted -or ($process.ExpireTime -lt $now)) { + Close-PodeScheduleInternal -Process $process + } + } + catch { + $_ | Write-PodeErrorLog + } } - # dispose and remove the schedule process - Close-PodeScheduleInternal -Process $process + $process = $null + } + catch { + $_ | Write-PodeErrorLog } - - $process = $null } $script = { - # select the schedules that trigger on-start - $_now = [DateTime]::Now - - $PodeContext.Schedules.Items.Values | - Where-Object { - $_.OnStart - } | ForEach-Object { - Invoke-PodeInternalSchedule -Schedule $_ - } - - # complete any schedules - Complete-PodeInternalSchedule -Now $_now - - # first, sleep for a period of time to get to 00 seconds (start of minute) - Start-Sleep -Seconds (60 - [DateTime]::Now.Second) - - while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + try { + # select the schedules that trigger on-start $_now = [DateTime]::Now - # select the schedules that need triggering $PodeContext.Schedules.Items.Values | Where-Object { - !$_.Completed -and - (($null -eq $_.StartTime) -or ($_.StartTime -le $_now)) -and - (($null -eq $_.EndTime) -or ($_.EndTime -ge $_now)) -and - (Test-PodeCronExpressions -Expressions $_.Crons -DateTime $_now) + $_.OnStart } | ForEach-Object { Invoke-PodeInternalSchedule -Schedule $_ } @@ -72,8 +62,46 @@ function Start-PodeScheduleRunspace { # complete any schedules Complete-PodeInternalSchedule -Now $_now - # cron expression only goes down to the minute, so sleep for 1min + # first, sleep for a period of time to get to 00 seconds (start of minute) Start-Sleep -Seconds (60 - [DateTime]::Now.Second) + + while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + try { + $_now = [DateTime]::Now + + # select the schedules that need triggering + $PodeContext.Schedules.Items.Values | + Where-Object { + !$_.Completed -and + (($null -eq $_.StartTime) -or ($_.StartTime -le $_now)) -and + (($null -eq $_.EndTime) -or ($_.EndTime -ge $_now)) -and + (Test-PodeCronExpressions -Expressions $_.Crons -DateTime $_now) + } | ForEach-Object { + try { + Invoke-PodeInternalSchedule -Schedule $_ + } + catch { + $_ | Write-PodeErrorLog + } + } + + # complete any schedules + Complete-PodeInternalSchedule -Now $_now + + # cron expression only goes down to the minute, so sleep for 1min + Start-Sleep -Seconds (60 - [DateTime]::Now.Second) + } + catch { + $_ | Write-PodeErrorLog + } + } + } + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } + catch { + $_ | Write-PodeErrorLog + throw $_.Exception } } @@ -128,17 +156,11 @@ function Complete-PodeInternalSchedule { $Now ) - # add any schedules to remove that have exceeded their end time - $Schedules = @($PodeContext.Schedules.Items.Values | - Where-Object { (($null -ne $_.EndTime) -and ($_.EndTime -lt $Now)) }) - - if (($null -eq $Schedules) -or ($Schedules.Length -eq 0)) { - return - } - # set any expired schedules as being completed - $Schedules | ForEach-Object { - $_.Completed = $true + foreach ($schedule in $PodeContext.Schedules.Items.Values) { + if (($null -ne $schedule.EndTime) -and ($schedule.EndTime -lt $Now)) { + $schedule.Completed = $true + } } } @@ -182,6 +204,7 @@ function Invoke-PodeInternalSchedule { function Invoke-PodeInternalScheduleLogic { param( [Parameter(Mandatory = $true)] + [hashtable] $Schedule, [Parameter()] @@ -190,44 +213,120 @@ function Invoke-PodeInternalScheduleLogic { ) try { + # generate processId for schedule + $processId = New-PodeGuid + # setup event param $parameters = @{ - Event = @{ - Lockable = $PodeContext.Threading.Lockables.Global - Sender = $Schedule - Metadata = @{} - } + ProcessId = $processId + ArgumentList = $ArgumentList } - # add any schedule args - foreach ($key in $Schedule.Arguments.Keys) { - $parameters[$key] = $Schedule.Arguments[$key] - } + # what is the expire time if using "create" timeout? + $expireTime = [datetime]::MaxValue + $createTime = [datetime]::UtcNow - # add adhoc schedule invoke args - if (($null -ne $ArgumentList) -and ($ArgumentList.Count -gt 0)) { - foreach ($key in $ArgumentList.Keys) { - $parameters[$key] = $ArgumentList[$key] - } + if (($Schedule.Timeout.From -ieq 'Create') -and ($Schedule.Timeout.Value -ge 0)) { + $expireTime = $createTime.AddSeconds($Schedule.Timeout.Value) } - # add any using variables - if ($null -ne $Schedule.UsingVariables) { - foreach ($usingVar in $Schedule.UsingVariables) { - $parameters[$usingVar.NewName] = $usingVar.Value - } + # add the schedule process + $PodeContext.Schedules.Processes[$processId] = @{ + ID = $processId + Schedule = $Schedule.Name + Runspace = $null + CreateTime = $createTime + StartTime = $null + ExpireTime = $expireTime + Timeout = $Schedule.Timeout + State = 'Pending' } - $name = New-PodeGuid - $runspace = Add-PodeRunspace -Type Schedules -ScriptBlock (($Schedule.Script).GetNewClosure()) -Parameters $parameters -PassThru + # start the schedule runspace + $scriptblock = Get-PodeScheduleScriptBlock + $runspace = Add-PodeRunspace -Type Schedules -ScriptBlock $scriptblock -Parameters $parameters -PassThru - $PodeContext.Schedules.Processes[$name] = @{ - ID = $name - Schedule = $Schedule.Name - Runspace = $runspace - } + # add runspace to process + $PodeContext.Schedules.Processes[$processId].Runspace = $runspace } catch { $_ | Write-PodeErrorLog } +} + +function Get-PodeScheduleScriptBlock { + return { + param($ProcessId, $ArgumentList) + + try { + # get the schedule process, error if not found + $process = $PodeContext.Schedules.Processes[$ProcessId] + if ($null -eq $process) { + # Schedule process does not exist: $ProcessId + throw ($PodeLocale.scheduleProcessDoesNotExistExceptionMessage -f $ProcessId) + } + + # set start time and state + $process.StartTime = [datetime]::UtcNow + $process.State = 'Running' + + # set expire time if timeout based on "start" time + if (($process.Timeout.From -ieq 'Start') -and ($process.Timeout.Value -ge 0)) { + $process.ExpireTime = $process.StartTime.AddSeconds($process.Timeout.Value) + } + + # get the schedule, error if not found + $schedule = Find-PodeSchedule -Name $process.Schedule + if ($null -eq $schedule) { + throw ($PodeLocale.scheduleDoesNotExistExceptionMessage -f $process.Schedule) + } + + # build the script arguments + $ScheduleEvent = @{ + Lockable = $PodeContext.Threading.Lockables.Global + Sender = $schedule + Timestamp = [DateTime]::UtcNow + Metadata = @{} + } + + $_args = @{ Event = $ScheduleEvent } + + if ($null -ne $schedule.Arguments) { + foreach ($key in $schedule.Arguments.Keys) { + $_args[$key] = $schedule.Arguments[$key] + } + } + + if ($null -ne $ArgumentList) { + foreach ($key in $ArgumentList.Keys) { + $_args[$key] = $ArgumentList[$key] + } + } + + # add any using variables + if ($null -ne $schedule.UsingVariables) { + foreach ($usingVar in $schedule.UsingVariables) { + $_args[$usingVar.NewName] = $usingVar.Value + } + } + + # invoke the script from the schedule + Invoke-PodeScriptBlock -ScriptBlock $schedule.Script -Arguments $_args -Scoped -Splat + + # set state to completed + $process.State = 'Completed' + } + catch { + # update the state + if ($null -ne $process) { + $process.State = 'Failed' + } + + # log the error + $_ | Write-PodeErrorLog + } + finally { + Invoke-PodeGC + } + } } \ No newline at end of file diff --git a/src/Private/Server.ps1 b/src/Private/Server.ps1 index 82a971288..63b63f8a9 100644 --- a/src/Private/Server.ps1 +++ b/src/Private/Server.ps1 @@ -66,12 +66,12 @@ function Start-PodeInternalServer { # start runspace for loggers Start-PodeLoggingRunspace - # start runspace for timers - Start-PodeTimerRunspace - # start runspace for schedules Start-PodeScheduleRunspace + # start runspace for timers + Start-PodeTimerRunspace + # start runspace for gui Start-PodeGuiRunspace @@ -254,7 +254,7 @@ function Restart-PodeInternalServer { # clear tasks $PodeContext.Tasks.Items.Clear() - $PodeContext.Tasks.Results.Clear() + $PodeContext.Tasks.Processes.Clear() # clear file watchers $PodeContext.Fim.Items.Clear() diff --git a/src/Private/Tasks.ps1 b/src/Private/Tasks.ps1 index 1a4c1f7d2..ae1f778cb 100644 --- a/src/Private/Tasks.ps1 +++ b/src/Private/Tasks.ps1 @@ -8,39 +8,38 @@ function Start-PodeTaskHousekeeper { } Add-PodeTimer -Name '__pode_task_housekeeper__' -Interval 30 -ScriptBlock { - if ($PodeContext.Tasks.Results.Count -eq 0) { - return - } - - $now = [datetime]::UtcNow - - foreach ($key in $PodeContext.Tasks.Results.Keys.Clone()) { - $result = $PodeContext.Tasks.Results[$key] - - # has it force expired? - if ($result.ExpireTime -lt $now) { - Close-PodeTaskInternal -Result $result - continue + try { + if ($PodeContext.Tasks.Processes.Count -eq 0) { + return } - # is it completed? - if (!$result.Runspace.Handler.IsCompleted) { - continue + $now = [datetime]::UtcNow + + foreach ($key in $PodeContext.Tasks.Processes.Keys.Clone()) { + try { + $process = $PodeContext.Tasks.Processes[$key] + + # has it completed or expire? then dispose and remove + if ((($null -ne $process.CompletedTime) -and ($process.CompletedTime.AddMinutes(1) -lt $now)) -or ($process.ExpireTime -lt $now)) { + Close-PodeTaskInternal -Process $process + continue + } + + # if completed, and no completed time, set it + if ($process.Runspace.Handler.IsCompleted -and ($null -eq $process.CompletedTime)) { + $process.CompletedTime = $now + } + } + catch { + $_ | Write-PodeErrorLog + } } - # is a completed time set? - if ($null -eq $result.CompletedTime) { - $result.CompletedTime = [datetime]::UtcNow - continue - } - - # is it expired by completion? if so, dispose and remove - if ($result.CompletedTime.AddMinutes(1) -lt $now) { - Close-PodeTaskInternal -Result $result - } + $process = $null + } + catch { + $_ | Write-PodeErrorLog } - - $result = $null } } @@ -48,21 +47,22 @@ function Close-PodeTaskInternal { param( [Parameter()] [hashtable] - $Result + $Process ) - if ($null -eq $Result) { + if ($null -eq $Process) { return } - Close-PodeDisposable -Disposable $Result.Runspace.Pipeline - Close-PodeDisposable -Disposable $Result.Result - $null = $PodeContext.Tasks.Results.Remove($Result.ID) + Close-PodeDisposable -Disposable $Process.Runspace.Pipeline + Close-PodeDisposable -Disposable $Process.Result + $null = $PodeContext.Tasks.Processes.Remove($Process.ID) } function Invoke-PodeInternalTask { param( [Parameter(Mandatory = $true)] + [hashtable] $Task, [Parameter()] @@ -71,66 +71,151 @@ function Invoke-PodeInternalTask { [Parameter()] [int] - $Timeout = -1 + $Timeout = -1, + + [Parameter()] + [ValidateSet('Default', 'Create', 'Start')] + [string] + $TimeoutFrom = 'Default' ) try { + # generate processId for task + $processId = New-PodeGuid + # setup event param $parameters = @{ - Event = @{ - Lockable = $PodeContext.Threading.Lockables.Global - Sender = $Task - Metadata = @{} - } + ProcessId = $processId + ArgumentList = $ArgumentList } - # add any task args - foreach ($key in $Task.Arguments.Keys) { - $parameters[$key] = $Task.Arguments[$key] + # what's the timeout values to use? + if ($TimeoutFrom -eq 'Default') { + $TimeoutFrom = $Task.Timeout.From } - # add adhoc task invoke args - if (($null -ne $ArgumentList) -and ($ArgumentList.Count -gt 0)) { - foreach ($key in $ArgumentList.Keys) { - $parameters[$key] = $ArgumentList[$key] - } + if ($Timeout -eq -1) { + $Timeout = $Task.Timeout.Value } - # add any using variables - if ($null -ne $Task.UsingVariables) { - foreach ($usingVar in $Task.UsingVariables) { - $parameters[$usingVar.NewName] = $usingVar.Value - } - } - - $name = New-PodeGuid - $result = [System.Management.Automation.PSDataCollection[psobject]]::new() - $runspace = Add-PodeRunspace -Type Tasks -ScriptBlock (($Task.Script).GetNewClosure()) -Parameters $parameters -OutputStream $result -PassThru + # what is the expire time if using "create" timeout? + $expireTime = [datetime]::MaxValue + $createTime = [datetime]::UtcNow - if ($Timeout -ge 0) { - $expireTime = [datetime]::UtcNow.AddSeconds($Timeout) - } - else { - $expireTime = [datetime]::MaxValue + if (($TimeoutFrom -ieq 'Create') -and ($Timeout -ge 0)) { + $expireTime = $createTime.AddSeconds($Timeout) } - $PodeContext.Tasks.Results[$name] = @{ - ID = $name + # add task process + $result = [System.Management.Automation.PSDataCollection[psobject]]::new() + $PodeContext.Tasks.Processes[$processId] = @{ + ID = $processId Task = $Task.Name - Runspace = $runspace + Runspace = $null Result = $result + CreateTime = $createTime + StartTime = $null CompletedTime = $null ExpireTime = $expireTime - Timeout = $Timeout + Timeout = @{ + Value = $Timeout + From = $TimeoutFrom + } + State = 'Pending' } - return $PodeContext.Tasks.Results[$name] + # start the task runspace + $scriptblock = Get-PodeTaskScriptBlock + $runspace = Add-PodeRunspace -Type Tasks -ScriptBlock $scriptblock -Parameters $parameters -OutputStream $result -PassThru + + # add runspace to process + $PodeContext.Tasks.Processes[$processId].Runspace = $runspace + + # return the task process + return $PodeContext.Tasks.Processes[$processId] } catch { $_ | Write-PodeErrorLog } } +function Get-PodeTaskScriptBlock { + return { + param($ProcessId, $ArgumentList) + + try { + $process = $PodeContext.Tasks.Processes[$ProcessId] + if ($null -eq $process) { + # Task process does not exist: $ProcessId + throw ($PodeLocale.taskProcessDoesNotExistExceptionMessage -f $ProcessId) + } + + # set the start time and state + $process.StartTime = [datetime]::UtcNow + $process.State = 'Running' + + # set the expire time of timeout based on "start" time + if (($process.Timeout.From -ieq 'Start') -and ($process.Timeout.Value -ge 0)) { + $process.ExpireTime = $process.StartTime.AddSeconds($process.Timeout.Value) + } + + # get the task, error if not found + $task = $PodeContext.Tasks.Items[$process.Task] + if ($null -eq $task) { + # Task does not exist + throw ($PodeLocale.taskDoesNotExistExceptionMessage -f $process.Task) + } + + # build the script arguments + $TaskEvent = @{ + Lockable = $PodeContext.Threading.Lockables.Global + Sender = $Task + Timestamp = [DateTime]::UtcNow + Metadata = @{} + } + + $_args = @{ Event = $TaskEvent } + + if ($null -ne $task.Arguments) { + foreach ($key in $task.Arguments.Keys) { + $_args[$key] = $task.Arguments[$key] + } + } + + if ($null -ne $ArgumentList) { + foreach ($key in $ArgumentList.Keys) { + $_args[$key] = $ArgumentList[$key] + } + } + + # add any using variables + if ($null -ne $task.UsingVariables) { + foreach ($usingVar in $task.UsingVariables) { + $_args[$usingVar.NewName] = $usingVar.Value + } + } + + # invoke the script from the task + Invoke-PodeScriptBlock -ScriptBlock $task.Script -Arguments $_args -Scoped -Splat -Return + + # set the state to completed + $process.State = 'Completed' + } + catch { + # update the state + if ($null -ne $process) { + $process.State = 'Failed' + } + + # log the error + $_ | Write-PodeErrorLog + } + finally { + Invoke-PodeGC + } + } +} + function Wait-PodeNetTaskInternal { [CmdletBinding()] [OutputType([object])] @@ -168,7 +253,8 @@ function Wait-PodeNetTaskInternal { # if the main task isnt complete, it timed out if (($null -ne $timeoutTask) -and (!$Task.IsCompleted)) { - throw [System.TimeoutException]::new($PodeLocale.taskTimedOutExceptionMessage -f $Timeout) #"Task has timed out after $($Timeout)ms") + # "Task has timed out after $($Timeout)ms") + throw [System.TimeoutException]::new($PodeLocale.taskTimedOutExceptionMessage -f $Timeout) } # only return a value if the result has one diff --git a/src/Private/Timers.ps1 b/src/Private/Timers.ps1 index 3dc1a9db3..31fb32412 100644 --- a/src/Private/Timers.ps1 +++ b/src/Private/Timers.ps1 @@ -19,50 +19,70 @@ function Start-PodeTimerRunspace { } $script = { - while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { - $_now = [DateTime]::Now - - # only run timers that haven't completed, and have a next trigger in the past - $PodeContext.Timers.Items.Values | Where-Object { - !$_.Completed -and ($_.OnStart -or ($_.NextTriggerTime -le $_now)) - } | ForEach-Object { - $_.OnStart = $false - $_.Count++ - - # set last trigger to current next trigger - if ($null -ne $_.NextTriggerTime) { - $_.LastTriggerTime = $_.NextTriggerTime + try { + while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + try { + $_now = [DateTime]::Now + + # only run timers that haven't completed, and have a next trigger in the past + foreach ($timer in $PodeContext.Timers.Items.Values) { + if ($timer.Completed -or (!$timer.OnStart -and ($timer.NextTriggerTime -gt $_now))) { + continue + } + + try { + $timer.OnStart = $false + $timer.Count++ + + # set last trigger to current next trigger + if ($null -ne $timer.NextTriggerTime) { + $timer.LastTriggerTime = $timer.NextTriggerTime + } + else { + $timer.LastTriggerTime = $_now + } + + # has the timer completed? + if (($timer.Limit -gt 0) -and ($timer.Count -ge $timer.Limit)) { + $timer.Completed = $true + } + + # next trigger + if (!$timer.Completed) { + $timer.NextTriggerTime = $_now.AddSeconds($timer.Interval) + } + else { + $timer.NextTriggerTime = $null + } + + # run the timer + Invoke-PodeInternalTimer -Timer $timer + } + catch { + $_ | Write-PodeErrorLog + } + } + + Start-Sleep -Seconds 1 } - else { - $_.LastTriggerTime = [datetime]::Now + catch { + $_ | Write-PodeErrorLog } - - # has the timer completed? - if (($_.Limit -gt 0) -and ($_.Count -ge $_.Limit)) { - $_.Completed = $true - } - - # next trigger - if (!$_.Completed) { - $_.NextTriggerTime = $_now.AddSeconds($_.Interval) - } - else { - $_.NextTriggerTime = $null - } - - # run the timer - Invoke-PodeInternalTimer -Timer $_ } - - Start-Sleep -Seconds 1 + } + catch [System.OperationCanceledException] { + $_ | Write-PodeErrorLog -Level Debug + } + catch { + $_ | Write-PodeErrorLog + throw $_.Exception } } - Add-PodeRunspace -Type Main -ScriptBlock $script + Add-PodeRunspace -Type Timers -ScriptBlock $script } function Invoke-PodeInternalTimer { - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] param( [Parameter(Mandatory = $true)] @@ -74,10 +94,11 @@ function Invoke-PodeInternalTimer { ) try { - $global:TimerEvent = @{ - Lockable = $PodeContext.Threading.Lockables.Global - Sender = $Timer - Metadata = @{} + $TimerEvent = @{ + Lockable = $PodeContext.Threading.Lockables.Global + Sender = $Timer + Timestamp = [DateTime]::UtcNow + Metadata = @{} } # add main timer args @@ -92,9 +113,12 @@ function Invoke-PodeInternalTimer { } # invoke timer - $null = Invoke-PodeScriptBlock -ScriptBlock $Timer.Script -Arguments $_args -UsingVariables $Timer.UsingVariables -Scoped -Splat + Invoke-PodeScriptBlock -ScriptBlock $Timer.Script.GetNewClosure() -Arguments $_args -UsingVariables $Timer.UsingVariables -Scoped -Splat -NoNewClosure } catch { $_ | Write-PodeErrorLog } + finally { + Invoke-PodeGC + } } \ No newline at end of file diff --git a/src/Public/Schedules.ps1 b/src/Public/Schedules.ps1 index 2b74cb538..8fb460d33 100644 --- a/src/Public/Schedules.ps1 +++ b/src/Public/Schedules.ps1 @@ -26,6 +26,12 @@ A DateTime for when the Schedule should stop triggering, and be removed. .PARAMETER ArgumentList A hashtable of arguments to supply to the Schedule's ScriptBlock. +.PARAMETER Timeout +An optional timeout, in seconds, for the Schedule's logic. (Default: -1 [never timeout]) + +.PARAMETER TimeoutFrom +An optional timeout from either 'Create' or 'Start'. (Default: 'Create') + .PARAMETER FilePath A literal, or relative, path to a file containing a ScriptBlock for the Schedule's logic. @@ -79,6 +85,15 @@ function Add-PodeSchedule { [hashtable] $ArgumentList, + [Parameter()] + [int] + $Timeout = -1, + + [Parameter()] + [ValidateSet('Create', 'Start')] + [string] + $TimeoutFrom = 'Create', + [switch] $OnStart ) @@ -137,6 +152,10 @@ function Add-PodeSchedule { Arguments = (Protect-PodeValue -Value $ArgumentList -Default @{}) OnStart = $OnStart Completed = ($null -eq $nextTrigger) + Timeout = @{ + Value = $Timeout + From = $TimeoutFrom + } } } @@ -545,4 +564,92 @@ function Use-PodeSchedules { ) Use-PodeFolder -Path $Path -DefaultPath 'schedules' +} + +<# +.SYNOPSIS +Get all Schedule Processes. + +.DESCRIPTION +Get all Schedule Processes, with support for filtering. + +.PARAMETER Name +An optional Name of the Schedule to filter by, can be one or more. + +.PARAMETER Id +An optional ID of the Schedule process to filter by, can be one or more. + +.PARAMETER State +An optional State of the Schedule process to filter by, can be one or more. + +.EXAMPLE +Get-PodeScheduleProcess + +.EXAMPLE +Get-PodeScheduleProcess -Name 'ScheduleName' + +.EXAMPLE +Get-PodeScheduleProcess -Id 'ScheduleId' + +.EXAMPLE +Get-PodeScheduleProcess -State 'Running' +#> +function Get-PodeScheduleProcess { + [CmdletBinding()] + param( + [Parameter()] + [string[]] + $Name, + + [Parameter()] + [string[]] + $Id, + + [Parameter()] + [ValidateSet('All', 'Pending', 'Running', 'Completed', 'Failed')] + [string[]] + $State = 'All' + ) + + $processes = $PodeContext.Schedules.Processes.Values + + # filter processes by name + if (($null -ne $Name) -and ($Name.Length -gt 0)) { + $processes = @(foreach ($_name in $Name) { + foreach ($process in $processes) { + if ($process.Schedule -ine $_name) { + continue + } + + $process + } + }) + } + + # filter processes by id + if (($null -ne $Id) -and ($Id.Length -gt 0)) { + $processes = @(foreach ($_id in $Id) { + foreach ($process in $processes) { + if ($process.ID -ine $_id) { + continue + } + + $process + } + }) + } + + # filter processes by status + if ($State -inotcontains 'All') { + $processes = @(foreach ($process in $processes) { + if ($State -inotcontains $process.State) { + continue + } + + $process + }) + } + + # return processes + return $processes } \ No newline at end of file diff --git a/src/Public/Tasks.ps1 b/src/Public/Tasks.ps1 index 0f46cbded..02e45bce3 100644 --- a/src/Public/Tasks.ps1 +++ b/src/Public/Tasks.ps1 @@ -17,6 +17,12 @@ A literal, or relative, path to a file containing a ScriptBlock for the Task's l .PARAMETER ArgumentList A hashtable of arguments to supply to the Task's ScriptBlock. +.PARAMETER Timeout +A Timeout, in seconds, to abort running the Task process. (Default: -1 [never timeout]) + +.PARAMETER TimeoutFrom +Where to start the Timeout from, either 'Create', 'Start'. (Default: 'Create') + .EXAMPLE Add-PodeTask -Name 'Example1' -ScriptBlock { Invoke-SomeLogic } @@ -40,7 +46,16 @@ function Add-PodeTask { [Parameter()] [hashtable] - $ArgumentList + $ArgumentList, + + [Parameter()] + [int] + $Timeout = -1, + + [Parameter()] + [ValidateSet('Create', 'Start')] + [string] + $TimeoutFrom = 'Create' ) # ensure the task doesn't already exist if ($PodeContext.Tasks.Items.ContainsKey($Name)) { @@ -63,6 +78,10 @@ function Add-PodeTask { Script = $ScriptBlock UsingVariables = $usingVars Arguments = (Protect-PodeValue -Value $ArgumentList -Default @{}) + Timeout = @{ + Value = $Timeout + From = $TimeoutFrom + } } } @@ -118,6 +137,7 @@ Invoke a Task. .DESCRIPTION Invoke a Task either asynchronously or synchronously, with support for returning values. +The function returns the Task process onbject which was triggered. .PARAMETER Name The Name of the Task. @@ -126,10 +146,16 @@ The Name of the Task. A hashtable of arguments to supply to the Task's ScriptBlock. .PARAMETER Timeout -A Timeout, in seconds, to abort running the task. (Default: -1 [never timeout]) +A Timeout, in seconds, to abort running the Task process. (Default: -1 [never timeout]) + +.PARAMETER TimeoutFrom +Where to start the Timeout from, either 'Default', 'Create', or 'Start'. (Default: 'Default' - will use the value from Add-PodeTask) .PARAMETER Wait -If supplied, Pode will wait until the Task has finished executing, and then return any values. +If supplied, Pode will wait until the Task process has finished executing, and then return any values. + +.OUTPUTS +The triggered Task process. .EXAMPLE Invoke-PodeTask -Name 'Example1' -Wait -Timeout 5 @@ -155,6 +181,11 @@ function Invoke-PodeTask { [int] $Timeout = -1, + [Parameter()] + [ValidateSet('Default', 'Create', 'Start')] + [string] + $TimeoutFrom = 'Default', + [switch] $Wait ) @@ -166,7 +197,7 @@ function Invoke-PodeTask { } # run task logic - $task = Invoke-PodeInternalTask -Task $PodeContext.Tasks.Items[$Name] -ArgumentList $ArgumentList -Timeout $Timeout + $task = Invoke-PodeInternalTask -Task $PodeContext.Tasks.Items[$Name] -ArgumentList $ArgumentList -Timeout $Timeout -TimeoutFrom $TimeoutFrom # wait, and return result? if ($Wait) { @@ -365,18 +396,18 @@ function Close-PodeTask { $Task ) - Close-PodeTaskInternal -Result $Task + Close-PodeTaskInternal -Process $Task } <# .SYNOPSIS -Test if a running Task has completed. +Test if a running Task process has completed. .DESCRIPTION -Test if a running Task has completed. +Test if a running Task process has completed. .PARAMETER Task -The Task to be check. +The Task process to be check. The process returned by either Invoke-PodeTask or Get-PodeTaskProcess. .EXAMPLE Invoke-PodeTask -Name 'Example1' | Test-PodeTaskCompleted @@ -395,13 +426,13 @@ function Test-PodeTaskCompleted { <# .SYNOPSIS -Waits for a task to finish, and returns a result if there is one. +Waits for a Task process to finish, and returns a result if there is one. .DESCRIPTION -Waits for a task to finish, and returns a result if there is one. +Waits for a Task process to finish, and returns a result if there is one. .PARAMETER Task -The task to wait on. +The Task process to wait on. The process returned by either Invoke-PodeTask or Get-PodeTaskProcess. .PARAMETER Timeout An optional Timeout in milliseconds. @@ -434,4 +465,93 @@ function Wait-PodeTask { # Task type is invalid, expected either [System.Threading.Tasks.Task] or [hashtable] throw ($PodeLocale.invalidTaskTypeExceptionMessage) +} + + +<# +.SYNOPSIS +Get all Task Processes. + +.DESCRIPTION +Get all Task Processes, with support for filtering. These are the processes created when using Invoke-PodeTask. + +.PARAMETER Name +An optional Name of the Task to filter by, can be one or more. + +.PARAMETER Id +An optional ID of the Task process to filter by, can be one or more. + +.PARAMETER State +An optional State of the Task process to filter by, can be one or more. + +.EXAMPLE +Get-PodeTaskProcess + +.EXAMPLE +Get-PodeTaskProcess -Name 'TaskName' + +.EXAMPLE +Get-PodeTaskProcess -Id 'TaskId' + +.EXAMPLE +Get-PodeTaskProcess -State 'Running' +#> +function Get-PodeTaskProcess { + [CmdletBinding()] + param( + [Parameter()] + [string[]] + $Name, + + [Parameter()] + [string[]] + $Id, + + [Parameter()] + [ValidateSet('All', 'Pending', 'Running', 'Completed', 'Failed')] + [string[]] + $State = 'All' + ) + + $processes = $PodeContext.Tasks.Processes.Values + + # filter processes by name + if (($null -ne $Name) -and ($Name.Length -gt 0)) { + $processes = @(foreach ($_name in $Name) { + foreach ($process in $processes) { + if ($process.Task -ine $_name) { + continue + } + + $process + } + }) + } + + # filter processes by id + if (($null -ne $Id) -and ($Id.Length -gt 0)) { + $processes = @(foreach ($_id in $Id) { + foreach ($process in $processes) { + if ($process.ID -ine $_id) { + continue + } + + $process + } + }) + } + + # filter processes by status + if ($State -inotcontains 'All') { + $processes = @(foreach ($process in $processes) { + if ($State -inotcontains $process.State) { + continue + } + + $process + }) + } + + # return processes + return $processes } \ No newline at end of file diff --git a/src/Public/Timers.ps1 b/src/Public/Timers.ps1 index 8042bca71..548f9db9b 100644 --- a/src/Public/Timers.ps1 +++ b/src/Public/Timers.ps1 @@ -259,7 +259,7 @@ function Edit-PodeTimer { # ensure the timer exists if (!$PodeContext.Timers.Items.ContainsKey($Name)) { - # Timer 'Name' does not exist + # Timer 'Name' does not exist throw ($PodeLocale.timerDoesNotExistExceptionMessage -f $Name) } diff --git a/src/Public/Utilities.ps1 b/src/Public/Utilities.ps1 index dde5ff1bb..d268f34b9 100644 --- a/src/Public/Utilities.ps1 +++ b/src/Public/Utilities.ps1 @@ -1362,6 +1362,23 @@ function ConvertFrom-PodeXml { $oHash.$childname += (ConvertFrom-PodeXml $child) } } + return $oHash +} + +<# +.SYNOPSIS +Invokes the garbage collector. + +.DESCRIPTION +Invokes the garbage collector. + +.EXAMPLE +Invoke-PodeGC +#> +function Invoke-PodeGC { + [CmdletBinding()] + param() + [System.GC]::Collect() } \ No newline at end of file diff --git a/tests/unit/Server.Tests.ps1 b/tests/unit/Server.Tests.ps1 index 21a1a7514..222f7af1d 100644 --- a/tests/unit/Server.Tests.ps1 +++ b/tests/unit/Server.Tests.ps1 @@ -37,6 +37,7 @@ Describe 'Start-PodeInternalServer' { Mock Invoke-PodeEvent { } Mock Write-Verbose { } Mock Add-PodeScopedVariablesInbuilt { } + Mock Write-PodeHost { } } It 'Calls one-off script logic' { @@ -221,11 +222,11 @@ Describe 'Restart-PodeInternalServer' { Processes = @{} } Tasks = @{ - Enabled = $true - Items = @{ + Enabled = $true + Items = @{ key = 'value' } - Results = @{} + Processes = @{} } Fim = @{ Enabled = $true From 3e51068dee2f99e20c5c0ff8f852d3f54b80ddb4 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Sat, 14 Sep 2024 16:50:27 +0100 Subject: [PATCH 153/177] Ignore 'issues' folders in example-docs building, force internal YAML --- pode.build.ps1 | 2 +- tests/unit/Helpers.Tests.ps1 | 16 +++++++++++++--- tests/unit/_.Tests.ps1 | 8 ++++---- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/pode.build.ps1 b/pode.build.ps1 index 4cd21aee6..7e972d452 100644 --- a/pode.build.ps1 +++ b/pode.build.ps1 @@ -353,7 +353,7 @@ Task IndexSamples { # List of directories to exclude $sampleMarkDownPath = './docs/Getting-Started/Samples.md' $excludeDirs = @('scripts', 'views', 'static', 'public', 'assets', 'timers', 'modules', - 'Authentication', 'certs', 'logs', 'relative', 'routes') + 'Authentication', 'certs', 'logs', 'relative', 'routes', 'issues') # Convert exlusion list into single regex pattern for directory matching $dirSeparator = [IO.Path]::DirectorySeparatorChar diff --git a/tests/unit/Helpers.Tests.ps1 b/tests/unit/Helpers.Tests.ps1 index e9d9cb76f..d1c4a6e43 100644 --- a/tests/unit/Helpers.Tests.ps1 +++ b/tests/unit/Helpers.Tests.ps1 @@ -2,7 +2,7 @@ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] param() BeforeAll { - Add-Type -AssemblyName "System.Net.Http" -ErrorAction SilentlyContinue + Add-Type -AssemblyName 'System.Net.Http' -ErrorAction SilentlyContinue $path = $PSCommandPath $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } @@ -770,7 +770,7 @@ Describe 'Get-PodeEndpointInfo' { } It 'Throws an error for an invalid IP endpoint' { - { Get-PodeEndpointInfo -Address '700.0.0.a' } | Should -Throw -ExpectedMessage ($PodeLocale.failedToParseAddressExceptionMessage -f '700.0.0.a' ) #'*Failed to parse*' + { Get-PodeEndpointInfo -Address '700.0.0.a' } | Should -Throw -ExpectedMessage ($PodeLocale.failedToParseAddressExceptionMessage -f '700.0.0.a' ) #'*Failed to parse*' } It 'Throws an error for an out-of-range IP endpoint' { @@ -1669,8 +1669,18 @@ Describe 'New-PodeCron' { Describe 'ConvertTo-PodeYaml Tests' { BeforeAll { - $PodeContext = @{ Server = @{InternalCache = @{} } } + $PodeContext = @{ + Server = @{ + InternalCache = @{} + Web = @{ + OpenApi = @{ + UsePodeYamlInternal = $true + } + } + } + } } + Context 'When converting basic types' { It 'Converts strings correctly' { $result = 'hello world' | ConvertTo-PodeYaml diff --git a/tests/unit/_.Tests.ps1 b/tests/unit/_.Tests.ps1 index 42b67b2f6..61e8aad23 100644 --- a/tests/unit/_.Tests.ps1 +++ b/tests/unit/_.Tests.ps1 @@ -7,7 +7,7 @@ BeforeDiscovery { # List of directories to exclude $excludeDirs = @('scripts', 'views', 'static', 'public', 'assets', 'timers', 'modules', - 'Authentication', 'certs', 'logs', 'relative', 'routes') + 'Authentication', 'certs', 'logs', 'relative', 'routes', 'issues') # Convert exlusion list into single regex pattern for directory matching $dirSeparator = [IO.Path]::DirectorySeparatorChar @@ -15,9 +15,9 @@ BeforeDiscovery { # get the example scripts $ps1Files = @(Get-ChildItem -Path $examplesPath -Filter *.ps1 -Recurse -File -Force | - Where-Object { - $_.FullName -inotmatch $excludeDirs - }).FullName + Where-Object { + $_.FullName -inotmatch $excludeDirs + }).FullName } BeforeAll { From 91ae29508c6f8e171163b2b6eda7af580fa033f3 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Sat, 14 Sep 2024 18:40:53 +0100 Subject: [PATCH 154/177] Clean-up, and adds quick schedule/task process docs --- docs/Tutorials/Schedules.md | 23 +++++++++++++++++++++++ docs/Tutorials/Tasks.md | 35 +++++++++++++++++++++++++++++------ src/Locales/de/Pode.psd1 | 2 +- src/Private/Context.ps1 | 5 ----- src/Private/Tasks.ps1 | 2 +- 5 files changed, 54 insertions(+), 13 deletions(-) diff --git a/docs/Tutorials/Schedules.md b/docs/Tutorials/Schedules.md index 9c754bfb1..2665501d0 100644 --- a/docs/Tutorials/Schedules.md +++ b/docs/Tutorials/Schedules.md @@ -126,6 +126,29 @@ Get-PodeSchedule -Name Name1 Get-PodeSchedule -Name Name1, Name2 ``` +## Getting Schedule Processes + +You can retrieve a list of processes triggered by Schedules via [`Get-PodeScheduleProcess`](../../Functions/Schedules/Get-PodeScheduleProcess) - this will return processes created either by a Schedule's natural time-based trigger, or via [`Invoke-PodeSchedule`](../../Functions/Schedules/Invoke-PodeSchedule). + +You can either retrieve all processes, or filter them by Schedule Name, or Process ID/Status: + +```powershell +# retrieves all schedule processes +Get-PodeScheduleProcess + +# retrieves all schedule processes for the "ScheduleName" process +Get-PodeScheduleProcess -Name 'ScheduleName' + +# retrieves the schedule process with ID "ScheduleId" +Get-PodeScheduleProcess -Id 'ScheduleId' + +# retrieves all running schedule processes +Get-PodeScheduleProcess -State 'Running' + +# retrieves all pending schedule processes for "ScheduleName" +Get-PodeScheduleProcess -Name 'ScheduleName' -State 'Running' +``` + ## Next Trigger Time When you retrieve a Schedule using [`Get-PodeSchedule`](../../Functions/Schedules/Get-PodeSchedule), each Schedule object will already have its next trigger time as `NextTriggerTime`. However, if you want to get a trigger time further ino the future than this, then you can use the [`Get-PodeScheduleNextTrigger`](../../Functions/Schedules/Get-PodeScheduleNextTrigger) function. diff --git a/docs/Tutorials/Tasks.md b/docs/Tutorials/Tasks.md index ac257a98c..f6a98e339 100644 --- a/docs/Tutorials/Tasks.md +++ b/docs/Tutorials/Tasks.md @@ -51,7 +51,7 @@ Add-PodeTask -Name 'Example' -ArgumentList @{ Name = 'Rick'; Environment = 'Mult } ``` -Tasks parameters **must** be bound in the param block in order to be used, but the values for the paramters can be set through the `-ArgumentList` hashtable parameter in either the Add-PodeTask definition or when invoking the task. The following snippet would populate the parameters to the task with the same values as the above example but the `-ArgumentList` parameter is populated during invocation. Note that Keys in the `-ArgumentList` hashtable parameter set during invocation override the same Keys set during task creation: +Tasks parameters **must** be bound in the param block in order to be used, but the values for the paramters can be set through the `-ArgumentList` hashtable parameter in either the Add-PodeTask definition or when invoking the task. The following snippet would populate the parameters to the task with the same values as the above example but the `-ArgumentList` parameter is populated during invocation. Note that Keys in the `-ArgumentList` hashtable parameter set during invocation override the same Keys set during task creation: ```powershell Add-PodeTask -Name 'Example' -ScriptBlock { @@ -184,6 +184,29 @@ Get-PodeTask -Name Example1 Get-PodeTask -Name Example1, Example2 ``` +## Getting Task Processes + +You can retrieve a list of processes triggered by Tasks via [`Get-PodeTaskProcess`](../../Functions/Tasks/Get-PodeTaskProcess) - this will return processes created via [`Invoke-PodeTask`](../../Functions/Tasks/Invoke-PodeTask). + +You can either retrieve all processes, or filter them by Task Name, or Process ID/Status: + +```powershell +# retrieves all task processes +Get-PodeTaskProcess + +# retrieves all task processes for the "TaskName" process +Get-PodeTaskProcess -Name 'TaskName' + +# retrieves the task process with ID "TaskId" +Get-PodeTaskProcess -Id 'TaskId' + +# retrieves all running task processes +Get-PodeTaskProcess -State 'Running' + +# retrieves all pending task processes for "TaskName" +Get-PodeTaskProcess -Name 'TaskName' -State 'Running' +``` + ## Task Object !!! warning @@ -191,8 +214,8 @@ Get-PodeTask -Name Example1, Example2 The following is the structure of the Task object internally, as well as the object that is returned from [`Get-PodeTask`](../../Functions/Tasks/Get-PodeTask): -| Name | Type | Description | -| ---- | ---- | ----------- | -| Name | string | The name of the Task | -| Script | scriptblock | The scriptblock of the Task | -| Arguments | hashtable | The arguments supplied from ArgumentList | +| Name | Type | Description | +| --------- | ----------- | ---------------------------------------- | +| Name | string | The name of the Task | +| Script | scriptblock | The scriptblock of the Task | +| Arguments | hashtable | The arguments supplied from ArgumentList | diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index c250afe73..8fe33f3f0 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -211,7 +211,7 @@ viewsFolderNameAlreadyExistsExceptionMessage = 'Der Name des Ansichtsordners existiert bereits: {0}' noNameForWebSocketResetExceptionMessage = 'Kein Name für das Zurücksetzen des WebSocket angegeben.' mergeDefaultAuthNotInListExceptionMessage = "Die MergeDefault-Authentifizierung '{0}' befindet sich nicht in der angegebenen Authentifizierungsliste." - descriptionRequiredExceptionMessage = 'Eine Beschreibung ist erforderlich.' + descriptionRequiredExceptionMessage = 'Eine Beschreibung ist erforderlich für Pfad:{0} Antwort:{1}' pageNameShouldBeAlphaNumericExceptionMessage = 'Der Seitenname sollte einen gültigen alphanumerischen Wert haben: {0}' defaultValueNotBooleanOrEnumExceptionMessage = 'Der Standardwert ist kein Boolean und gehört nicht zum Enum.' openApiComponentSchemaDoesNotExistExceptionMessage = 'Das OpenApi-Komponentenschema {0} existiert nicht.' diff --git a/src/Private/Context.ps1 b/src/Private/Context.ps1 index 7667d73c0..28584fa42 100644 --- a/src/Private/Context.ps1 +++ b/src/Private/Context.ps1 @@ -526,16 +526,11 @@ function New-PodeRunspacePool { # setup main runspace pool $threadsCounts = @{ Default = 3 - # Timer = 1 Log = 1 Schedule = 1 Misc = 1 } - # if (!(Test-PodeTimersExist)) { - # $threadsCounts.Timer = 0 - # } - if (!(Test-PodeSchedulesExist)) { $threadsCounts.Schedule = 0 } diff --git a/src/Private/Tasks.ps1 b/src/Private/Tasks.ps1 index ae1f778cb..db596544e 100644 --- a/src/Private/Tasks.ps1 +++ b/src/Private/Tasks.ps1 @@ -169,7 +169,7 @@ function Get-PodeTaskScriptBlock { # build the script arguments $TaskEvent = @{ Lockable = $PodeContext.Threading.Lockables.Global - Sender = $Task + Sender = $task Timestamp = [DateTime]::UtcNow Metadata = @{} } From 87e25d5dd693c1404991f62196131553f88c94f8 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sun, 15 Sep 2024 15:06:56 -0700 Subject: [PATCH 155/177] Update Utilities.ps1 --- src/Public/Utilities.ps1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Public/Utilities.ps1 b/src/Public/Utilities.ps1 index 49add0153..20ff6343c 100644 --- a/src/Public/Utilities.ps1 +++ b/src/Public/Utilities.ps1 @@ -1465,8 +1465,6 @@ function ConvertFrom-PodeXml { } return $oHash } - - return $oHash } <# From fc482a997b1478db12513d483fc8d4a52589eafd Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sun, 15 Sep 2024 15:48:53 -0700 Subject: [PATCH 156/177] Update Schedules.ps1 --- src/Private/Schedules.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Private/Schedules.ps1 b/src/Private/Schedules.ps1 index 10d45e5f6..9bd59fb53 100644 --- a/src/Private/Schedules.ps1 +++ b/src/Private/Schedules.ps1 @@ -12,7 +12,6 @@ function Find-PodeSchedule { function Test-PodeSchedulesExist { return (($null -ne $PodeContext.Schedules) -and (($PodeContext.Schedules.Enabled) -or ($PodeContext.Schedules.Items.Count -gt 0))) } - function Start-PodeScheduleRunspace { if (!(Test-PodeSchedulesExist)) { return @@ -51,11 +50,12 @@ function Start-PodeScheduleRunspace { } $script = { - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name 'Scheduler_Trigger' + try { + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name 'Scheduler_Trigger' - # select the schedules that trigger on-start - $_now = [DateTime]::Now + # select the schedules that trigger on-start + $_now = [DateTime]::Now $PodeContext.Schedules.Items.Values | Where-Object { From a7d8f315a8d9cf4414652ab8a5c8881417f89938 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Mon, 16 Sep 2024 10:17:28 -0700 Subject: [PATCH 157/177] add support for automatically naming tasks, schedules and timers --- docs/Getting-Started/Debug.md | 21 +- src/Private/Helpers.ps1 | 289 +-------------------------- src/Private/Runspaces.ps1 | 352 +++++++++++++++++++++++++++++++++ src/Private/Schedules.ps1 | 2 - src/Private/Tasks.ps1 | 2 - src/Public/Runspaces.ps1 | 57 ++++++ src/Public/Schedules.ps1 | 48 +++-- src/Public/Tasks.ps1 | 34 ++-- src/Public/Timers.ps1 | 42 ++-- src/Public/Utilities.ps1 | 56 ------ tests/unit/Schedules.Tests.ps1 | 14 +- tests/unit/Timers.Tests.ps1 | 10 +- 12 files changed, 518 insertions(+), 409 deletions(-) create mode 100644 src/Private/Runspaces.ps1 create mode 100644 src/Public/Runspaces.ps1 diff --git a/docs/Getting-Started/Debug.md b/docs/Getting-Started/Debug.md index fbf8a1d27..057ad4a2f 100644 --- a/docs/Getting-Started/Debug.md +++ b/docs/Getting-Started/Debug.md @@ -185,22 +185,33 @@ In Pode, internal runspaces are automatically assigned distinct names. This nami ### Customizing Runspace Names -To provide clarity and better manageability, you can set custom names for runspaces within your Pode tasks or schedules. This can be achieved using the `Set-PodeCurrentRunspaceName` cmdlet. By assigning meaningful names to your runspaces, you can easily identify and work with them, especially during debugging or performance monitoring. +By default, Pode’s Tasks, Schedules, and Timers use their own names to label their associated runspaces, making it easier to identify them during debugging and monitoring. + +However, if you wish to use a different name for the runspace, you can invoke `Add-PodeTask`, `Add-PodeSchedule`, or `Add-PodeTimer` with the `-DisableRunspaceNaming` parameter. +Then, within the script block, you can use the Set-PodeCurrentRunspaceName cmdlet to assign any custom name you prefer. Another useful cmdlet is `Get-PodeCurrentRunspaceName`, which retrieves the current runspace's name. This can be helpful if you need to log or display the runspace name dynamically. ### Example -Here is an example demonstrating how to set a custom name for a runspace in a Pode task: +Here is an updated example demonstrating how to set a custom runspace name in a Pode task: ```powershell -Add-PodeTask -Name 'Test2' -ScriptBlock { +Add-PodeTask -Name 'Test2' -DisableRunspaceNaming -ScriptBlock { param($value) # Set a custom name for the current runspace - Set-PodeCurrentRunspaceName -Name 'Test2' + Set-PodeCurrentRunspaceName -Name 'My Fancy Runspace' Start-Sleep -Seconds 10 "A $($value) is never late, it arrives exactly when it means to" | Out-Default } ``` -In this example, the `Set-PodeCurrentRunspaceName` cmdlet is used to assign the name 'Test2' to the runspace executing the task. This makes it easier to identify the runspace in logs or during debugging sessions. +In this example, the `Set-PodeCurrentRunspaceName` cmdlet is used to assign the custom name 'My Fancy Runspace' to the runspace executing the task, enhancing identification during debugging or in logs. + +### Retrieving Runspace Names + +Another useful cmdlet is `Get-PodeCurrentRunspaceName`, which retrieves the current runspace's name. This cmdlet can be particularly helpful if you need to log or display the runspace name dynamically during execution. It allows you to track and manage runspaces effectively, especially in complex scenarios where multiple runspaces are running concurrently. + +```powershell + Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-PodeHost "Runspace name: $(Get-PodeCurrentRunspaceName)" } + ``` \ No newline at end of file diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index 92eaa286a..ff45ce5a1 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -550,237 +550,7 @@ function Get-PodeSubnetRange { 'IP' = ($ip_parts -join '.') } } - -function Add-PodeRunspace { - param( - [Parameter(Mandatory = $true)] - [ValidateSet('Main', 'Signals', 'Schedules', 'Gui', 'Web', 'Smtp', 'Tcp', 'Tasks', 'WebSockets', 'Files', 'Timers')] - [string] - $Type, - - [Parameter(Mandatory = $true)] - [ValidateNotNull()] - [scriptblock] - $ScriptBlock, - - [Parameter()] - $Parameters, - - [Parameter()] - [System.Management.Automation.PSDataCollection[psobject]] - $OutputStream = $null, - - [switch] - $Forget, - - [switch] - $NoProfile, - - [switch] - $PassThru - ) - - try { - # create powershell pipelines - $ps = [powershell]::Create() - $ps.RunspacePool = $PodeContext.RunspacePools[$Type].Pool - - # load modules/drives - if (!$NoProfile) { - $null = $ps.AddScript("Open-PodeRunspace -Type '$($Type)'") - } - - # load main script - $null = $ps.AddScript($ScriptBlock) - - # load parameters - if (!(Test-PodeIsEmpty $Parameters)) { - $Parameters.Keys | ForEach-Object { - $null = $ps.AddParameter($_, $Parameters[$_]) - } - } - - # start the pipeline - if ($null -eq $OutputStream) { - $pipeline = $ps.BeginInvoke() - } - else { - $pipeline = $ps.BeginInvoke($OutputStream, $OutputStream) - } - - # do we need to remember this pipeline? sorry, what did you say? - if ($Forget) { - $null = $pipeline - } - - # or do we need to return it for custom processing? ie: tasks - elseif ($PassThru) { - return @{ - Pipeline = $ps - Handler = $pipeline - } - } - - # or store it here for later clean-up - else { - $PodeContext.Runspaces += @{ - Pool = $Type - Pipeline = $ps - Handler = $pipeline - Stopped = $false - } - } - } - catch { - $_ | Write-PodeErrorLog - throw $_.Exception - } -} - -<# -.SYNOPSIS - Closes and disposes of the Pode runspaces, listeners, receivers, watchers, and optionally runspace pools. - -.DESCRIPTION - This function checks and waits for all Listeners, Receivers, and Watchers to be disposed of - before proceeding to close and dispose of the runspaces and optionally the runspace pools. - It ensures a clean shutdown by managing the disposal of resources in a specified order. - The function handles serverless and regular server environments differently, skipping - disposal actions in serverless contexts. - -.PARAMETER ClosePool - Specifies whether to close and dispose of the runspace pools along with the runspaces. - This is optional and should be specified if the pools need to be explicitly closed. - -.EXAMPLE - Close-PodeRunspace -ClosePool - This example closes all runspaces and their associated pools, ensuring that all resources are properly disposed of. - -.OUTPUTS - None - Outputs from this function are primarily internal state changes and verbose logging. - -.NOTES - It is recommended to use verbose logging to monitor the steps and understand the closing sequence during execution. -#> -function Close-PodeRunspace { - param( - [switch] - $ClosePool - ) - - # Early return if server is serverless, as disposal is not required. - if ($PodeContext.Server.IsServerless) { - return - } - - try { - # Only proceed if there are runspaces to dispose of. - if (!(Test-PodeIsEmpty $PodeContext.Runspaces)) { - Write-Verbose 'Waiting until all Listeners are disposed' - - $count = 0 - $continue = $false - # Attempts to dispose of resources for up to 10 seconds. - while ($count -le 10) { - Start-Sleep -Seconds 1 - $count++ - - $continue = $false - # Check each listener, receiver, and watcher; if any are not disposed, continue waiting. - foreach ($listener in $PodeContext.Listeners) { - if (!$listener.IsDisposed) { - $continue = $true - break - } - } - - foreach ($receiver in $PodeContext.Receivers) { - if (!$receiver.IsDisposed) { - $continue = $true - break - } - } - - foreach ($watcher in $PodeContext.Watchers) { - if (!$watcher.IsDisposed) { - $continue = $true - break - } - } - # If undisposed resources exist, continue waiting. - if ($continue) { - continue - } - - break - } - - Write-Verbose 'All Listeners disposed' - - # now dispose runspaces - Write-Verbose 'Disposing Runspaces' - $runspaceErrors = @(foreach ($item in $PodeContext.Runspaces) { - if ($item.Stopped) { - continue - } - - try { - # only do this, if the pool is in error - if ($PodeContext.RunspacePools[$item.Pool].State -ieq 'error') { - $item.Pipeline.EndInvoke($item.Handler) - } - } - catch { - "$($item.Pool) runspace failed to load: $($_.Exception.InnerException.Message)" - } - - Close-PodeDisposable -Disposable $item.Pipeline - $item.Stopped = $true - }) - - # dispose of schedule runspaces - if ($PodeContext.Schedules.Processes.Count -gt 0) { - foreach ($key in $PodeContext.Schedules.Processes.Keys.Clone()) { - Close-PodeScheduleInternal -Process $PodeContext.Schedules.Processes[$key] - } - } - - # dispose of task runspaces - if ($PodeContext.Tasks.Processes.Count -gt 0) { - foreach ($key in $PodeContext.Tasks.Processes.Keys.Clone()) { - Close-PodeTaskInternal -Process $PodeContext.Tasks.Processes[$key] - } - } - - $PodeContext.Runspaces = @() - Write-Verbose 'Runspaces disposed' - } - - # close/dispose the runspace pools - if ($ClosePool) { - Close-PodeRunspacePool - } - - # Check for and throw runspace errors if any occurred during disposal. - if (($null -ne $runspaceErrors) -and ($runspaceErrors.Length -gt 0)) { - foreach ($err in $runspaceErrors) { - if ($null -eq $err) { - continue - } - - throw $err - } - } - - # garbage collect - Invoke-PodeGC - } - catch { - $_ | Write-PodeErrorLog - throw $_.Exception - } -} + function Get-PodeConsoleKey { if ([Console]::IsInputRedirected -or ![Console]::KeyAvailable) { @@ -3917,63 +3687,6 @@ function ConvertTo-PodeYamlInternal { } } -<# -.SYNOPSIS - Opens a runspace for Pode server operations based on the specified type. - -.DESCRIPTION - This function initializes a runspace for Pode server tasks by importing necessary - modules, adding PowerShell drives, and setting the state of the runspace pool to 'Ready'. - If an error occurs during the initialization, the state is adjusted to 'Error' if it - was previously set to 'waiting', and the error details are outputted. - -.PARAMETER Type - The type of the runspace pool to open. This parameter only accepts predefined values, - ensuring the runspace pool corresponds to a supported server operation type. The valid - types are: Main, Signals, Schedules, Gui, Web, Smtp, Tcp, Tasks, WebSockets, Files. - -.EXAMPLE - Open-PodeRunspace -Type "Web" - - Opens a runspace for the 'Web' type, setting it ready for handling web server tasks. - -.NOTES - This function is not invoked directly but indirectly by `Add-PodeRunspace` function using - $null = $ps.AddScript("Open-PodeRunspace -Type '$($Type)'") -#> - -function Open-PodeRunspace { - param( - [Parameter(Mandatory = $true)] - [ValidateSet('Main', 'Signals', 'Schedules', 'Gui', 'Web', 'Smtp', 'Tcp', 'Tasks', 'WebSockets', 'Files')] - [string] - $Type - ) - - try { - # Importing internal Pode modules necessary for the runspace operations. - Import-PodeModulesInternal - - # Adding PowerShell drives required by the runspace. - Add-PodePSDrivesInternal - - # Setting the state of the runspace pool to 'Ready', indicating it is ready to process requests. - $PodeContext.RunspacePools[$Type].State = 'Ready' - } - catch { - # If an error occurs and the current state is 'waiting', set it to 'Error'. - if ($PodeContext.RunspacePools[$Type].State -ieq 'waiting') { - $PodeContext.RunspacePools[$Type].State = 'Error' - } - - # Outputting the error to the default output stream, including the stack trace. - $_ | Out-Default - $_.ScriptStackTrace | Out-Default - - # Rethrowing the error to be handled further up the call stack. - throw - } -} <# .SYNOPSIS diff --git a/src/Private/Runspaces.ps1 b/src/Private/Runspaces.ps1 new file mode 100644 index 000000000..1325c7e64 --- /dev/null +++ b/src/Private/Runspaces.ps1 @@ -0,0 +1,352 @@ +function Add-PodeRunspaceNameToScriptblock { + param ( + [ScriptBlock]$ScriptBlock, + [string]$Name + ) + + # Convert the scriptblock to a string + $scriptBlockString = $ScriptBlock.ToString() + if ($scriptBlockString.contains('Set-PodeCurrentRunspaceName')) { + Write-PodeHost "'Set-PodeCurrentRunspaceName' already there" + } + # Check for a param block and insert the desired line after it + $pattern = '(\s*param\s*\([^\)]*\)\s*)' #'(\{\s*|\s*)param\s*\([^\)]*\)\s*' + + # Check for a param block and insert the desired line after it + if ($scriptBlockString -match $pattern) { + # Insert Set-PodeCurrentRunspaceName after the param block + $modifiedScriptBlockString = $scriptBlockString -replace $pattern,"`${1}Set-PodeCurrentRunspaceName -Name '$Name'`n" + } + else { + # If no param block is found, add Set-PodeCurrentRunspaceName at the beginning + $modifiedScriptBlockString = "Set-PodeCurrentRunspaceName -Name `"$Name`"`n$scriptBlockString" + } + + # Convert the modified string back into a scriptblock + return [ScriptBlock]::Create($modifiedScriptBlockString) +} + +<# +.SYNOPSIS + Opens a runspace for Pode server operations based on the specified type. + +.DESCRIPTION + This function initializes a runspace for Pode server tasks by importing necessary + modules, adding PowerShell drives, and setting the state of the runspace pool to 'Ready'. + If an error occurs during the initialization, the state is adjusted to 'Error' if it + was previously set to 'waiting', and the error details are outputted. + +.PARAMETER Type + The type of the runspace pool to open. This parameter only accepts predefined values, + ensuring the runspace pool corresponds to a supported server operation type. The valid + types are: Main, Signals, Schedules, Gui, Web, Smtp, Tcp, Tasks, WebSockets, Files. + +.EXAMPLE + Open-PodeRunspace -Type "Web" + + Opens a runspace for the 'Web' type, setting it ready for handling web server tasks. + +.NOTES + This function is not invoked directly but indirectly by `Add-PodeRunspace` function using + $null = $ps.AddScript("Open-PodeRunspace -Type '$($Type)'") +#> +function Open-PodeRunspace { + param( + [Parameter(Mandatory = $true)] + [ValidateSet('Main', 'Signals', 'Schedules', 'Gui', 'Web', 'Smtp', 'Tcp', 'Tasks', 'WebSockets', 'Files')] + [string] + $Type + ) + + try { + # Importing internal Pode modules necessary for the runspace operations. + Import-PodeModulesInternal + + # Adding PowerShell drives required by the runspace. + Add-PodePSDrivesInternal + + # Setting the state of the runspace pool to 'Ready', indicating it is ready to process requests. + $PodeContext.RunspacePools[$Type].State = 'Ready' + } + catch { + # If an error occurs and the current state is 'waiting', set it to 'Error'. + if ($PodeContext.RunspacePools[$Type].State -ieq 'waiting') { + $PodeContext.RunspacePools[$Type].State = 'Error' + } + + # Outputting the error to the default output stream, including the stack trace. + $_ | Out-Default + $_.ScriptStackTrace | Out-Default + + # Rethrowing the error to be handled further up the call stack. + throw + } +} + + +<# +.SYNOPSIS + Adds a new runspace to Pode with specified type and script block. + +.DESCRIPTION + The `Add-PodeRunspace` function creates a new PowerShell runspace within Pode + based on the provided type and script block. This function allows for additional + customization through parameters, output streaming, and runspace management options. + +.PARAMETER Type + The type of runspace to create. Accepted values are: + 'Main', 'Signals', 'Schedules', 'Gui', 'Web', 'Smtp', 'Tcp', 'Tasks', + 'WebSockets', 'Files', 'Timers'. + +.PARAMETER ScriptBlock + The script block to execute within the runspace. This script block will be + added to the runspace's pipeline. + +.PARAMETER Parameters + Optional parameters to pass to the script block. + +.PARAMETER OutputStream + A PSDataCollection object to handle output streaming for the runspace. + +.PARAMETER Forget + If specified, the pipeline's output will not be stored or remembered. + +.PARAMETER NoProfile + If specified, the runspace will not load any modules or profiles. + +.PARAMETER PassThru + If specified, returns the pipeline and handler for custom processing. + +.EXAMPLE + Add-PodeRunspace -Type 'Tasks' -ScriptBlock { + # Your script code here + } +#> + +function Add-PodeRunspace { + param( + [Parameter(Mandatory = $true)] + [ValidateSet('Main', 'Signals', 'Schedules', 'Gui', 'Web', 'Smtp', 'Tcp', 'Tasks', 'WebSockets', 'Files', 'Timers')] + [string] + $Type, + + [Parameter(Mandatory = $true)] + [ValidateNotNull()] + [scriptblock] + $ScriptBlock, + + [Parameter()] + $Parameters, + + [Parameter()] + [System.Management.Automation.PSDataCollection[psobject]] + $OutputStream = $null, + + [switch] + $Forget, + + [switch] + $NoProfile, + + [switch] + $PassThru + ) + + try { + # create powershell pipelines + $ps = [powershell]::Create() + $ps.RunspacePool = $PodeContext.RunspacePools[$Type].Pool + + # load modules/drives + if (!$NoProfile) { + $null = $ps.AddScript("Open-PodeRunspace -Type '$($Type)'") + } + + # load main script + $null = $ps.AddScript($ScriptBlock) + + # load parameters + if (!(Test-PodeIsEmpty $Parameters)) { + $Parameters.Keys | ForEach-Object { + $null = $ps.AddParameter($_, $Parameters[$_]) + } + } + + # start the pipeline + if ($null -eq $OutputStream) { + $pipeline = $ps.BeginInvoke() + } + else { + $pipeline = $ps.BeginInvoke($OutputStream, $OutputStream) + } + + # do we need to remember this pipeline? sorry, what did you say? + if ($Forget) { + $null = $pipeline + } + + # or do we need to return it for custom processing? ie: tasks + elseif ($PassThru) { + return @{ + Pipeline = $ps + Handler = $pipeline + } + } + + # or store it here for later clean-up + else { + $PodeContext.Runspaces += @{ + Pool = $Type + Pipeline = $ps + Handler = $pipeline + Stopped = $false + } + } + } + catch { + $_ | Write-PodeErrorLog + throw $_.Exception + } +} + +<# +.SYNOPSIS + Closes and disposes of the Pode runspaces, listeners, receivers, watchers, and optionally runspace pools. + +.DESCRIPTION + This function checks and waits for all Listeners, Receivers, and Watchers to be disposed of + before proceeding to close and dispose of the runspaces and optionally the runspace pools. + It ensures a clean shutdown by managing the disposal of resources in a specified order. + The function handles serverless and regular server environments differently, skipping + disposal actions in serverless contexts. + +.PARAMETER ClosePool + Specifies whether to close and dispose of the runspace pools along with the runspaces. + This is optional and should be specified if the pools need to be explicitly closed. + +.EXAMPLE + Close-PodeRunspace -ClosePool + This example closes all runspaces and their associated pools, ensuring that all resources are properly disposed of. + +.OUTPUTS + None + Outputs from this function are primarily internal state changes and verbose logging. +#> +function Close-PodeRunspace { + param( + [switch] + $ClosePool + ) + + # Early return if server is serverless, as disposal is not required. + if ($PodeContext.Server.IsServerless) { + return + } + + try { + # Only proceed if there are runspaces to dispose of. + if (!(Test-PodeIsEmpty $PodeContext.Runspaces)) { + Write-Verbose 'Waiting until all Listeners are disposed' + + $count = 0 + $continue = $false + # Attempts to dispose of resources for up to 10 seconds. + while ($count -le 10) { + Start-Sleep -Seconds 1 + $count++ + + $continue = $false + # Check each listener, receiver, and watcher; if any are not disposed, continue waiting. + foreach ($listener in $PodeContext.Listeners) { + if (!$listener.IsDisposed) { + $continue = $true + break + } + } + + foreach ($receiver in $PodeContext.Receivers) { + if (!$receiver.IsDisposed) { + $continue = $true + break + } + } + + foreach ($watcher in $PodeContext.Watchers) { + if (!$watcher.IsDisposed) { + $continue = $true + break + } + } + # If undisposed resources exist, continue waiting. + if ($continue) { + continue + } + + break + } + + Write-Verbose 'All Listeners disposed' + + # now dispose runspaces + Write-Verbose 'Disposing Runspaces' + $runspaceErrors = @(foreach ($item in $PodeContext.Runspaces) { + if ($item.Stopped) { + continue + } + + try { + # only do this, if the pool is in error + if ($PodeContext.RunspacePools[$item.Pool].State -ieq 'error') { + $item.Pipeline.EndInvoke($item.Handler) + } + } + catch { + "$($item.Pool) runspace failed to load: $($_.Exception.InnerException.Message)" + } + + Close-PodeDisposable -Disposable $item.Pipeline + $item.Stopped = $true + }) + + # dispose of schedule runspaces + if ($PodeContext.Schedules.Processes.Count -gt 0) { + foreach ($key in $PodeContext.Schedules.Processes.Keys.Clone()) { + Close-PodeScheduleInternal -Process $PodeContext.Schedules.Processes[$key] + } + } + + # dispose of task runspaces + if ($PodeContext.Tasks.Processes.Count -gt 0) { + foreach ($key in $PodeContext.Tasks.Processes.Keys.Clone()) { + Close-PodeTaskInternal -Process $PodeContext.Tasks.Processes[$key] + } + } + + $PodeContext.Runspaces = @() + Write-Verbose 'Runspaces disposed' + } + + # close/dispose the runspace pools + if ($ClosePool) { + Close-PodeRunspacePool + } + + # Check for and throw runspace errors if any occurred during disposal. + if (($null -ne $runspaceErrors) -and ($runspaceErrors.Length -gt 0)) { + foreach ($err in $runspaceErrors) { + if ($null -eq $err) { + continue + } + + throw $err + } + } + + # garbage collect + Invoke-PodeGC + } + catch { + $_ | Write-PodeErrorLog + throw $_.Exception + } +} \ No newline at end of file diff --git a/src/Private/Schedules.ps1 b/src/Private/Schedules.ps1 index 9bd59fb53..96f1db151 100644 --- a/src/Private/Schedules.ps1 +++ b/src/Private/Schedules.ps1 @@ -19,8 +19,6 @@ function Start-PodeScheduleRunspace { Add-PodeTimer -Name '__pode_schedule_housekeeper__' -Interval 30 -ScriptBlock { try { - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name '__pode_schedule_housekeeper__' if ($PodeContext.Schedules.Processes.Count -eq 0) { return diff --git a/src/Private/Tasks.ps1 b/src/Private/Tasks.ps1 index 6d2bd6b35..db596544e 100644 --- a/src/Private/Tasks.ps1 +++ b/src/Private/Tasks.ps1 @@ -12,8 +12,6 @@ function Start-PodeTaskHousekeeper { if ($PodeContext.Tasks.Processes.Count -eq 0) { return } - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name '__pode_task_housekeeper__' $now = [datetime]::UtcNow diff --git a/src/Public/Runspaces.ps1 b/src/Public/Runspaces.ps1 new file mode 100644 index 000000000..5b83b6089 --- /dev/null +++ b/src/Public/Runspaces.ps1 @@ -0,0 +1,57 @@ +<# +.SYNOPSIS + Sets the name of the current runspace. + +.DESCRIPTION + The Set-PodeCurrentRunspaceName function assigns a specified name to the current runspace. + This can be useful for identifying and managing the runspace in scripts and during debugging. + +.PARAMETER Name + The name to assign to the current runspace. This parameter is mandatory. + +.EXAMPLE + Set-PodeCurrentRunspaceName -Name "MyRunspace" + This command sets the name of the current runspace to "MyRunspace". + +.NOTES + This is an internal function and may change in future releases of Pode. +#> + +function Set-PodeCurrentRunspaceName { + param ( + [Parameter(Mandatory = $true)] + [string] + $Name + ) + + # Get the current runspace + $currentRunspace = [System.Management.Automation.Runspaces.Runspace]::DefaultRunspace + # Set the name of the current runspace if the name is not already set + if ( $currentRunspace.Name -ne $Name) { + # Set the name of the current runspace + $currentRunspace.Name = $Name + } +} + +<# +.SYNOPSIS + Retrieves the name of the current PowerShell runspace. + +.DESCRIPTION + The Get-PodeCurrentRunspaceName function retrieves the name of the current PowerShell runspace. + This can be useful for debugging or logging purposes to identify the runspace in use. + +.EXAMPLE + Get-PodeCurrentRunspaceName + Returns the name of the current runspace. + +.NOTES + This is an internal function and may change in future releases of Pode. +#> +function Get-PodeCurrentRunspaceName { + # Get the current runspace + $currentRunspace = [System.Management.Automation.Runspaces.Runspace]::DefaultRunspace + + # Get the name of the current runspace + return $currentRunspace.Name +} diff --git a/src/Public/Schedules.ps1 b/src/Public/Schedules.ps1 index 8fb460d33..f1f21d0e8 100644 --- a/src/Public/Schedules.ps1 +++ b/src/Public/Schedules.ps1 @@ -1,54 +1,57 @@ <# .SYNOPSIS -Adds a new Schedule with logic to periodically invoke, defined using Cron Expressions. + Adds a new Schedule with logic to periodically invoke, defined using Cron Expressions. .DESCRIPTION -Adds a new Schedule with logic to periodically invoke, defined using Cron Expressions. + Adds a new Schedule with logic to periodically invoke, defined using Cron Expressions. .PARAMETER Name -The Name of the Schedule. + The Name of the Schedule. .PARAMETER Cron -One, or an Array, of Cron Expressions to define when the Schedule should trigger. + One, or an Array, of Cron Expressions to define when the Schedule should trigger. .PARAMETER ScriptBlock -The script defining the Schedule's logic. + The script defining the Schedule's logic. .PARAMETER Limit -The number of times the Schedule should trigger before being removed. + The number of times the Schedule should trigger before being removed. .PARAMETER StartTime -A DateTime for when the Schedule should start triggering. + A DateTime for when the Schedule should start triggering. .PARAMETER EndTime -A DateTime for when the Schedule should stop triggering, and be removed. + A DateTime for when the Schedule should stop triggering, and be removed. .PARAMETER ArgumentList -A hashtable of arguments to supply to the Schedule's ScriptBlock. + A hashtable of arguments to supply to the Schedule's ScriptBlock. .PARAMETER Timeout -An optional timeout, in seconds, for the Schedule's logic. (Default: -1 [never timeout]) + An optional timeout, in seconds, for the Schedule's logic. (Default: -1 [never timeout]) .PARAMETER TimeoutFrom -An optional timeout from either 'Create' or 'Start'. (Default: 'Create') + An optional timeout from either 'Create' or 'Start'. (Default: 'Create') .PARAMETER FilePath -A literal, or relative, path to a file containing a ScriptBlock for the Schedule's logic. + A literal, or relative, path to a file containing a ScriptBlock for the Schedule's logic. .PARAMETER OnStart -If supplied, the schedule will trigger when the server starts, regardless if the cron-expression matches the current time. + If supplied, the schedule will trigger when the server starts, regardless if the cron-expression matches the current time. + +.PARAMETER DisableRunspaceNaming + If supplied, the runspace name will not be set for the Schedule's ScriptBlock. .EXAMPLE -Add-PodeSchedule -Name 'RunEveryMinute' -Cron '@minutely' -ScriptBlock { /* logic */ } + Add-PodeSchedule -Name 'RunEveryMinute' -Cron '@minutely' -ScriptBlock { /* logic */ } .EXAMPLE -Add-PodeSchedule -Name 'RunEveryTuesday' -Cron '0 0 * * TUE' -ScriptBlock { /* logic */ } + Add-PodeSchedule -Name 'RunEveryTuesday' -Cron '0 0 * * TUE' -ScriptBlock { /* logic */ } .EXAMPLE -Add-PodeSchedule -Name 'StartAfter2days' -Cron '@hourly' -StartTime [DateTime]::Now.AddDays(2) -ScriptBlock { /* logic */ } + Add-PodeSchedule -Name 'StartAfter2days' -Cron '@hourly' -StartTime [DateTime]::Now.AddDays(2) -ScriptBlock { /* logic */ } .EXAMPLE -Add-PodeSchedule -Name 'Args' -Cron '@minutely' -ScriptBlock { /* logic */ } -ArgumentList @{ Arg1 = 'value' } + Add-PodeSchedule -Name 'Args' -Cron '@minutely' -ScriptBlock { /* logic */ } -ArgumentList @{ Arg1 = 'value' } #> function Add-PodeSchedule { [CmdletBinding(DefaultParameterSetName = 'Script')] @@ -95,7 +98,10 @@ function Add-PodeSchedule { $TimeoutFrom = 'Create', [switch] - $OnStart + $OnStart, + + [switch] + $DisableRunspaceNaming ) # error if serverless @@ -129,6 +135,12 @@ function Add-PodeSchedule { $ScriptBlock = Convert-PodeFileToScriptBlock -FilePath $FilePath } + # Check if the runspace naming feature is not disabled + if (! $DisableRunspaceNaming) { + # Set the runspace name by adding the specified name to the ScriptBlock + $ScriptBlock = Add-PodeRunspaceNameToScriptblock -ScriptBlock $ScriptBlock -Name $Name + } + # check for scoped vars $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState diff --git a/src/Public/Tasks.ps1 b/src/Public/Tasks.ps1 index 02e45bce3..b5df4cc1e 100644 --- a/src/Public/Tasks.ps1 +++ b/src/Public/Tasks.ps1 @@ -1,33 +1,36 @@ <# .SYNOPSIS -Adds a new Task. + Adds a new Task. .DESCRIPTION -Adds a new Task, which can be asynchronously or synchronously invoked. + Adds a new Task, which can be asynchronously or synchronously invoked. .PARAMETER Name -The Name of the Task. + The Name of the Task. .PARAMETER ScriptBlock -The script for the Task. + The script for the Task. .PARAMETER FilePath -A literal, or relative, path to a file containing a ScriptBlock for the Task's logic. + A literal, or relative, path to a file containing a ScriptBlock for the Task's logic. .PARAMETER ArgumentList -A hashtable of arguments to supply to the Task's ScriptBlock. + A hashtable of arguments to supply to the Task's ScriptBlock. .PARAMETER Timeout -A Timeout, in seconds, to abort running the Task process. (Default: -1 [never timeout]) + A Timeout, in seconds, to abort running the Task process. (Default: -1 [never timeout]) .PARAMETER TimeoutFrom -Where to start the Timeout from, either 'Create', 'Start'. (Default: 'Create') + Where to start the Timeout from, either 'Create', 'Start'. (Default: 'Create') + +.PARAMETER DisableRunspaceNaming + If supplied, the runspace name will not be set for the Schedule's ScriptBlock. .EXAMPLE -Add-PodeTask -Name 'Example1' -ScriptBlock { Invoke-SomeLogic } + Add-PodeTask -Name 'Example1' -ScriptBlock { Invoke-SomeLogic } .EXAMPLE -Add-PodeTask -Name 'Example1' -ScriptBlock { return Get-SomeObject } + Add-PodeTask -Name 'Example1' -ScriptBlock { return Get-SomeObject } #> function Add-PodeTask { [CmdletBinding(DefaultParameterSetName = 'Script')] @@ -55,7 +58,10 @@ function Add-PodeTask { [Parameter()] [ValidateSet('Create', 'Start')] [string] - $TimeoutFrom = 'Create' + $TimeoutFrom = 'Create', + + [switch] + $DisableRunspaceNaming ) # ensure the task doesn't already exist if ($PodeContext.Tasks.Items.ContainsKey($Name)) { @@ -68,6 +74,12 @@ function Add-PodeTask { $ScriptBlock = Convert-PodeFileToScriptBlock -FilePath $FilePath } + # Check if the runspace naming feature is not disabled + if (! $DisableRunspaceNaming) { + # Set the runspace name by adding the specified name to the ScriptBlock + $ScriptBlock = Add-PodeRunspaceNameToScriptblock -ScriptBlock $ScriptBlock -Name $Name + } + # check for scoped vars $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState diff --git a/src/Public/Timers.ps1 b/src/Public/Timers.ps1 index 548f9db9b..bfd5d8caa 100644 --- a/src/Public/Timers.ps1 +++ b/src/Public/Timers.ps1 @@ -1,45 +1,48 @@ <# .SYNOPSIS -Adds a new Timer with logic to periodically invoke. + Adds a new Timer with logic to periodically invoke. .DESCRIPTION -Adds a new Timer with logic to periodically invoke, with options to only run a specific number of times. + Adds a new Timer with logic to periodically invoke, with options to only run a specific number of times. .PARAMETER Name -The Name of the Timer. + The Name of the Timer. .PARAMETER Interval -The number of seconds to periodically invoke the Timer's ScriptBlock. + The number of seconds to periodically invoke the Timer's ScriptBlock. .PARAMETER ScriptBlock -The script for the Timer. + The script for the Timer. .PARAMETER Limit -The number of times the Timer should be invoked before being removed. (If 0, it will run indefinitely) + The number of times the Timer should be invoked before being removed. (If 0, it will run indefinitely) .PARAMETER Skip -The number of "invokes" to skip before the Timer actually runs. + The number of "invokes" to skip before the Timer actually runs. .PARAMETER ArgumentList -An array of arguments to supply to the Timer's ScriptBlock. + An array of arguments to supply to the Timer's ScriptBlock. .PARAMETER FilePath -A literal, or relative, path to a file containing a ScriptBlock for the Timer's logic. + A literal, or relative, path to a file containing a ScriptBlock for the Timer's logic. .PARAMETER OnStart -If supplied, the timer will trigger when the server starts. + If supplied, the timer will trigger when the server starts. + +.PARAMETER DisableRunspaceNaming + If supplied, the runspace name will not be set for the Schedule's ScriptBlock. .EXAMPLE -Add-PodeTimer -Name 'Hello' -Interval 10 -ScriptBlock { 'Hello, world!' | Out-Default } + Add-PodeTimer -Name 'Hello' -Interval 10 -ScriptBlock { 'Hello, world!' | Out-Default } .EXAMPLE -Add-PodeTimer -Name 'RunOnce' -Interval 1 -Limit 1 -ScriptBlock { /* logic */ } + Add-PodeTimer -Name 'RunOnce' -Interval 1 -Limit 1 -ScriptBlock { /* logic */ } .EXAMPLE -Add-PodeTimer -Name 'RunAfter60secs' -Interval 10 -Skip 6 -ScriptBlock { /* logic */ } + Add-PodeTimer -Name 'RunAfter60secs' -Interval 10 -Skip 6 -ScriptBlock { /* logic */ } .EXAMPLE -Add-PodeTimer -Name 'Args' -Interval 2 -ScriptBlock { /* logic */ } -ArgumentList 'arg1', 'arg2' + Add-PodeTimer -Name 'Args' -Interval 2 -ScriptBlock { /* logic */ } -ArgumentList 'arg1', 'arg2' #> function Add-PodeTimer { [CmdletBinding(DefaultParameterSetName = 'Script')] @@ -73,7 +76,10 @@ function Add-PodeTimer { $ArgumentList, [switch] - $OnStart + $OnStart, + + [switch] + $DisableRunspaceNaming ) # error if serverless @@ -108,6 +114,12 @@ function Add-PodeTimer { $ScriptBlock = Convert-PodeFileToScriptBlock -FilePath $FilePath } + # Check if the runspace naming feature is not disabled + if (! $DisableRunspaceNaming) { + # Set the runspace name by adding the specified name to the ScriptBlock + $ScriptBlock = Add-PodeRunspaceNameToScriptblock -ScriptBlock $ScriptBlock -Name $Name + } + # check for scoped vars $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState diff --git a/src/Public/Utilities.ps1 b/src/Public/Utilities.ps1 index d98d3fe1f..c00b26eba 100644 --- a/src/Public/Utilities.ps1 +++ b/src/Public/Utilities.ps1 @@ -1382,59 +1382,3 @@ function Invoke-PodeGC { [System.GC]::Collect() } - -<# -.SYNOPSIS - Sets the name of the current runspace. - -.DESCRIPTION - The Set-PodeCurrentRunspaceName function assigns a specified name to the current runspace. - This can be useful for identifying and managing the runspace in scripts and during debugging. - -.PARAMETER Name - The name to assign to the current runspace. This parameter is mandatory. - -.EXAMPLE - Set-PodeCurrentRunspaceName -Name "MyRunspace" - This command sets the name of the current runspace to "MyRunspace". - -.NOTES - This is an internal function and may change in future releases of Pode. -#> - -function Set-PodeCurrentRunspaceName { - param ( - [Parameter(Mandatory = $true)] - [string] - $Name - ) - - # Get the current runspace - $currentRunspace = [System.Management.Automation.Runspaces.Runspace]::DefaultRunspace - - # Set the name of the current runspace - $currentRunspace.Name = $Name -} - -<# -.SYNOPSIS - Retrieves the name of the current PowerShell runspace. - -.DESCRIPTION - The Get-PodeCurrentRunspaceName function retrieves the name of the current PowerShell runspace. - This can be useful for debugging or logging purposes to identify the runspace in use. - -.EXAMPLE - Get-PodeCurrentRunspaceName - Returns the name of the current runspace. - -.NOTES - This is an internal function and may change in future releases of Pode. -#> -function Get-PodeCurrentRunspaceName { - # Get the current runspace - $currentRunspace = [System.Management.Automation.Runspaces.Runspace]::DefaultRunspace - - # Get the name of the current runspace - return $currentRunspace.Name -} diff --git a/tests/unit/Schedules.Tests.ps1 b/tests/unit/Schedules.Tests.ps1 index ce426bbe0..3f3182fe2 100644 --- a/tests/unit/Schedules.Tests.ps1 +++ b/tests/unit/Schedules.Tests.ps1 @@ -65,7 +65,7 @@ Describe 'Add-PodeSchedule' { $start = ([DateTime]::Now.AddHours(3)) $end = ([DateTime]::Now.AddHours(5)) - Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } -StartTime $start -EndTime $end + Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } -StartTime $start -EndTime $end -DisableRunspaceNaming $schedule = $PodeContext.Schedules.Items['test'] $schedule | Should -Not -Be $null @@ -81,7 +81,7 @@ Describe 'Add-PodeSchedule' { $PodeContext = @{ 'Schedules' = @{ Items = @{} }; } $end = ([DateTime]::Now.AddHours(5)) - Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } -EndTime $end + Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } -EndTime $end -DisableRunspaceNaming $schedule = $PodeContext.Schedules.Items['test'] $schedule | Should -Not -Be $null @@ -97,7 +97,7 @@ Describe 'Add-PodeSchedule' { $PodeContext = @{ 'Schedules' = @{ Items = @{} }; } $start = ([DateTime]::Now.AddHours(3)) - Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } -StartTime $start + Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } -StartTime $start -DisableRunspaceNaming $schedule = $PodeContext.Schedules.Items['test'] $schedule | Should -Not -Be $null @@ -112,7 +112,7 @@ Describe 'Add-PodeSchedule' { It 'Adds new schedule with just a cron' { $PodeContext = @{ 'Schedules' = @{ Items = @{} }; } - Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } + Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } -DisableRunspaceNaming $schedule = $PodeContext.Schedules.Items['test'] $schedule | Should -Not -Be $null @@ -129,7 +129,7 @@ Describe 'Add-PodeSchedule' { $start = ([DateTime]::Now.AddHours(3)) $end = ([DateTime]::Now.AddHours(5)) - Add-PodeSchedule -Name 'test' -Cron @('@minutely', '@hourly') -ScriptBlock { Write-Host 'hello' } -StartTime $start -EndTime $end + Add-PodeSchedule -Name 'test' -Cron @('@minutely', '@hourly') -ScriptBlock { Write-Host 'hello' } -StartTime $start -EndTime $end -DisableRunspaceNaming $schedule = $PodeContext.Schedules.Items['test'] $schedule | Should -Not -Be $null @@ -318,7 +318,7 @@ Describe 'Clear-PodeSchedules' { Describe 'Edit-PodeSchedule' { It 'Adds a new schedule, then edits the cron' { $PodeContext = @{ 'Schedules' = @{ Items = @{} }; } - Add-PodeSchedule -Name 'test1' -Cron '@hourly' -ScriptBlock { Write-Host 'hello1' } + Add-PodeSchedule -Name 'test1' -Cron '@hourly' -ScriptBlock { Write-Host 'hello1' } -DisableRunspaceNaming $PodeContext.Schedules.Items['test1'].Crons.Length | Should -Be 1 $PodeContext.Schedules.Items['test1'].Script.ToString() | Should -Be ({ Write-Host 'hello1' }).ToString() @@ -329,7 +329,7 @@ Describe 'Edit-PodeSchedule' { It 'Adds a new schedule, then edits the script' { $PodeContext = @{ 'Schedules' = @{ Items = @{} }; } - Add-PodeSchedule -Name 'test1' -Cron '@hourly' -ScriptBlock { Write-Host 'hello1' } + Add-PodeSchedule -Name 'test1' -Cron '@hourly' -ScriptBlock { Write-Host 'hello1' } -DisableRunspaceNaming $PodeContext.Schedules.Items['test1'].Crons.Length | Should -Be 1 $PodeContext.Schedules.Items['test1'].Script.ToString() | Should -Be ({ Write-Host 'hello1' }).ToString() diff --git a/tests/unit/Timers.Tests.ps1 b/tests/unit/Timers.Tests.ps1 index 8ea420d62..e37dc8890 100644 --- a/tests/unit/Timers.Tests.ps1 +++ b/tests/unit/Timers.Tests.ps1 @@ -71,7 +71,7 @@ Describe 'Add-PodeTimer' { It 'Adds new timer to session with no limit' { $PodeContext = @{ 'Timers' = @{ Items = @{} }; } - Add-PodeTimer -Name 'test' -Interval 1 -ScriptBlock { Write-Host 'hello' } -Limit 0 -Skip 1 + Add-PodeTimer -Name 'test' -Interval 1 -ScriptBlock { Write-Host 'hello' } -Limit 0 -Skip 1 -DisableRunspaceNaming $timer = $PodeContext.Timers.Items['test'] $timer | Should -Not -Be $null @@ -87,7 +87,7 @@ Describe 'Add-PodeTimer' { It 'Adds new timer to session with limit' { $PodeContext = @{ 'Timers' = @{ Items = @{} }; } - Add-PodeTimer -Name 'test' -Interval 3 -ScriptBlock { Write-Host 'hello' } -Limit 2 -Skip 1 + Add-PodeTimer -Name 'test' -Interval 3 -ScriptBlock { Write-Host 'hello' } -Limit 2 -Skip 1 -DisableRunspaceNaming $timer = $PodeContext.Timers.Items['test'] $timer | Should -Not -Be $null @@ -148,7 +148,7 @@ Describe 'Get-PodeTimer' { Describe 'Remove-PodeTimer' { It 'Adds new timer and then removes it' { $PodeContext = @{ 'Timers' = @{ Items = @{} }; } - Add-PodeTimer -Name 'test' -Interval 1 -ScriptBlock { Write-Host 'hello' } + Add-PodeTimer -Name 'test' -Interval 1 -ScriptBlock { Write-Host 'hello' } -DisableRunspaceNaming $timer = $PodeContext.Timers.Items['test'] $timer.Name | Should -Be 'test' @@ -178,7 +178,7 @@ Describe 'Clear-PodeTimers' { Describe 'Edit-PodeTimer' { It 'Adds a new timer, then edits the interval' { $PodeContext = @{ 'Timers' = @{ Items = @{} }; } - Add-PodeTimer -Name 'test1' -Interval 1 -ScriptBlock { Write-Host 'hello1' } + Add-PodeTimer -Name 'test1' -Interval 1 -ScriptBlock { Write-Host 'hello1' } -DisableRunspaceNaming $PodeContext.Timers.Items['test1'].Interval | Should -Be 1 $PodeContext.Timers.Items['test1'].Script.ToString() | Should -Be ({ Write-Host 'hello1' }).ToString() @@ -189,7 +189,7 @@ Describe 'Edit-PodeTimer' { It 'Adds a new timer, then edits the script' { $PodeContext = @{ 'Timers' = @{ Items = @{} }; } - Add-PodeTimer -Name 'test1' -Interval 1 -ScriptBlock { Write-Host 'hello1' } + Add-PodeTimer -Name 'test1' -Interval 1 -ScriptBlock { Write-Host 'hello1' } -DisableRunspaceNaming $PodeContext.Timers.Items['test1'].Interval | Should -Be 1 $PodeContext.Timers.Items['test1'].Script.ToString() | Should -Be ({ Write-Host 'hello1' }).ToString() From b690b60df9ebf934c3e6a91dbed78a8bd0da26e4 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Thu, 19 Sep 2024 07:49:19 -0700 Subject: [PATCH 158/177] Matthew suggestions --- docs/Getting-Started/Debug.md | 55 ++++++++--- src/Private/FileWatchers.ps1 | 14 +-- src/Private/Gui.ps1 | 5 +- src/Private/Logging.ps1 | 5 +- src/Private/PodeServer.ps1 | 37 +++---- src/Private/Runspaces.ps1 | 173 ++++++++++++++------------------- src/Private/Schedules.ps1 | 8 +- src/Private/ServiceServer.ps1 | 4 +- src/Private/SmtpServer.ps1 | 14 +-- src/Private/Tasks.ps1 | 2 +- src/Private/TcpServer.ps1 | 14 +-- src/Private/Timers.ps1 | 4 +- src/Private/WebSockets.ps1 | 14 +-- src/Public/Schedules.ps1 | 14 +-- src/Public/Tasks.ps1 | 14 +-- src/Public/Timers.ps1 | 14 +-- tests/unit/Schedules.Tests.ps1 | 14 +-- tests/unit/Timers.Tests.ps1 | 10 +- 18 files changed, 159 insertions(+), 256 deletions(-) diff --git a/docs/Getting-Started/Debug.md b/docs/Getting-Started/Debug.md index 057ad4a2f..50bb23a60 100644 --- a/docs/Getting-Started/Debug.md +++ b/docs/Getting-Started/Debug.md @@ -177,27 +177,44 @@ The steps to attach to the Pode process are as follows: -## Customizing and Managing Runspace Names +## Customizing and Managing Runspace Names in Pode ### Distinguishing Runspace Names in Pode -In Pode, internal runspaces are automatically assigned distinct names. This naming convention helps in identifying and managing these runspaces efficiently during debugging and monitoring. However, this is not the case for runspaces created by user tasks and schedules (excluding AsyncTask). These user-created runspaces typically have names in the `Runspace` format, which can make it challenging to distinguish between different runspaces. +In Pode, internal runspaces are automatically assigned distinct names. This built-in naming convention is crucial for identifying and managing runspaces efficiently, particularly during debugging or when monitoring multiple concurrent processes. + +Pode uses specific naming patterns for its internal runspaces, which include: + +- **Pode_Web_Listener_1** +- **Pode_Signals_Broadcaster_1** +- **Pode_Signals_Listener_1** +- **Pode_Web_KeepAlive_1** +- **Pode_Files_Watcher_1** +- **Pode_Main_Logging_1** +- **Pode_Timers_Scheduler_1** +- **Pode_Schedules_[Schedule Name]_1** – where `[Schedule Name]` is the name of the schedule. +- **Pode_Tasks_[Task Name]_1** – where `[Task Name]` is the name of the task. + +These default names are automatically assigned by Pode, making it easier to identify the purpose of each runspace during execution. ### Customizing Runspace Names -By default, Pode’s Tasks, Schedules, and Timers use their own names to label their associated runspaces, making it easier to identify them during debugging and monitoring. +By default, Pode’s Tasks, Schedules, and Timers label their associated runspaces with their own names (as shown above). This simplifies the identification of runspaces when debugging or reviewing logs. + +However, if a different runspace name is needed, Pode allows you to customize it. Inside the script block of `Add-PodeTask`, `Add-PodeSchedule`, or `Add-PodeTimer`, you can use the `Set-PodeCurrentRunspaceName` cmdlet to assign any custom name you prefer. -However, if you wish to use a different name for the runspace, you can invoke `Add-PodeTask`, `Add-PodeSchedule`, or `Add-PodeTimer` with the `-DisableRunspaceNaming` parameter. -Then, within the script block, you can use the Set-PodeCurrentRunspaceName cmdlet to assign any custom name you prefer. +```powershell +Set-PodeCurrentRunspaceName -Name 'Custom Runspace Name' +``` -Another useful cmdlet is `Get-PodeCurrentRunspaceName`, which retrieves the current runspace's name. This can be helpful if you need to log or display the runspace name dynamically. +This cmdlet sets a custom name for the runspace, making it easier to track during execution. ### Example -Here is an updated example demonstrating how to set a custom runspace name in a Pode task: +Here’s an example that demonstrates how to set a custom runspace name in a Pode task: ```powershell -Add-PodeTask -Name 'Test2' -DisableRunspaceNaming -ScriptBlock { +Add-PodeTask -Name 'Test2' -ScriptBlock { param($value) # Set a custom name for the current runspace Set-PodeCurrentRunspaceName -Name 'My Fancy Runspace' @@ -206,12 +223,26 @@ Add-PodeTask -Name 'Test2' -DisableRunspaceNaming -ScriptBlock { } ``` -In this example, the `Set-PodeCurrentRunspaceName` cmdlet is used to assign the custom name 'My Fancy Runspace' to the runspace executing the task, enhancing identification during debugging or in logs. +In this example, the `Set-PodeCurrentRunspaceName` cmdlet assigns the custom name `'My Fancy Runspace'` to the task's runspace. This is especially useful for debugging or when examining logs, as the custom name makes the runspace more recognizable. ### Retrieving Runspace Names -Another useful cmdlet is `Get-PodeCurrentRunspaceName`, which retrieves the current runspace's name. This cmdlet can be particularly helpful if you need to log or display the runspace name dynamically during execution. It allows you to track and manage runspaces effectively, especially in complex scenarios where multiple runspaces are running concurrently. +Pode also provides the `Get-PodeCurrentRunspaceName` cmdlet to retrieve the name of the current runspace. This is particularly helpful when you need to log or display the runspace name dynamically during execution. + +```powershell +Get-PodeCurrentRunspaceName +``` + +This cmdlet returns the name of the current runspace, allowing for easier tracking and management in complex scenarios with multiple concurrent runspaces. + +### Example + +Here’s an example that uses `Get-PodeCurrentRunspaceName` to output the runspace name during the execution of a schedule: ```powershell - Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-PodeHost "Runspace name: $(Get-PodeCurrentRunspaceName)" } - ``` \ No newline at end of file +Add-PodeSchedule -Name 'TestSchedule' -Cron '@hourly' -ScriptBlock { + Write-PodeHost "Runspace name: $(Get-PodeCurrentRunspaceName)" +} +``` + +In this example, the schedule outputs the name of the runspace executing the script block every hour. This can be useful for logging and monitoring purposes when dealing with multiple schedules or tasks. diff --git a/src/Private/FileWatchers.ps1 b/src/Private/FileWatchers.ps1 index a0bce00ae..8bb919d15 100644 --- a/src/Private/FileWatchers.ps1 +++ b/src/Private/FileWatchers.ps1 @@ -54,14 +54,8 @@ function Start-PodeFileWatcherRunspace { $watchScript = { param( [Parameter(Mandatory = $true)] - $Watcher, - - [Parameter(Mandatory = $true)] - [int] - $ThreadId + $Watcher ) - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name "FileWatcher_$ThreadId" try { while ($Watcher.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -135,7 +129,7 @@ function Start-PodeFileWatcherRunspace { } 1..$PodeContext.Threads.Files | ForEach-Object { - Add-PodeRunspace -Type Files -ScriptBlock $watchScript -Parameters @{ 'Watcher' = $watcher; 'ThreadId' = $_ } + Add-PodeRunspace -Type Files -Name 'Watcher' -Id $_ -ScriptBlock $watchScript -Parameters @{ 'Watcher' = $watcher } } # script to keep file watcher server alive until cancelled @@ -144,8 +138,6 @@ function Start-PodeFileWatcherRunspace { [Parameter(Mandatory = $true)] $Watcher ) - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name 'FileWatcher_KeepAlive' try { while ($Watcher.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -165,5 +157,5 @@ function Start-PodeFileWatcherRunspace { } } - Add-PodeRunspace -Type Files -ScriptBlock $waitScript -Parameters @{ 'Watcher' = $watcher } -NoProfile + Add-PodeRunspace -Type Files -Name 'KeepAlive' -ScriptBlock $waitScript -Parameters @{ 'Watcher' = $watcher } -NoProfile } diff --git a/src/Private/Gui.ps1 b/src/Private/Gui.ps1 index 2caf49612..94b772795 100644 --- a/src/Private/Gui.ps1 +++ b/src/Private/Gui.ps1 @@ -12,9 +12,6 @@ function Start-PodeGuiRunspace { } $script = { - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name 'PodeGui' - try { # if there are multiple endpoints, flag warning we're only using the first - unless explicitly set if ($null -eq $PodeContext.Server.Gui.Endpoint) { @@ -139,5 +136,5 @@ function Start-PodeGuiRunspace { } } - Add-PodeRunspace -Type Gui -ScriptBlock $script + Add-PodeRunspace -Type Gui -Name 'Watcher' -ScriptBlock $script } \ No newline at end of file diff --git a/src/Private/Logging.ps1 b/src/Private/Logging.ps1 index a98223f7e..27db3e4fa 100644 --- a/src/Private/Logging.ps1 +++ b/src/Private/Logging.ps1 @@ -376,9 +376,6 @@ function Start-PodeLoggingRunspace { $script = { try { - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name 'Logging' - while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { try { # if there are no logs to process, just sleep for a few seconds - but after checking the batch @@ -455,7 +452,7 @@ function Start-PodeLoggingRunspace { } } - Add-PodeRunspace -Type Main -ScriptBlock $script + Add-PodeRunspace -Type Main -Name 'Logging' -ScriptBlock $script } <# diff --git a/src/Private/PodeServer.ps1 b/src/Private/PodeServer.ps1 index 33ef263c4..7f3ffa5fa 100644 --- a/src/Private/PodeServer.ps1 +++ b/src/Private/PodeServer.ps1 @@ -108,14 +108,8 @@ function Start-PodeWebServer { $listenScript = { param( [Parameter(Mandatory = $true)] - $Listener, - - [Parameter(Mandatory = $true)] - [int] - $ThreadId + $Listener ) - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name "HttpEndpoint_$ThreadId" try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -282,7 +276,7 @@ function Start-PodeWebServer { # start the runspace for listening on x-number of threads 1..$PodeContext.Threads.General | ForEach-Object { - Add-PodeRunspace -Type Web -ScriptBlock $listenScript -Parameters @{ 'Listener' = $listener; 'ThreadId' = $_ } + Add-PodeRunspace -Type Web -Name 'Listener' -Id $_ -ScriptBlock $listenScript -Parameters @{ 'Listener' = $listener } } } @@ -294,8 +288,6 @@ function Start-PodeWebServer { [Parameter(Mandatory = $true)] $Listener ) - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name 'WsEndpoint' try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -359,7 +351,7 @@ function Start-PodeWebServer { } } - Add-PodeRunspace -Type Signals -ScriptBlock $signalScript -Parameters @{ 'Listener' = $listener } + Add-PodeRunspace -Type Signals -Name 'Listener' -ScriptBlock $signalScript -Parameters @{ 'Listener' = $listener } } # only if WS endpoint @@ -368,14 +360,8 @@ function Start-PodeWebServer { $clientScript = { param( [Parameter(Mandatory = $true)] - $Listener, - - [Parameter(Mandatory = $true)] - [int] - $ThreadId + $Listener ) - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name "WsEndpoint_$ThreadId" try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -444,7 +430,7 @@ function Start-PodeWebServer { # start the runspace for listening on x-number of threads 1..$PodeContext.Threads.General | ForEach-Object { - Add-PodeRunspace -Type Signals -ScriptBlock $clientScript -Parameters @{ 'Listener' = $listener; 'ThreadId' = $_ } + Add-PodeRunspace -Type Signals -Name 'Broadcaster' -Id $_ -ScriptBlock $clientScript -Parameters @{ 'Listener' = $listener } } } @@ -455,8 +441,6 @@ function Start-PodeWebServer { [ValidateNotNull()] $Listener ) - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name "Listener_KeepAlive" try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -476,12 +460,13 @@ function Start-PodeWebServer { } } - $waitType = 'Web' - if (!(Test-PodeEndpointByProtocolType -Type Http)) { - $waitType = 'Signals' - } - Add-PodeRunspace -Type $waitType -ScriptBlock $waitScript -Parameters @{ 'Listener' = $listener} -NoProfile + if (Test-PodeEndpointByProtocolType -Type Http) { + Add-PodeRunspace -Type 'Web' -Name 'KeepAlive' -ScriptBlock $waitScript -Parameters @{ 'Listener' = $listener } -NoProfile + } + else { + Add-PodeRunspace -Type 'Signals' -Name 'KeepAlive' -ScriptBlock $waitScript -Parameters @{ 'Listener' = $listener } -NoProfile + } # browse to the first endpoint, if flagged if ($Browse) { diff --git a/src/Private/Runspaces.ps1 b/src/Private/Runspaces.ps1 index 1325c7e64..7bedb2f33 100644 --- a/src/Private/Runspaces.ps1 +++ b/src/Private/Runspaces.ps1 @@ -1,92 +1,6 @@ -function Add-PodeRunspaceNameToScriptblock { - param ( - [ScriptBlock]$ScriptBlock, - [string]$Name - ) - - # Convert the scriptblock to a string - $scriptBlockString = $ScriptBlock.ToString() - if ($scriptBlockString.contains('Set-PodeCurrentRunspaceName')) { - Write-PodeHost "'Set-PodeCurrentRunspaceName' already there" - } - # Check for a param block and insert the desired line after it - $pattern = '(\s*param\s*\([^\)]*\)\s*)' #'(\{\s*|\s*)param\s*\([^\)]*\)\s*' - - # Check for a param block and insert the desired line after it - if ($scriptBlockString -match $pattern) { - # Insert Set-PodeCurrentRunspaceName after the param block - $modifiedScriptBlockString = $scriptBlockString -replace $pattern,"`${1}Set-PodeCurrentRunspaceName -Name '$Name'`n" - } - else { - # If no param block is found, add Set-PodeCurrentRunspaceName at the beginning - $modifiedScriptBlockString = "Set-PodeCurrentRunspaceName -Name `"$Name`"`n$scriptBlockString" - } - - # Convert the modified string back into a scriptblock - return [ScriptBlock]::Create($modifiedScriptBlockString) -} - -<# -.SYNOPSIS - Opens a runspace for Pode server operations based on the specified type. - -.DESCRIPTION - This function initializes a runspace for Pode server tasks by importing necessary - modules, adding PowerShell drives, and setting the state of the runspace pool to 'Ready'. - If an error occurs during the initialization, the state is adjusted to 'Error' if it - was previously set to 'waiting', and the error details are outputted. - -.PARAMETER Type - The type of the runspace pool to open. This parameter only accepts predefined values, - ensuring the runspace pool corresponds to a supported server operation type. The valid - types are: Main, Signals, Schedules, Gui, Web, Smtp, Tcp, Tasks, WebSockets, Files. - -.EXAMPLE - Open-PodeRunspace -Type "Web" - - Opens a runspace for the 'Web' type, setting it ready for handling web server tasks. - -.NOTES - This function is not invoked directly but indirectly by `Add-PodeRunspace` function using - $null = $ps.AddScript("Open-PodeRunspace -Type '$($Type)'") -#> -function Open-PodeRunspace { - param( - [Parameter(Mandatory = $true)] - [ValidateSet('Main', 'Signals', 'Schedules', 'Gui', 'Web', 'Smtp', 'Tcp', 'Tasks', 'WebSockets', 'Files')] - [string] - $Type - ) - - try { - # Importing internal Pode modules necessary for the runspace operations. - Import-PodeModulesInternal - - # Adding PowerShell drives required by the runspace. - Add-PodePSDrivesInternal - - # Setting the state of the runspace pool to 'Ready', indicating it is ready to process requests. - $PodeContext.RunspacePools[$Type].State = 'Ready' - } - catch { - # If an error occurs and the current state is 'waiting', set it to 'Error'. - if ($PodeContext.RunspacePools[$Type].State -ieq 'waiting') { - $PodeContext.RunspacePools[$Type].State = 'Error' - } - - # Outputting the error to the default output stream, including the stack trace. - $_ | Out-Default - $_.ScriptStackTrace | Out-Default - - # Rethrowing the error to be handled further up the call stack. - throw - } -} - - <# .SYNOPSIS - Adds a new runspace to Pode with specified type and script block. + Adds a new runspace to Pode with the specified type and script block. .DESCRIPTION The `Add-PodeRunspace` function creates a new PowerShell runspace within Pode @@ -149,30 +63,72 @@ function Add-PodeRunspace { $NoProfile, [switch] - $PassThru + $PassThru, + + [string] + $Name, + + [string] + $Id = '1' ) try { - # create powershell pipelines + # Define the script block to open the runspace and set its state. + $openRunspaceScript = { + param($Type, $Name, $NoProfile) + try { + # Set the runspace name. + Set-PodeCurrentRunspaceName -Name $Name + + if (!$NoProfile) { + # Import necessary internal Pode modules for the runspace. + Import-PodeModulesInternal + + # Add required PowerShell drives. + Add-PodePSDrivesInternal + } + + # Mark the runspace as 'Ready' to process requests. + $PodeContext.RunspacePools[$Type].State = 'Ready' + } + catch { + # Handle errors, setting the runspace state to 'Error' if applicable. + if ($PodeContext.RunspacePools[$Type].State -ieq 'waiting') { + $PodeContext.RunspacePools[$Type].State = 'Error' + } + + # Output the error details to the default stream and rethrow. + $_ | Out-Default + $_.ScriptStackTrace | Out-Default + throw + } + } + + # Create a PowerShell pipeline. $ps = [powershell]::Create() $ps.RunspacePool = $PodeContext.RunspacePools[$Type].Pool - # load modules/drives - if (!$NoProfile) { - $null = $ps.AddScript("Open-PodeRunspace -Type '$($Type)'") - } + # Add the script block and parameters to the pipeline. + $null = $ps.AddScript($openRunspaceScript) + $null = $ps.AddParameters( + @{ + 'Type' = $Type + 'Name' = "Pode_$($Type)_$($Name)_$($Id)" + 'NoProfile' = $NoProfile.IsPresent + } + ) - # load main script + # Add the main script block to the pipeline. $null = $ps.AddScript($ScriptBlock) - # load parameters + # Add any provided parameters to the script block. if (!(Test-PodeIsEmpty $Parameters)) { $Parameters.Keys | ForEach-Object { $null = $ps.AddParameter($_, $Parameters[$_]) } } - # start the pipeline + # Begin invoking the pipeline, with or without output streaming. if ($null -eq $OutputStream) { $pipeline = $ps.BeginInvoke() } @@ -180,20 +136,16 @@ function Add-PodeRunspace { $pipeline = $ps.BeginInvoke($OutputStream, $OutputStream) } - # do we need to remember this pipeline? sorry, what did you say? + # Handle forgetting, returning, or storing the pipeline. if ($Forget) { $null = $pipeline } - - # or do we need to return it for custom processing? ie: tasks elseif ($PassThru) { return @{ Pipeline = $ps Handler = $pipeline } } - - # or store it here for later clean-up else { $PodeContext.Runspaces += @{ Pool = $Type @@ -204,6 +156,7 @@ function Add-PodeRunspace { } } catch { + # Log and throw any exceptions encountered during execution. $_ | Write-PodeErrorLog throw $_.Exception } @@ -349,4 +302,20 @@ function Close-PodeRunspace { $_ | Write-PodeErrorLog throw $_.Exception } -} \ No newline at end of file +} + + + + + + + + + + + + + + + + diff --git a/src/Private/Schedules.ps1 b/src/Private/Schedules.ps1 index 96f1db151..4c3c5bf32 100644 --- a/src/Private/Schedules.ps1 +++ b/src/Private/Schedules.ps1 @@ -49,8 +49,6 @@ function Start-PodeScheduleRunspace { $script = { try { - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name 'Scheduler_Trigger' # select the schedules that trigger on-start $_now = [DateTime]::Now @@ -108,7 +106,7 @@ function Start-PodeScheduleRunspace { } } - Add-PodeRunspace -Type Main -ScriptBlock $script -NoProfile + Add-PodeRunspace -Type Main -Name 'ScheduleHouseKeeper' -ScriptBlock $script -NoProfile } function Close-PodeScheduleInternal { @@ -232,7 +230,6 @@ function Invoke-PodeInternalScheduleLogic { if (($Schedule.Timeout.From -ieq 'Create') -and ($Schedule.Timeout.Value -ge 0)) { $expireTime = $createTime.AddSeconds($Schedule.Timeout.Value) } - # add the schedule process $PodeContext.Schedules.Processes[$processId] = @{ ID = $processId @@ -247,8 +244,7 @@ function Invoke-PodeInternalScheduleLogic { # start the schedule runspace $scriptblock = Get-PodeScheduleScriptBlock - $runspace = Add-PodeRunspace -Type Schedules -ScriptBlock $scriptblock -Parameters $parameters -PassThru - + $runspace = Add-PodeRunspace -Type Schedules -Name $Schedule.Name -ScriptBlock $scriptblock -Parameters $parameters -PassThru # add runspace to process $PodeContext.Schedules.Processes[$processId].Runspace = $runspace } diff --git a/src/Private/ServiceServer.ps1 b/src/Private/ServiceServer.ps1 index 5c6a8d9f9..bd7fe6eca 100644 --- a/src/Private/ServiceServer.ps1 +++ b/src/Private/ServiceServer.ps1 @@ -11,8 +11,6 @@ function Start-PodeServiceServer { # script for the looping server $serverScript = { - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name 'ServiceServer' try { while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -43,5 +41,5 @@ function Start-PodeServiceServer { } # start the runspace for the server - Add-PodeRunspace -Type Main -ScriptBlock $serverScript + Add-PodeRunspace -Type Main -Name 'ServiceServer' -ScriptBlock $serverScript } \ No newline at end of file diff --git a/src/Private/SmtpServer.ps1 b/src/Private/SmtpServer.ps1 index fb9d82df1..354b353a4 100644 --- a/src/Private/SmtpServer.ps1 +++ b/src/Private/SmtpServer.ps1 @@ -82,14 +82,8 @@ function Start-PodeSmtpServer { param( [Parameter(Mandatory = $true)] [ValidateNotNull()] - $Listener, - - [Parameter(Mandatory = $true)] - [int] - $ThreadId + $Listener ) - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name "SMTPEndpoint_$ThreadId" try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -179,7 +173,7 @@ function Start-PodeSmtpServer { # start the runspace for listening on x-number of threads 1..$PodeContext.Threads.General | ForEach-Object { - Add-PodeRunspace -Type Smtp -ScriptBlock $listenScript -Parameters @{ 'Listener' = $listener; 'ThreadId' = $_ } + Add-PodeRunspace -Type Smtp -Name 'Listener' -Id $_ -ScriptBlock $listenScript -Parameters @{ 'Listener' = $listener } } # script to keep smtp server listening until cancelled @@ -189,8 +183,6 @@ function Start-PodeSmtpServer { [ValidateNotNull()] $Listener ) - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name 'SMTPEndpoint_KeepAlive' try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -210,7 +202,7 @@ function Start-PodeSmtpServer { } } - Add-PodeRunspace -Type Smtp -ScriptBlock $waitScript -Parameters @{ 'Listener' = $listener } -NoProfile + Add-PodeRunspace -Type Smtp -Name 'KeepAlive' -ScriptBlock $waitScript -Parameters @{ 'Listener' = $listener } -NoProfile # state where we're running return @(foreach ($endpoint in $endpoints) { diff --git a/src/Private/Tasks.ps1 b/src/Private/Tasks.ps1 index db596544e..b723a4f74 100644 --- a/src/Private/Tasks.ps1 +++ b/src/Private/Tasks.ps1 @@ -126,7 +126,7 @@ function Invoke-PodeInternalTask { # start the task runspace $scriptblock = Get-PodeTaskScriptBlock - $runspace = Add-PodeRunspace -Type Tasks -ScriptBlock $scriptblock -Parameters $parameters -OutputStream $result -PassThru + $runspace = Add-PodeRunspace -Type Tasks -Name $Task.Name -ScriptBlock $scriptblock -Parameters $parameters -OutputStream $result -PassThru # add runspace to process $PodeContext.Tasks.Processes[$processId].Runspace = $runspace diff --git a/src/Private/TcpServer.ps1 b/src/Private/TcpServer.ps1 index 719edbd98..6562b60c7 100644 --- a/src/Private/TcpServer.ps1 +++ b/src/Private/TcpServer.ps1 @@ -78,14 +78,8 @@ function Start-PodeTcpServer { param( [Parameter(Mandatory = $true)] [ValidateNotNull()] - $Listener, - - [Parameter(Mandatory = $true)] - [int] - $ThreadId + $Listener ) - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name "TCPEndpoint_$ThreadId" try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -197,7 +191,7 @@ function Start-PodeTcpServer { # start the runspace for listening on x-number of threads 1..$PodeContext.Threads.General | ForEach-Object { - Add-PodeRunspace -Type Tcp -ScriptBlock $listenScript -Parameters @{ 'Listener' = $listener; 'ThreadId' = $_ } + Add-PodeRunspace -Type Tcp -Name 'Listener' -Id $_ -ScriptBlock $listenScript -Parameters @{ 'Listener' = $listener } } # script to keep tcp server listening until cancelled @@ -207,8 +201,6 @@ function Start-PodeTcpServer { [ValidateNotNull()] $Listener ) - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name 'TCPEndpoint_KeepAlive' try { while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -228,7 +220,7 @@ function Start-PodeTcpServer { } } - Add-PodeRunspace -Type Tcp -ScriptBlock $waitScript -Parameters @{ 'Listener' = $listener } -NoProfile + Add-PodeRunspace -Type Tcp -Name 'KeepAlive' -ScriptBlock $waitScript -Parameters @{ 'Listener' = $listener } -NoProfile # state where we're running return @(foreach ($endpoint in $endpoints) { diff --git a/src/Private/Timers.ps1 b/src/Private/Timers.ps1 index 9fae1b06a..d5a3ac3d7 100644 --- a/src/Private/Timers.ps1 +++ b/src/Private/Timers.ps1 @@ -20,8 +20,6 @@ function Start-PodeTimerRunspace { $script = { try { - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name 'Timer' while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { try { @@ -82,7 +80,7 @@ function Start-PodeTimerRunspace { } } - Add-PodeRunspace -Type Timers -ScriptBlock $script + Add-PodeRunspace -Type Timers -Name "Scheduler" -ScriptBlock $script } function Invoke-PodeInternalTimer { diff --git a/src/Private/WebSockets.ps1 b/src/Private/WebSockets.ps1 index 016d5488c..963c66420 100644 --- a/src/Private/WebSockets.ps1 +++ b/src/Private/WebSockets.ps1 @@ -44,14 +44,8 @@ function Start-PodeWebSocketRunspace { param( [Parameter(Mandatory = $true)] [ValidateNotNull()] - $Receiver, - - [Parameter(Mandatory = $true)] - [int] - $ThreadId + $Receiver ) - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name "WebSocketEndpoint_$ThreadId" try { while ($Receiver.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -109,7 +103,7 @@ function Start-PodeWebSocketRunspace { # start the runspace for listening on x-number of threads 1..$PodeContext.Threads.WebSockets | ForEach-Object { - Add-PodeRunspace -Type WebSockets -ScriptBlock $receiveScript -Parameters @{ 'Receiver' = $PodeContext.Server.WebSockets.Receiver; 'ThreadId' = $_ } + Add-PodeRunspace -Type WebSockets -Name 'Listener' -Id $_ -ScriptBlock $receiveScript -Parameters @{ 'Receiver' = $PodeContext.Server.WebSockets.Receiver } } # script to keep websocket server receiving until cancelled @@ -119,8 +113,6 @@ function Start-PodeWebSocketRunspace { [ValidateNotNull()] $Receiver ) - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name 'WebSocketEndpoint__KeepAlive' try { while ($Receiver.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { @@ -140,5 +132,5 @@ function Start-PodeWebSocketRunspace { } } - Add-PodeRunspace -Type WebSockets -ScriptBlock $waitScript -Parameters @{ 'Receiver' = $PodeContext.Server.WebSockets.Receiver } -NoProfile + Add-PodeRunspace -Type WebSockets -Name 'KeepAlive' -ScriptBlock $waitScript -Parameters @{ 'Receiver' = $PodeContext.Server.WebSockets.Receiver } -NoProfile } \ No newline at end of file diff --git a/src/Public/Schedules.ps1 b/src/Public/Schedules.ps1 index f1f21d0e8..21a89c916 100644 --- a/src/Public/Schedules.ps1 +++ b/src/Public/Schedules.ps1 @@ -38,9 +38,6 @@ .PARAMETER OnStart If supplied, the schedule will trigger when the server starts, regardless if the cron-expression matches the current time. -.PARAMETER DisableRunspaceNaming - If supplied, the runspace name will not be set for the Schedule's ScriptBlock. - .EXAMPLE Add-PodeSchedule -Name 'RunEveryMinute' -Cron '@minutely' -ScriptBlock { /* logic */ } @@ -98,10 +95,7 @@ function Add-PodeSchedule { $TimeoutFrom = 'Create', [switch] - $OnStart, - - [switch] - $DisableRunspaceNaming + $OnStart ) # error if serverless @@ -135,12 +129,6 @@ function Add-PodeSchedule { $ScriptBlock = Convert-PodeFileToScriptBlock -FilePath $FilePath } - # Check if the runspace naming feature is not disabled - if (! $DisableRunspaceNaming) { - # Set the runspace name by adding the specified name to the ScriptBlock - $ScriptBlock = Add-PodeRunspaceNameToScriptblock -ScriptBlock $ScriptBlock -Name $Name - } - # check for scoped vars $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState diff --git a/src/Public/Tasks.ps1 b/src/Public/Tasks.ps1 index b5df4cc1e..56511f54f 100644 --- a/src/Public/Tasks.ps1 +++ b/src/Public/Tasks.ps1 @@ -23,9 +23,6 @@ .PARAMETER TimeoutFrom Where to start the Timeout from, either 'Create', 'Start'. (Default: 'Create') -.PARAMETER DisableRunspaceNaming - If supplied, the runspace name will not be set for the Schedule's ScriptBlock. - .EXAMPLE Add-PodeTask -Name 'Example1' -ScriptBlock { Invoke-SomeLogic } @@ -58,10 +55,7 @@ function Add-PodeTask { [Parameter()] [ValidateSet('Create', 'Start')] [string] - $TimeoutFrom = 'Create', - - [switch] - $DisableRunspaceNaming + $TimeoutFrom = 'Create' ) # ensure the task doesn't already exist if ($PodeContext.Tasks.Items.ContainsKey($Name)) { @@ -74,12 +68,6 @@ function Add-PodeTask { $ScriptBlock = Convert-PodeFileToScriptBlock -FilePath $FilePath } - # Check if the runspace naming feature is not disabled - if (! $DisableRunspaceNaming) { - # Set the runspace name by adding the specified name to the ScriptBlock - $ScriptBlock = Add-PodeRunspaceNameToScriptblock -ScriptBlock $ScriptBlock -Name $Name - } - # check for scoped vars $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState diff --git a/src/Public/Timers.ps1 b/src/Public/Timers.ps1 index bfd5d8caa..0c9acf9c6 100644 --- a/src/Public/Timers.ps1 +++ b/src/Public/Timers.ps1 @@ -29,9 +29,6 @@ .PARAMETER OnStart If supplied, the timer will trigger when the server starts. -.PARAMETER DisableRunspaceNaming - If supplied, the runspace name will not be set for the Schedule's ScriptBlock. - .EXAMPLE Add-PodeTimer -Name 'Hello' -Interval 10 -ScriptBlock { 'Hello, world!' | Out-Default } @@ -76,10 +73,7 @@ function Add-PodeTimer { $ArgumentList, [switch] - $OnStart, - - [switch] - $DisableRunspaceNaming + $OnStart ) # error if serverless @@ -114,12 +108,6 @@ function Add-PodeTimer { $ScriptBlock = Convert-PodeFileToScriptBlock -FilePath $FilePath } - # Check if the runspace naming feature is not disabled - if (! $DisableRunspaceNaming) { - # Set the runspace name by adding the specified name to the ScriptBlock - $ScriptBlock = Add-PodeRunspaceNameToScriptblock -ScriptBlock $ScriptBlock -Name $Name - } - # check for scoped vars $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -PSSession $PSCmdlet.SessionState diff --git a/tests/unit/Schedules.Tests.ps1 b/tests/unit/Schedules.Tests.ps1 index 3f3182fe2..4f854672a 100644 --- a/tests/unit/Schedules.Tests.ps1 +++ b/tests/unit/Schedules.Tests.ps1 @@ -65,7 +65,7 @@ Describe 'Add-PodeSchedule' { $start = ([DateTime]::Now.AddHours(3)) $end = ([DateTime]::Now.AddHours(5)) - Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } -StartTime $start -EndTime $end -DisableRunspaceNaming + Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } -StartTime $start -EndTime $end $schedule = $PodeContext.Schedules.Items['test'] $schedule | Should -Not -Be $null @@ -81,7 +81,7 @@ Describe 'Add-PodeSchedule' { $PodeContext = @{ 'Schedules' = @{ Items = @{} }; } $end = ([DateTime]::Now.AddHours(5)) - Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } -EndTime $end -DisableRunspaceNaming + Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } -EndTime $end $schedule = $PodeContext.Schedules.Items['test'] $schedule | Should -Not -Be $null @@ -97,7 +97,7 @@ Describe 'Add-PodeSchedule' { $PodeContext = @{ 'Schedules' = @{ Items = @{} }; } $start = ([DateTime]::Now.AddHours(3)) - Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } -StartTime $start -DisableRunspaceNaming + Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } -StartTime $start $schedule = $PodeContext.Schedules.Items['test'] $schedule | Should -Not -Be $null @@ -112,7 +112,7 @@ Describe 'Add-PodeSchedule' { It 'Adds new schedule with just a cron' { $PodeContext = @{ 'Schedules' = @{ Items = @{} }; } - Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } -DisableRunspaceNaming + Add-PodeSchedule -Name 'test' -Cron '@hourly' -ScriptBlock { Write-Host 'hello' } $schedule = $PodeContext.Schedules.Items['test'] $schedule | Should -Not -Be $null @@ -129,7 +129,7 @@ Describe 'Add-PodeSchedule' { $start = ([DateTime]::Now.AddHours(3)) $end = ([DateTime]::Now.AddHours(5)) - Add-PodeSchedule -Name 'test' -Cron @('@minutely', '@hourly') -ScriptBlock { Write-Host 'hello' } -StartTime $start -EndTime $end -DisableRunspaceNaming + Add-PodeSchedule -Name 'test' -Cron @('@minutely', '@hourly') -ScriptBlock { Write-Host 'hello' } -StartTime $start -EndTime $end $schedule = $PodeContext.Schedules.Items['test'] $schedule | Should -Not -Be $null @@ -318,7 +318,7 @@ Describe 'Clear-PodeSchedules' { Describe 'Edit-PodeSchedule' { It 'Adds a new schedule, then edits the cron' { $PodeContext = @{ 'Schedules' = @{ Items = @{} }; } - Add-PodeSchedule -Name 'test1' -Cron '@hourly' -ScriptBlock { Write-Host 'hello1' } -DisableRunspaceNaming + Add-PodeSchedule -Name 'test1' -Cron '@hourly' -ScriptBlock { Write-Host 'hello1' } $PodeContext.Schedules.Items['test1'].Crons.Length | Should -Be 1 $PodeContext.Schedules.Items['test1'].Script.ToString() | Should -Be ({ Write-Host 'hello1' }).ToString() @@ -329,7 +329,7 @@ Describe 'Edit-PodeSchedule' { It 'Adds a new schedule, then edits the script' { $PodeContext = @{ 'Schedules' = @{ Items = @{} }; } - Add-PodeSchedule -Name 'test1' -Cron '@hourly' -ScriptBlock { Write-Host 'hello1' } -DisableRunspaceNaming + Add-PodeSchedule -Name 'test1' -Cron '@hourly' -ScriptBlock { Write-Host 'hello1' } $PodeContext.Schedules.Items['test1'].Crons.Length | Should -Be 1 $PodeContext.Schedules.Items['test1'].Script.ToString() | Should -Be ({ Write-Host 'hello1' }).ToString() diff --git a/tests/unit/Timers.Tests.ps1 b/tests/unit/Timers.Tests.ps1 index e37dc8890..f8607c73f 100644 --- a/tests/unit/Timers.Tests.ps1 +++ b/tests/unit/Timers.Tests.ps1 @@ -71,7 +71,7 @@ Describe 'Add-PodeTimer' { It 'Adds new timer to session with no limit' { $PodeContext = @{ 'Timers' = @{ Items = @{} }; } - Add-PodeTimer -Name 'test' -Interval 1 -ScriptBlock { Write-Host 'hello' } -Limit 0 -Skip 1 -DisableRunspaceNaming + Add-PodeTimer -Name 'test' -Interval 1 -ScriptBlock { Write-Host 'hello' } -Limit 0 -Skip 1 $timer = $PodeContext.Timers.Items['test'] $timer | Should -Not -Be $null @@ -87,7 +87,7 @@ Describe 'Add-PodeTimer' { It 'Adds new timer to session with limit' { $PodeContext = @{ 'Timers' = @{ Items = @{} }; } - Add-PodeTimer -Name 'test' -Interval 3 -ScriptBlock { Write-Host 'hello' } -Limit 2 -Skip 1 -DisableRunspaceNaming + Add-PodeTimer -Name 'test' -Interval 3 -ScriptBlock { Write-Host 'hello' } -Limit 2 -Skip 1 $timer = $PodeContext.Timers.Items['test'] $timer | Should -Not -Be $null @@ -148,7 +148,7 @@ Describe 'Get-PodeTimer' { Describe 'Remove-PodeTimer' { It 'Adds new timer and then removes it' { $PodeContext = @{ 'Timers' = @{ Items = @{} }; } - Add-PodeTimer -Name 'test' -Interval 1 -ScriptBlock { Write-Host 'hello' } -DisableRunspaceNaming + Add-PodeTimer -Name 'test' -Interval 1 -ScriptBlock { Write-Host 'hello' } $timer = $PodeContext.Timers.Items['test'] $timer.Name | Should -Be 'test' @@ -178,7 +178,7 @@ Describe 'Clear-PodeTimers' { Describe 'Edit-PodeTimer' { It 'Adds a new timer, then edits the interval' { $PodeContext = @{ 'Timers' = @{ Items = @{} }; } - Add-PodeTimer -Name 'test1' -Interval 1 -ScriptBlock { Write-Host 'hello1' } -DisableRunspaceNaming + Add-PodeTimer -Name 'test1' -Interval 1 -ScriptBlock { Write-Host 'hello1' } $PodeContext.Timers.Items['test1'].Interval | Should -Be 1 $PodeContext.Timers.Items['test1'].Script.ToString() | Should -Be ({ Write-Host 'hello1' }).ToString() @@ -189,7 +189,7 @@ Describe 'Edit-PodeTimer' { It 'Adds a new timer, then edits the script' { $PodeContext = @{ 'Timers' = @{ Items = @{} }; } - Add-PodeTimer -Name 'test1' -Interval 1 -ScriptBlock { Write-Host 'hello1' } -DisableRunspaceNaming + Add-PodeTimer -Name 'test1' -Interval 1 -ScriptBlock { Write-Host 'hello1' } $PodeContext.Timers.Items['test1'].Interval | Should -Be 1 $PodeContext.Timers.Items['test1'].Script.ToString() | Should -Be ({ Write-Host 'hello1' }).ToString() From d55b548603ed77c6c0229f68a1ccc27facffcd7e Mon Sep 17 00:00:00 2001 From: mdaneri Date: Thu, 19 Sep 2024 20:55:41 -0700 Subject: [PATCH 159/177] fix Schedule example and created pester test for schedule events --- PSScriptAnalyzerSettings.psd1 | 2 +- examples/Schedules.ps1 | 6 +-- tests/integration/Schedules.Tests.ps1 | 68 +++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/PSScriptAnalyzerSettings.psd1 b/PSScriptAnalyzerSettings.psd1 index 99840546d..751210939 100644 --- a/PSScriptAnalyzerSettings.psd1 +++ b/PSScriptAnalyzerSettings.psd1 @@ -10,6 +10,6 @@ } } ExcludeRules = @( 'PSAvoidUsingPlainTextForPassword','PSUseShouldProcessForStateChangingFunctions', - 'PSAvoidUsingUsernameAndPasswordParams','PSUseProcessBlockForPipelineCommand','PSAvoidUsingConvertToSecureStringWithPlainText','PSReviewUnusedParameter' ) + 'PSAvoidUsingUsernameAndPasswordParams','PSUseProcessBlockForPipelineCommand','PSAvoidUsingConvertToSecureStringWithPlainText','PSReviewUnusedParameter' ,'PSAvoidAssignmentToAutomaticVariable') } \ No newline at end of file diff --git a/examples/Schedules.ps1 b/examples/Schedules.ps1 index 43444dc1c..0bf017bdd 100644 --- a/examples/Schedules.ps1 +++ b/examples/Schedules.ps1 @@ -47,11 +47,11 @@ Start-PodeServer { # schedule minutely using predefined cron $message = 'Hello, world!' Add-PodeSchedule -Name 'predefined' -Cron '@minutely' -Limit 2 -ScriptBlock { - param($TriggeredEvent, $Message1, $Message2) + param($Event, $Message1, $Message2) $using:message | Out-Default Get-PodeSchedule -Name 'predefined' | Out-Default - "Last: $($TriggeredEvent.Sender.LastTriggerTime)" | Out-Default - "Next: $($TriggeredEvent.Sender.NextTriggerTime)" | Out-Default + "Last: $($Event.Sender.LastTriggerTime)" | Out-Default + "Next: $($Event.Sender.NextTriggerTime)" | Out-Default "Message1: $($Message1)" | Out-Default "Message2: $($Message2)" | Out-Default } diff --git a/tests/integration/Schedules.Tests.ps1 b/tests/integration/Schedules.Tests.ps1 index c4fed1f62..9a76c8f47 100644 --- a/tests/integration/Schedules.Tests.ps1 +++ b/tests/integration/Schedules.Tests.ps1 @@ -18,6 +18,46 @@ Describe 'Schedules' { Close-PodeServer } + # schedule minutely using predefined cron + + Set-PodeState -Name 'test3' -Value @{eventList = @() } + + Add-PodeSchedule -Name 'predefined' -Cron '* * * * *' -Limit 2 -ScriptBlock { + param($Event, $Message1, $Message2) + Lock-PodeObject -ScriptBlock { + $test3 = (Get-PodeState -Name 'test3') + $test3.eventList += @{ + message = 'Hello, world!' + 'Last' = $Event.Sender.LastTriggerTime + 'Next' = $Event.Sender.NextTriggerTime + 'Message1' = $Message1 + 'Message2' = $Message2 + } + } + } + + + Add-PodeRoute -Method Get -Path '/eventlist' -ScriptBlock { + Lock-PodeObject -ScriptBlock { + $test3 = (Get-PodeState -Name 'test3') + if ($test3.eventList.Count -gt 1) { + Write-PodeJsonResponse -Value @{ ready = $true ; count = $test3.eventList.Count; eventList = $test3.eventList } + } + else { + Write-PodeJsonResponse -Value @{ ready = $false ; count = $test3.eventList.Count; } + } + } + } + + + # adhoc invoke a schedule's logic + Add-PodeRoute -Method Post -Path '/eventlist/run' -ScriptBlock { + Invoke-PodeSchedule -Name 'predefined' -ArgumentList @{ + Message1 = 'Hello!' + Message2 = 'Bye!' + } + } + # test1 Set-PodeState -Name 'Test1' -Value 0 Add-PodeSchedule -Name 'Test1' -Cron '* * * * *' -ScriptBlock { @@ -63,4 +103,32 @@ Describe 'Schedules' { $result = Invoke-RestMethod -Uri "$($Endpoint)/test2" -Method Get $result.Result | Should -Be 314 } + + It 'schedule events' { + Invoke-RestMethod -Uri "$($Endpoint)/eventlist/run" -Method post + Start-Sleep 10 + for ($i = 0; $i -lt 20; $i++) { + $result = Invoke-RestMethod -Uri "$($Endpoint)/eventlist" -Method Get + if ($result.ready) { + break + } + Start-Sleep -Seconds 10 + } + $result.ready | Should -BeTrue + $result.Count | Should -Be 2 + $result.eventList.GetType() | Should -Be 'System.Object[]' + $result.eventList.Count | Should -Be 2 + $result.eventList[0].Message1 | Should -Be "Hello!" + $result.eventList[0].Message2 | Should -Be 'Bye!' + $result.eventList[0].Message | Should -Be 'Hello, world!' + $result.eventList[0].Last | Should -BeNullOrEmpty + $result.eventList[0].next | Should -not -BeNullOrEmpty + + $result.eventList[1].Message1 | Should -BeNullOrEmpty + $result.eventList[1].Message2 | Should -BeNullOrEmpty + $result.eventList[1].Message | Should -Be 'Hello, world!' + $result.eventList[1].Last | Should -not -BeNullOrEmpty + $result.eventList[1].next | Should -not -BeNullOrEmpty + } + } \ No newline at end of file From c9c338375d1476aab78bd87cd4688e5342c81f71 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 20 Sep 2024 07:24:57 -0700 Subject: [PATCH 160/177] Pester test improvement --- tests/integration/Schedules.Tests.ps1 | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/tests/integration/Schedules.Tests.ps1 b/tests/integration/Schedules.Tests.ps1 index 9a76c8f47..74a53bd14 100644 --- a/tests/integration/Schedules.Tests.ps1 +++ b/tests/integration/Schedules.Tests.ps1 @@ -1,4 +1,5 @@ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseUsingScopeModifierInNewRunspaces', '', Justification = 'Using ArgumentList')] param() Describe 'Schedules' { @@ -22,7 +23,7 @@ Describe 'Schedules' { Set-PodeState -Name 'test3' -Value @{eventList = @() } - Add-PodeSchedule -Name 'predefined' -Cron '* * * * *' -Limit 2 -ScriptBlock { + Add-PodeSchedule -Name 'TestEvents' -Cron '* * * * *' -Limit 2 -ScriptBlock { param($Event, $Message1, $Message2) Lock-PodeObject -ScriptBlock { $test3 = (Get-PodeState -Name 'test3') @@ -52,10 +53,11 @@ Describe 'Schedules' { # adhoc invoke a schedule's logic Add-PodeRoute -Method Post -Path '/eventlist/run' -ScriptBlock { - Invoke-PodeSchedule -Name 'predefined' -ArgumentList @{ + Invoke-PodeSchedule -Name 'TestEvents' -ArgumentList @{ Message1 = 'Hello!' Message2 = 'Bye!' } + Write-PodeJsonResponse -Value ( @{Result = 'ok' } ) } # test1 @@ -93,20 +95,22 @@ Describe 'Schedules' { Get-Job -Name 'Pode' | Remove-Job -Force } - - It 'schedule updates state value - full cron' { + It 'Invoke schedule events' { + $result = Invoke-RestMethod -Uri "$($Endpoint)/eventlist/run" -Method post + $result.Result | Should -Be 'OK' + } + It 'Schedule updates state value - full cron' { $result = Invoke-RestMethod -Uri "$($Endpoint)/test1" -Method Get $result.Result | Should -Be 1337 } - It 'schedule updates state value - short cron' { + It 'Schedule updates state value - short cron' { $result = Invoke-RestMethod -Uri "$($Endpoint)/test2" -Method Get $result.Result | Should -Be 314 } - It 'schedule events' { - Invoke-RestMethod -Uri "$($Endpoint)/eventlist/run" -Method post - Start-Sleep 10 + It 'Check schedule events result' { + for ($i = 0; $i -lt 20; $i++) { $result = Invoke-RestMethod -Uri "$($Endpoint)/eventlist" -Method Get if ($result.ready) { @@ -118,7 +122,7 @@ Describe 'Schedules' { $result.Count | Should -Be 2 $result.eventList.GetType() | Should -Be 'System.Object[]' $result.eventList.Count | Should -Be 2 - $result.eventList[0].Message1 | Should -Be "Hello!" + $result.eventList[0].Message1 | Should -Be 'Hello!' $result.eventList[0].Message2 | Should -Be 'Bye!' $result.eventList[0].Message | Should -Be 'Hello, world!' $result.eventList[0].Last | Should -BeNullOrEmpty From d6a76e727fc0f4aeecd8f6e57bdd552ddebe1fb8 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sat, 21 Sep 2024 08:23:02 -0700 Subject: [PATCH 161/177] Fixes --- docs/Getting-Started/Debug.md | 8 ++++---- src/Private/FileWatchers.ps1 | 8 ++++++-- src/Private/PodeServer.ps1 | 16 ++++++++++++---- src/Private/Schedules.ps1 | 4 ++-- src/Private/SmtpServer.ps1 | 8 ++++++-- src/Private/TcpServer.ps1 | 8 ++++++-- src/Private/WebSockets.ps1 | 10 +++++++--- src/Public/Utilities.ps1 | 1 - 8 files changed, 43 insertions(+), 20 deletions(-) diff --git a/docs/Getting-Started/Debug.md b/docs/Getting-Started/Debug.md index 50bb23a60..0baef9a75 100644 --- a/docs/Getting-Started/Debug.md +++ b/docs/Getting-Started/Debug.md @@ -177,9 +177,9 @@ The steps to attach to the Pode process are as follows: -## Customizing and Managing Runspace Names in Pode +## Managing Runspace Names -### Distinguishing Runspace Names in Pode +### Internal Runspace Naming In Pode, internal runspaces are automatically assigned distinct names. This built-in naming convention is crucial for identifying and managing runspaces efficiently, particularly during debugging or when monitoring multiple concurrent processes. @@ -209,7 +209,7 @@ Set-PodeCurrentRunspaceName -Name 'Custom Runspace Name' This cmdlet sets a custom name for the runspace, making it easier to track during execution. -### Example +#### Example Here’s an example that demonstrates how to set a custom runspace name in a Pode task: @@ -235,7 +235,7 @@ Get-PodeCurrentRunspaceName This cmdlet returns the name of the current runspace, allowing for easier tracking and management in complex scenarios with multiple concurrent runspaces. -### Example +#### Example Here’s an example that uses `Get-PodeCurrentRunspaceName` to output the runspace name during the execution of a schedule: diff --git a/src/Private/FileWatchers.ps1 b/src/Private/FileWatchers.ps1 index 8bb919d15..ce0ebc4c7 100644 --- a/src/Private/FileWatchers.ps1 +++ b/src/Private/FileWatchers.ps1 @@ -54,7 +54,11 @@ function Start-PodeFileWatcherRunspace { $watchScript = { param( [Parameter(Mandatory = $true)] - $Watcher + $Watcher, + + [Parameter(Mandatory = $true)] + [int] + $ThreadId ) try { @@ -129,7 +133,7 @@ function Start-PodeFileWatcherRunspace { } 1..$PodeContext.Threads.Files | ForEach-Object { - Add-PodeRunspace -Type Files -Name 'Watcher' -Id $_ -ScriptBlock $watchScript -Parameters @{ 'Watcher' = $watcher } + Add-PodeRunspace -Type Files -Name 'Watcher' -Id $_ -ScriptBlock $watchScript -Parameters @{ 'Watcher' = $watcher ; 'ThreadId' = $_ } } # script to keep file watcher server alive until cancelled diff --git a/src/Private/PodeServer.ps1 b/src/Private/PodeServer.ps1 index 7f3ffa5fa..776438654 100644 --- a/src/Private/PodeServer.ps1 +++ b/src/Private/PodeServer.ps1 @@ -108,7 +108,11 @@ function Start-PodeWebServer { $listenScript = { param( [Parameter(Mandatory = $true)] - $Listener + $Listener, + + [Parameter(Mandatory = $true)] + [int] + $ThreadId ) try { @@ -276,7 +280,7 @@ function Start-PodeWebServer { # start the runspace for listening on x-number of threads 1..$PodeContext.Threads.General | ForEach-Object { - Add-PodeRunspace -Type Web -Name 'Listener' -Id $_ -ScriptBlock $listenScript -Parameters @{ 'Listener' = $listener } + Add-PodeRunspace -Type Web -Name 'Listener' -Id $_ -ScriptBlock $listenScript -Parameters @{ 'Listener' = $listener; 'ThreadId' = $_ } } } @@ -360,7 +364,11 @@ function Start-PodeWebServer { $clientScript = { param( [Parameter(Mandatory = $true)] - $Listener + $Listener, + + [Parameter(Mandatory = $true)] + [int] + $ThreadId ) try { @@ -430,7 +438,7 @@ function Start-PodeWebServer { # start the runspace for listening on x-number of threads 1..$PodeContext.Threads.General | ForEach-Object { - Add-PodeRunspace -Type Signals -Name 'Broadcaster' -Id $_ -ScriptBlock $clientScript -Parameters @{ 'Listener' = $listener } + Add-PodeRunspace -Type Signals -Name 'Broadcaster' -Id $_ -ScriptBlock $clientScript -Parameters @{ 'Listener' = $listener; 'ThreadId' = $_ } } } diff --git a/src/Private/Schedules.ps1 b/src/Private/Schedules.ps1 index 4c3c5bf32..924a888d2 100644 --- a/src/Private/Schedules.ps1 +++ b/src/Private/Schedules.ps1 @@ -13,13 +13,13 @@ function Test-PodeSchedulesExist { return (($null -ne $PodeContext.Schedules) -and (($PodeContext.Schedules.Enabled) -or ($PodeContext.Schedules.Items.Count -gt 0))) } function Start-PodeScheduleRunspace { + if (!(Test-PodeSchedulesExist)) { return } Add-PodeTimer -Name '__pode_schedule_housekeeper__' -Interval 30 -ScriptBlock { try { - if ($PodeContext.Schedules.Processes.Count -eq 0) { return } @@ -106,7 +106,7 @@ function Start-PodeScheduleRunspace { } } - Add-PodeRunspace -Type Main -Name 'ScheduleHouseKeeper' -ScriptBlock $script -NoProfile + Add-PodeRunspace -Type Main -Name 'Schedules' -ScriptBlock $script -NoProfile } function Close-PodeScheduleInternal { diff --git a/src/Private/SmtpServer.ps1 b/src/Private/SmtpServer.ps1 index 354b353a4..c3cc7cfd2 100644 --- a/src/Private/SmtpServer.ps1 +++ b/src/Private/SmtpServer.ps1 @@ -82,7 +82,11 @@ function Start-PodeSmtpServer { param( [Parameter(Mandatory = $true)] [ValidateNotNull()] - $Listener + $Listener, + + [Parameter(Mandatory = $true)] + [int] + $ThreadId ) try { @@ -173,7 +177,7 @@ function Start-PodeSmtpServer { # start the runspace for listening on x-number of threads 1..$PodeContext.Threads.General | ForEach-Object { - Add-PodeRunspace -Type Smtp -Name 'Listener' -Id $_ -ScriptBlock $listenScript -Parameters @{ 'Listener' = $listener } + Add-PodeRunspace -Type Smtp -Name 'Listener' -Id $_ -ScriptBlock $listenScript -Parameters @{ 'Listener' = $listener; 'ThreadId' = $_ } } # script to keep smtp server listening until cancelled diff --git a/src/Private/TcpServer.ps1 b/src/Private/TcpServer.ps1 index 6562b60c7..43a3c38c5 100644 --- a/src/Private/TcpServer.ps1 +++ b/src/Private/TcpServer.ps1 @@ -78,7 +78,11 @@ function Start-PodeTcpServer { param( [Parameter(Mandatory = $true)] [ValidateNotNull()] - $Listener + $Listener, + + [Parameter(Mandatory = $true)] + [int] + $ThreadId ) try { @@ -191,7 +195,7 @@ function Start-PodeTcpServer { # start the runspace for listening on x-number of threads 1..$PodeContext.Threads.General | ForEach-Object { - Add-PodeRunspace -Type Tcp -Name 'Listener' -Id $_ -ScriptBlock $listenScript -Parameters @{ 'Listener' = $listener } + Add-PodeRunspace -Type Tcp -Name 'Listener' -Id $_ -ScriptBlock $listenScript -Parameters @{ 'Listener' = $listener; 'ThreadId' = $_ } } # script to keep tcp server listening until cancelled diff --git a/src/Private/WebSockets.ps1 b/src/Private/WebSockets.ps1 index 963c66420..b1c0cdc8f 100644 --- a/src/Private/WebSockets.ps1 +++ b/src/Private/WebSockets.ps1 @@ -39,12 +39,16 @@ function Start-PodeWebSocketRunspace { return } - # script for listening out of for incoming requests + # script for listening out of for incoming requests (Receiver) $receiveScript = { param( [Parameter(Mandatory = $true)] [ValidateNotNull()] - $Receiver + $Receiver, + + [Parameter(Mandatory = $true)] + [int] + $ThreadId ) try { @@ -103,7 +107,7 @@ function Start-PodeWebSocketRunspace { # start the runspace for listening on x-number of threads 1..$PodeContext.Threads.WebSockets | ForEach-Object { - Add-PodeRunspace -Type WebSockets -Name 'Listener' -Id $_ -ScriptBlock $receiveScript -Parameters @{ 'Receiver' = $PodeContext.Server.WebSockets.Receiver } + Add-PodeRunspace -Type WebSockets -Name 'Receiver' -Id $_ -ScriptBlock $receiveScript -Parameters @{ 'Receiver' = $PodeContext.Server.WebSockets.Receiver; 'ThreadId' = $_ } } # script to keep websocket server receiving until cancelled diff --git a/src/Public/Utilities.ps1 b/src/Public/Utilities.ps1 index c00b26eba..527a44840 100644 --- a/src/Public/Utilities.ps1 +++ b/src/Public/Utilities.ps1 @@ -1363,7 +1363,6 @@ function ConvertFrom-PodeXml { } } return $oHash - } <# From 679be68f540a47ee12371176f1284bc4fee2ca64 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sat, 21 Sep 2024 10:10:00 -0700 Subject: [PATCH 162/177] Update Core.ps1 --- src/Public/Core.ps1 | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Public/Core.ps1 b/src/Public/Core.ps1 index 4fc221668..3d609f763 100644 --- a/src/Public/Core.ps1 +++ b/src/Public/Core.ps1 @@ -142,9 +142,9 @@ function Start-PodeServer { if ($pipelineItemCount -gt 1) { throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) } # Store the name of the current runspace - $previousRunspaceName = Get-PodeCurrentRunspaceName - # Sets the name of the current runspace - Set-PodeCurrentRunspaceName -Name 'PodeServer' + $previousRunspaceName = Get-PodeCurrentRunspaceName + # Sets the name of the current runspace + Set-PodeCurrentRunspaceName -Name 'PodeServer' # ensure the session is clean $PodeContext = $null @@ -248,11 +248,12 @@ function Start-PodeServer { # clean the runspaces and tokens Close-PodeServerInternal -ShowDoneMessage:$ShowDoneMessage - # clean the session - $PodeContext = $null + # clean the session + $PodeContext = $null - # Restore the name of the current runspace - Set-PodeCurrentRunspaceName -Name $previousRunspaceName + # Restore the name of the current runspace + Set-PodeCurrentRunspaceName -Name $previousRunspaceName + } } } From ecda42139765ebb7a6b107a4fb0c762646ce8746 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Sat, 21 Sep 2024 18:42:43 +0100 Subject: [PATCH 163/177] #1354: fix retreiving domain name on mac --- src/Private/Authentication.ps1 | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Private/Authentication.ps1 b/src/Private/Authentication.ps1 index f179a5286..8ab0c00b3 100644 --- a/src/Private/Authentication.ps1 +++ b/src/Private/Authentication.ps1 @@ -2180,22 +2180,29 @@ function Get-PodeAuthADGroupAll { } function Get-PodeAuthDomainName { - if (Test-PodeIsUnix) { - $dn = (dnsdomainname) - if ([string]::IsNullOrWhiteSpace($dn)) { - $dn = (/usr/sbin/realm list --name-only) - } + $domain = $null - return $dn + if (Test-PodeIsMacOS) { + $domain = (scutil --dns | grep -m 1 'search domain\[0\]' | cut -d ':' -f 2) + } + elseif (Test-PodeIsUnix) { + $domain = (dnsdomainname) + if ([string]::IsNullOrWhiteSpace($domain)) { + $domain = (/usr/sbin/realm list --name-only) + } } else { $domain = $env:USERDNSDOMAIN if ([string]::IsNullOrWhiteSpace($domain)) { $domain = (Get-CimInstance -Class Win32_ComputerSystem -Verbose:$false).Domain } + } - return $domain + if (![string]::IsNullOrEmpty($domain)) { + $domain = $domain.Trim() } + + return $domain } function Find-PodeAuth { From 0a9ae4a16cca22e9eefaa9dc9719a771f0cfd103 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sat, 21 Sep 2024 14:40:19 -0700 Subject: [PATCH 164/177] Update Schedules.Tests.ps1 --- tests/integration/Schedules.Tests.ps1 | 47 +++++++++------------------ 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/tests/integration/Schedules.Tests.ps1 b/tests/integration/Schedules.Tests.ps1 index 74a53bd14..ab4e1f898 100644 --- a/tests/integration/Schedules.Tests.ps1 +++ b/tests/integration/Schedules.Tests.ps1 @@ -23,16 +23,14 @@ Describe 'Schedules' { Set-PodeState -Name 'test3' -Value @{eventList = @() } - Add-PodeSchedule -Name 'TestEvents' -Cron '* * * * *' -Limit 2 -ScriptBlock { - param($Event, $Message1, $Message2) + Add-PodeSchedule -Name 'TestEvents' -Cron '* * * * *' -Limit 2 -OnStart -ScriptBlock { + param($Event ) Lock-PodeObject -ScriptBlock { $test3 = (Get-PodeState -Name 'test3') $test3.eventList += @{ - message = 'Hello, world!' - 'Last' = $Event.Sender.LastTriggerTime - 'Next' = $Event.Sender.NextTriggerTime - 'Message1' = $Message1 - 'Message2' = $Message2 + message = 'Hello, world!' + 'Last' = $Event.Sender.LastTriggerTime + 'Next' = $Event.Sender.NextTriggerTime } } } @@ -50,16 +48,6 @@ Describe 'Schedules' { } } - - # adhoc invoke a schedule's logic - Add-PodeRoute -Method Post -Path '/eventlist/run' -ScriptBlock { - Invoke-PodeSchedule -Name 'TestEvents' -ArgumentList @{ - Message1 = 'Hello!' - Message2 = 'Bye!' - } - Write-PodeJsonResponse -Value ( @{Result = 'ok' } ) - } - # test1 Set-PodeState -Name 'Test1' -Value 0 Add-PodeSchedule -Name 'Test1' -Cron '* * * * *' -ScriptBlock { @@ -95,10 +83,6 @@ Describe 'Schedules' { Get-Job -Name 'Pode' | Remove-Job -Force } - It 'Invoke schedule events' { - $result = Invoke-RestMethod -Uri "$($Endpoint)/eventlist/run" -Method post - $result.Result | Should -Be 'OK' - } It 'Schedule updates state value - full cron' { $result = Invoke-RestMethod -Uri "$($Endpoint)/test1" -Method Get $result.Result | Should -Be 1337 @@ -122,17 +106,16 @@ Describe 'Schedules' { $result.Count | Should -Be 2 $result.eventList.GetType() | Should -Be 'System.Object[]' $result.eventList.Count | Should -Be 2 - $result.eventList[0].Message1 | Should -Be 'Hello!' - $result.eventList[0].Message2 | Should -Be 'Bye!' - $result.eventList[0].Message | Should -Be 'Hello, world!' - $result.eventList[0].Last | Should -BeNullOrEmpty - $result.eventList[0].next | Should -not -BeNullOrEmpty - - $result.eventList[1].Message1 | Should -BeNullOrEmpty - $result.eventList[1].Message2 | Should -BeNullOrEmpty - $result.eventList[1].Message | Should -Be 'Hello, world!' - $result.eventList[1].Last | Should -not -BeNullOrEmpty - $result.eventList[1].next | Should -not -BeNullOrEmpty + + + if ( $null -eq $result.eventList[0].Next ) { $index = 0 } else { $index = 1 } + $result.eventList[$index].Message | Should -Be 'Hello, world!' + $result.eventList[$index].Last | Should -not -BeNullOrEmpty + $result.eventList[$index].next | Should -BeNullOrEmpty + if ($index -eq 0) { $index = 1 }else { $index = 0 } + $result.eventList[$index].Message | Should -Be 'Hello, world!' + $result.eventList[$index].Last | Should -not -BeNullOrEmpty + $result.eventList[$index].next | Should -not -BeNullOrEmpty } } \ No newline at end of file From 88ada6d03c7a160301be72425fd6c4cc98335499 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Sun, 22 Sep 2024 11:11:14 +0100 Subject: [PATCH 165/177] #1361: replaces New-Object calls with new(), adds PSScriptAnalyzer to detect and flag --- .github/CONTRIBUTING.md | 13 ++++ .github/workflows/PSScriptAnalyzer.yml | 10 +-- .vscode/settings.json | 1 + PSScriptAnalyzerSettings.psd1 | 26 +++++-- analyzers/AvoidNewObjectRule.psm1 | 38 ++++++++++ docs/Servers/TCP.md | 22 +++--- .../Authentication/Inbuilt/UserFile.md | 34 ++++----- docs/Tutorials/Compression/Requests.md | 4 +- docs/Tutorials/Middleware/Types/Sessions.md | 2 +- examples/Web-Pages.ps1 | 9 ++- src/Private/Authentication.ps1 | 12 +-- src/Private/Context.ps1 | 76 ++++++++++--------- src/Private/FileMonitor.ps1 | 10 +-- src/Private/Helpers.ps1 | 16 ++-- src/Private/ScopedVariables.ps1 | 4 +- src/Private/Server.ps1 | 4 +- src/Private/Serverless.ps1 | 2 +- src/Private/Sessions.ps1 | 2 +- src/Private/Streams.ps1 | 38 +++++++++- src/Public/Responses.ps1 | 6 +- tests/integration/RestApi.Https.Tests.ps1 | 14 ++-- tests/integration/RestApi.Tests.ps1 | 12 +-- tests/unit/Logging.Tests.ps1 | 12 +-- tests/unit/Server.Tests.ps1 | 4 +- 24 files changed, 235 insertions(+), 136 deletions(-) create mode 100644 analyzers/AvoidNewObjectRule.psm1 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 9122555d5..b326b5548 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -30,6 +30,7 @@ The following is a set of guidelines for contributing to Pode on GitHub. These a - [Where-Object](#where-object) - [Select-Object](#select-object) - [Measure-Object](#measure-object) + - [New-Object](#new-object) ## Code of Conduct @@ -245,3 +246,15 @@ Instead of using the `Measure-Object` commandlet, please use either the `.Length (@(1, 2, 3)).Length (@{ Name = 'Rick' }).Count ``` + +#### New-Object + +Instead of using the `New-Object` commandlet, please use `::new()` as this is far faster than the former. + +```powershell +# instead of +$stream = New-Object System.IO.MemoryStream + +# do this +$stream = [System.IO.MemoryStream]::new() +``` diff --git a/.github/workflows/PSScriptAnalyzer.yml b/.github/workflows/PSScriptAnalyzer.yml index 8673d21f4..d1af32421 100644 --- a/.github/workflows/PSScriptAnalyzer.yml +++ b/.github/workflows/PSScriptAnalyzer.yml @@ -3,7 +3,7 @@ # separate terms of service, privacy policy, and support # documentation. # -# https://github.com/microsoft/action-psscriptanalyzer +# https://github.com/microsoft/psscriptanalyzer-action # For more information on PSScriptAnalyzer in general, see # https://github.com/PowerShell/PSScriptAnalyzer @@ -48,15 +48,11 @@ jobs: - name: Run PSScriptAnalyzer uses: microsoft/psscriptanalyzer-action@6b2948b1944407914a58661c49941824d149734f with: - # Check https://github.com/microsoft/action-psscriptanalyzer for more info about the options. - # The below set up runs PSScriptAnalyzer to your entire repository and runs some basic security rules. - path: .\ + path: .\src recurse: true - # Include your own basic security rules. Removing this option will run all the rules - includeRule: '"PSAvoidUsingCmdletAliases" ,"PSAvoidUsingPlainTextForPassword","PSAvoidUsingWriteHost","PSAvoidUsingInvokeExpression","PSUseShouldProcessForStateChangingFunctions","PSAvoidUsingUsernameAndPasswordParams","PSUseProcessBlockForPipelineCommand","PSAvoidUsingConvertToSecureStringWithPlainText","PSUseSingularNouns","PSReviewUnusedParameter"' + settings: .\PSScriptAnalyzerSettings.psd1 output: results.sarif - # Upload the SARIF file generated in the previous step - name: Upload SARIF results file uses: github/codeql-action/upload-sarif@v3 with: diff --git a/.vscode/settings.json b/.vscode/settings.json index 559d3ecf2..6f817660d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,6 +21,7 @@ "powershell.codeFormatting.whitespaceBetweenParameters": false, "powershell.codeFormatting.whitespaceInsideBrace": true, "powershell.scriptAnalysis.settingsPath": "PSScriptAnalyzerSettings.psd1", + "powershell.scriptAnalysis.enable": true, "files.trimTrailingWhitespace": true, "files.associations": { "*.pode": "html" diff --git a/PSScriptAnalyzerSettings.psd1 b/PSScriptAnalyzerSettings.psd1 index 751210939..5ae2be002 100644 --- a/PSScriptAnalyzerSettings.psd1 +++ b/PSScriptAnalyzerSettings.psd1 @@ -1,15 +1,29 @@ -# PSScriptAnalyzerSettings.psd1 @{ - Severity = @('Error', 'Warning', 'Information') + Severity = @('Error', 'Warning', 'Information') + IncludeDefaultRules = $true - Rules = @{ + CustomRulePath = @( + './analyzers/AvoidNewObjectRule.psm1' + ) + + Rules = @{ PSReviewUnusedParameter = @{ CommandsToTraverse = @( - 'Where-Object','Remove-PodeRoute' + 'Where-Object', + 'Remove-PodeRoute' ) } + AvoidNewObjectRule = @{ + Severity = 'Warning' + } } - ExcludeRules = @( 'PSAvoidUsingPlainTextForPassword','PSUseShouldProcessForStateChangingFunctions', - 'PSAvoidUsingUsernameAndPasswordParams','PSUseProcessBlockForPipelineCommand','PSAvoidUsingConvertToSecureStringWithPlainText','PSReviewUnusedParameter' ,'PSAvoidAssignmentToAutomaticVariable') + ExcludeRules = @( + 'PSAvoidUsingPlainTextForPassword', + 'PSUseShouldProcessForStateChangingFunctions', + 'PSAvoidUsingUsernameAndPasswordParams', + 'PSUseProcessBlockForPipelineCommand', + 'PSAvoidUsingConvertToSecureStringWithPlainText', + 'PSReviewUnusedParameter' + ) } \ No newline at end of file diff --git a/analyzers/AvoidNewObjectRule.psm1 b/analyzers/AvoidNewObjectRule.psm1 new file mode 100644 index 000000000..c6b47f231 --- /dev/null +++ b/analyzers/AvoidNewObjectRule.psm1 @@ -0,0 +1,38 @@ +function Measure-AvoidNewObjectRule { + [CmdletBinding()] + [OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]])] + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.Language.ScriptBlockAst] + $ScriptBlockAst + ) + + # Initialize an empty array to collect diagnostic records + $diagnostics = @() + + try { + # Traverse the AST to find all instances of New-Object cmdlet + $ScriptBlockAst.FindAll({ + param($Ast) + $Ast -is [System.Management.Automation.Language.CommandAst] -and + $Ast.CommandElements[0].Extent.Text -eq 'New-Object' + }, $true) | ForEach-Object { + $diagnostics += [PSCustomObject]@{ + Message = "Avoid using 'New-Object' and use '::new()' instead." + Extent = $_.Extent + RuleName = 'AvoidNewObjectRule' + Severity = 'Warning' + ScriptName = $FileName + } + } + + # Return the diagnostic records + return $diagnostics + } + catch { + $PSCmdlet.ThrowTerminatingError($PSItem) + } +} + +Export-ModuleMember -Function Measure-AvoidNewObjectRule \ No newline at end of file diff --git a/docs/Servers/TCP.md b/docs/Servers/TCP.md index 7a2acd44a..10425897c 100644 --- a/docs/Servers/TCP.md +++ b/docs/Servers/TCP.md @@ -172,14 +172,14 @@ Start-PodeServer { Verbs will be passed the `$TcpEvent` object, that contains the Request, Response, and other properties: -| Name | Type | Description | -| ---- | ---- | ----------- | -| Request | object | The raw Request object | -| Response | object | The raw Response object | -| Lockable | hashtable | A synchronized hashtable that can be used with `Lock-PodeObject` | -| Endpoint | hashtable | Contains the Address and Protocol of the endpoint being hit - such as "pode.example.com" or "127.0.0.2", or HTTP or HTTPS for the Protocol | -| Parameters | hashtable | Contains the parsed parameter values from the Verb's path | -| Timestamp | datetime | The current date and time of the Request | +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| Request | object | The raw Request object | +| Response | object | The raw Response object | +| Lockable | hashtable | A synchronized hashtable that can be used with `Lock-PodeObject` | +| Endpoint | hashtable | Contains the Address and Protocol of the endpoint being hit - such as "pode.example.com" or "127.0.0.2", or HTTP or HTTPS for the Protocol | +| Parameters | hashtable | Contains the parsed parameter values from the Verb's path | +| Timestamp | datetime | The current date and time of the Request | ## Test Send @@ -189,11 +189,11 @@ The following function can be used to test sending messages to a TCP server. Thi function Send-TCPMessage($Endpoint, $Port, $Message) { # Setup connection $Address = [System.Net.IPAddress]::Parse([System.Net.Dns]::GetHostAddresses($EndPoint)) - $Socket = New-Object System.Net.Sockets.TCPClient($Address,$Port) + $Socket = [System.Net.Sockets.TcpClient]::new($Address, $Port) - # Setup stream wrtier + # Setup stream writer $Stream = $Socket.GetStream() - $Writer = New-Object System.IO.StreamWriter($Stream) + $Writer = [System.IO.StreamWriter]::new($Stream) # Write message to stream $Writer.WriteLine($Message) diff --git a/docs/Tutorials/Authentication/Inbuilt/UserFile.md b/docs/Tutorials/Authentication/Inbuilt/UserFile.md index 564c54dbc..4b9109809 100644 --- a/docs/Tutorials/Authentication/Inbuilt/UserFile.md +++ b/docs/Tutorials/Authentication/Inbuilt/UserFile.md @@ -20,14 +20,14 @@ The default users file is `./users.json` at the root of the server. You can supp The users file is a JSON array of user objects, each user object must contain the following (metadata is optional): -| Name | Type | Description | -| ---- | ---- | ----------- | -| Username | string | The user's username | -| Name | string | The user's fullname | -| Email | string | The user's email address | -| Password | string | Either a SHA256 or an HMAC SHA256 of the user's password | -| Groups | string[] | An array of groups which the the user is a member | -| Metadata | psobject | Custom metadata for the user | +| Name | Type | Description | +| -------- | -------- | -------------------------------------------------------- | +| Username | string | The user's username | +| Name | string | The user's fullname | +| Email | string | The user's email address | +| Password | string | Either a SHA256 or an HMAC SHA256 of the user's password | +| Groups | string[] | An array of groups which the the user is a member | +| Metadata | psobject | Custom metadata for the user | For example: @@ -66,7 +66,7 @@ Regardless of whether the password is a standard SHA256 hash or HMAC hash, the h ```powershell function ConvertTo-SHA256([string]$String) { - $SHA256 = New-Object System.Security.Cryptography.SHA256Managed + $SHA256 = [System.Security.Cryptography.SHA256Managed]::new() $SHA256Hash = $SHA256.ComputeHash([Text.Encoding]::ASCII.GetBytes($String)) $SHA256HashString = [Convert]::ToBase64String($SHA256Hash) return $SHA256HashString @@ -77,7 +77,7 @@ function ConvertTo-SHA256([string]$String) ```powershell function ConvertTo-HMACSHA256([string]$String, [string]$Secret) { - $HMACSHA256 = New-Object System.Security.Cryptography.HMACSHA256 + $HMACSHA256 = [System.Security.Cryptography.HMACSHA256]::new() $HMACSHA256.Secret = [Text.Encoding]::ASCII.GetBytes($Secret) $HMACSHA256Hash = $HMACSHA256.ComputeHash([Text.Encoding]::ASCII.GetBytes($String)) $HMACSHA256HashString = [Convert]::ToBase64String($HMACSHA256Hash) @@ -89,13 +89,13 @@ function ConvertTo-HMACSHA256([string]$String, [string]$Secret) { The User object returned, and accessible on Routes, and other functions via the [web event](../../../WebEvent)'s `$WebEvent.Auth.User` property, will contain the following information: -| Name | Type | Description | -| ---- | ---- | ----------- | -| Username | string | The user's username | -| Name | string | The user's fullname | -| Email | string | The user's email address | -| Groups | string[] | An array of groups which the the user is a member | -| Metadata | psobject | Custom metadata for the user | +| Name | Type | Description | +| -------- | -------- | ------------------------------------------------- | +| Username | string | The user's username | +| Name | string | The user's fullname | +| Email | string | The user's email address | +| Groups | string[] | An array of groups which the the user is a member | +| Metadata | psobject | Custom metadata for the user | Such as: diff --git a/docs/Tutorials/Compression/Requests.md b/docs/Tutorials/Compression/Requests.md index 804cea5e8..f5604a307 100644 --- a/docs/Tutorials/Compression/Requests.md +++ b/docs/Tutorials/Compression/Requests.md @@ -94,8 +94,8 @@ $message = ($data | ConvertTo-Json) $bytes = [System.Text.Encoding]::UTF8.GetBytes($message) # compress the message using gzip -$ms = New-Object -TypeName System.IO.MemoryStream -$gzip = New-Object System.IO.Compression.GZipStream($ms, [IO.Compression.CompressionMode]::Compress, $true) +$ms = [System.IO.MemoryStream]::new() +$gzip = [System.IO.Compression.GZipStream]::new($ms, [IO.Compression.CompressionMode]::Compress, $true) $gzip.Write($bytes, 0, $bytes.Length) $gzip.Close() $ms.Position = 0 diff --git a/docs/Tutorials/Middleware/Types/Sessions.md b/docs/Tutorials/Middleware/Types/Sessions.md index ba622c0e2..90221f1dc 100644 --- a/docs/Tutorials/Middleware/Types/Sessions.md +++ b/docs/Tutorials/Middleware/Types/Sessions.md @@ -111,7 +111,7 @@ For example, the following is a mock up of a Storage for Redis. Note that the fu ```powershell # create the object -$store = New-Object -TypeName psobject +$store = [psobject]::new() # add a Get property for retreiving a session's data by SessionId $store | Add-Member -MemberType NoteProperty -Name Get -Value { diff --git a/examples/Web-Pages.ps1 b/examples/Web-Pages.ps1 index 275b100b1..9cd174a25 100644 --- a/examples/Web-Pages.ps1 +++ b/examples/Web-Pages.ps1 @@ -43,10 +43,12 @@ try { # Import the Pode module from the source path if it exists, otherwise from installed modules if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop - } else { + } + else { Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop } -} catch { throw } +} +catch { throw } # or just: # Import-Module Pode @@ -117,7 +119,8 @@ Start-PodeServer -Threads 2 -Verbose { Add-PodeRoute -Method Get -Path '/redirect-port' -ScriptBlock { if ($WebEvent.Request.Url.Port -ne 8086) { Move-PodeResponseUrl -Port 8086 - } else { + } + else { Write-PodeJsonResponse -Value @{ 'value' = 'you got redirected!'; } } } diff --git a/src/Private/Authentication.ps1 b/src/Private/Authentication.ps1 index f179a5286..3f3e998a3 100644 --- a/src/Private/Authentication.ps1 +++ b/src/Private/Authentication.ps1 @@ -947,7 +947,7 @@ function Get-PodeAuthWindowsADIISMethod { try { # parse the auth token and get the user $winAuthToken = [System.IntPtr][Int]"0x$($token)" - $winIdentity = New-Object System.Security.Principal.WindowsIdentity($winAuthToken, 'Windows') + $winIdentity = [System.Security.Principal.WindowsIdentity]::new($winAuthToken, 'Windows') # get user and domain $username = ($winIdentity.Name -split '\\')[-1] @@ -1902,10 +1902,10 @@ function Open-PodeAuthADConnection { 'directoryservices' { if ([string]::IsNullOrWhiteSpace($Password)) { - $ad = (New-Object System.DirectoryServices.DirectoryEntry "$($Protocol)://$($Server)") + $ad = [System.DirectoryServices.DirectoryEntry]::new("$($Protocol)://$($Server)") } else { - $ad = (New-Object System.DirectoryServices.DirectoryEntry "$($Protocol)://$($Server)", "$($Username)", "$($Password)") + $ad = [System.DirectoryServices.DirectoryEntry]::new("$($Protocol)://$($Server)", "$($Username)", "$($Password)") } if (Test-PodeIsEmpty $ad.distinguishedName) { @@ -1978,7 +1978,7 @@ function Get-PodeAuthADUser { } 'directoryservices' { - $Connection.Searcher = New-Object System.DirectoryServices.DirectorySearcher $Connection.Entry + $Connection.Searcher = [System.DirectoryServices.DirectorySearcher]::new($Connection.Entry) $Connection.Searcher.filter = $query $result = $Connection.Searcher.FindOne().Properties @@ -2118,7 +2118,7 @@ function Get-PodeAuthADGroupDirect { 'directoryservices' { if ($null -eq $Connection.Searcher) { - $Connection.Searcher = New-Object System.DirectoryServices.DirectorySearcher $Connection.Entry + $Connection.Searcher = [System.DirectoryServices.DirectorySearcher]::new($Connection.Entry) } $Connection.Searcher.filter = $query @@ -2167,7 +2167,7 @@ function Get-PodeAuthADGroupAll { 'directoryservices' { if ($null -eq $Connection.Searcher) { - $Connection.Searcher = New-Object System.DirectoryServices.DirectorySearcher $Connection.Entry + $Connection.Searcher = [System.DirectoryServices.DirectorySearcher]::new($Connection.Entry) } $null = $Connection.Searcher.PropertiesToLoad.Add('samaccountname') diff --git a/src/Private/Context.ps1 b/src/Private/Context.ps1 index 28584fa42..4e38b56d8 100644 --- a/src/Private/Context.ps1 +++ b/src/Private/Context.ps1 @@ -67,23 +67,24 @@ function New-PodeContext { } # basic context object - $ctx = New-Object -TypeName psobject | - Add-Member -MemberType NoteProperty -Name Threads -Value @{} -PassThru | - Add-Member -MemberType NoteProperty -Name Timers -Value @{} -PassThru | - Add-Member -MemberType NoteProperty -Name Schedules -Value @{} -PassThru | - Add-Member -MemberType NoteProperty -Name Tasks -Value @{} -PassThru | - Add-Member -MemberType NoteProperty -Name RunspacePools -Value $null -PassThru | - Add-Member -MemberType NoteProperty -Name Runspaces -Value $null -PassThru | - Add-Member -MemberType NoteProperty -Name RunspaceState -Value $null -PassThru | - Add-Member -MemberType NoteProperty -Name Tokens -Value @{} -PassThru | - Add-Member -MemberType NoteProperty -Name LogsToProcess -Value $null -PassThru | - Add-Member -MemberType NoteProperty -Name Threading -Value @{} -PassThru | - Add-Member -MemberType NoteProperty -Name Server -Value @{} -PassThru | - Add-Member -MemberType NoteProperty -Name Metrics -Value @{} -PassThru | - Add-Member -MemberType NoteProperty -Name Listeners -Value @() -PassThru | - Add-Member -MemberType NoteProperty -Name Receivers -Value @() -PassThru | - Add-Member -MemberType NoteProperty -Name Watchers -Value @() -PassThru | - Add-Member -MemberType NoteProperty -Name Fim -Value @{} -PassThru + $ctx = [PSCustomObject]@{ + Threads = @{} + Timers = @{} + Schedules = @{} + Tasks = @{} + RunspacePools = $null + Runspaces = $null + RunspaceState = $null + Tokens = @{} + LogsToProcess = $null + Threading = @{} + Server = @{} + Metrics = @{} + Listeners = @() + Receivers = @() + Watchers = @() + Fim = @{} + } # set the server name, logic and root, and other basic properties $ctx.Server.Name = $Name @@ -276,7 +277,7 @@ function New-PodeContext { $ctx.Server.EndpointsMap = @{} # general encoding for the server - $ctx.Server.Encoding = New-Object System.Text.UTF8Encoding + $ctx.Server.Encoding = [System.Text.UTF8Encoding]::new() # setup gui details $ctx.Server.Gui = @{} @@ -403,12 +404,12 @@ function New-PodeContext { # create new cancellation tokens $ctx.Tokens = @{ - Cancellation = New-Object System.Threading.CancellationTokenSource - Restart = New-Object System.Threading.CancellationTokenSource + Cancellation = [System.Threading.CancellationTokenSource]::new() + Restart = [System.Threading.CancellationTokenSource]::new() } # requests that should be logged - $ctx.LogsToProcess = New-Object System.Collections.ArrayList + $ctx.LogsToProcess = [System.Collections.ArrayList]::new() # middleware that needs to run $ctx.Server.Middleware = @() @@ -495,10 +496,10 @@ function New-PodeRunspaceState { $session = New-PodeStateContext -Context $PodeContext $variables = @( - (New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'PodeLocale', $PodeLocale, $null), - (New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'PodeContext', $session, $null), - (New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'Console', $Host, $null), - (New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'PODE_SCOPE_RUNSPACE', $true, $null) + [System.Management.Automation.Runspaces.SessionStateVariableEntry]::new('PodeLocale', $PodeLocale, $null), + [System.Management.Automation.Runspaces.SessionStateVariableEntry]::new('PodeContext', $session, $null), + [System.Management.Automation.Runspaces.SessionStateVariableEntry]::new('Console', $Host, $null), + [System.Management.Automation.Runspaces.SessionStateVariableEntry]::new('PODE_SCOPE_RUNSPACE', $true, $null) ) foreach ($var in $variables) { @@ -783,18 +784,19 @@ function New-PodeStateContext { $Context ) - return (New-Object -TypeName psobject | - Add-Member -MemberType NoteProperty -Name Threads -Value $Context.Threads -PassThru | - Add-Member -MemberType NoteProperty -Name Timers -Value $Context.Timers -PassThru | - Add-Member -MemberType NoteProperty -Name Schedules -Value $Context.Schedules -PassThru | - Add-Member -MemberType NoteProperty -Name Tasks -Value $Context.Tasks -PassThru | - Add-Member -MemberType NoteProperty -Name Fim -Value $Context.Fim -PassThru | - Add-Member -MemberType NoteProperty -Name RunspacePools -Value $Context.RunspacePools -PassThru | - Add-Member -MemberType NoteProperty -Name Tokens -Value $Context.Tokens -PassThru | - Add-Member -MemberType NoteProperty -Name Metrics -Value $Context.Metrics -PassThru | - Add-Member -MemberType NoteProperty -Name LogsToProcess -Value $Context.LogsToProcess -PassThru | - Add-Member -MemberType NoteProperty -Name Threading -Value $Context.Threading -PassThru | - Add-Member -MemberType NoteProperty -Name Server -Value $Context.Server -PassThru) + return [PSCustomObject]@{ + Threads = $Context.Threads + Timers = $Context.Timers + Schedules = $Context.Schedules + Tasks = $Context.Tasks + Fim = $Context.Fim + RunspacePools = $Context.RunspacePools + Tokens = $Context.Tokens + Metrics = $Context.Metrics + LogsToProcess = $Context.LogsToProcess + Threading = $Context.Threading + Server = $Context.Server + } } function Open-PodeConfiguration { diff --git a/src/Private/FileMonitor.ps1 b/src/Private/FileMonitor.ps1 index 7ebfcdc9d..7b9fae009 100644 --- a/src/Private/FileMonitor.ps1 +++ b/src/Private/FileMonitor.ps1 @@ -9,15 +9,13 @@ function Start-PodeFileMonitor { $filter = '*.*' # setup the file monitor - $watcher = New-Object System.IO.FileSystemWatcher $folder, $filter -Property @{ - IncludeSubdirectories = $true - NotifyFilter = [System.IO.NotifyFilters]'FileName,LastWrite,CreationTime' - } - + $watcher = [System.IO.FileSystemWatcher]::new($folder, $filter) + $watcher.IncludeSubdirectories = $true + $watcher.NotifyFilter = [System.IO.NotifyFilters]'FileName,LastWrite,CreationTime' $watcher.EnableRaisingEvents = $true # setup the monitor timer - only restart server after changes + 2s of no changes - $timer = New-Object System.Timers.Timer + $timer = [System.Timers.Timer]::new() $timer.AutoReset = $false $timer.Interval = 2000 diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index ff45ce5a1..bc2d154d9 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -152,7 +152,7 @@ function Test-PodeIsAdminUser { } try { - $principal = New-Object System.Security.Principal.WindowsPrincipal([System.Security.Principal.WindowsIdentity]::GetCurrent()) + $principal = [System.Security.Principal.WindowsPrincipal]::new([System.Security.Principal.WindowsIdentity]::GetCurrent()) if ($null -eq $principal) { return $false } @@ -550,7 +550,7 @@ function Get-PodeSubnetRange { 'IP' = ($ip_parts -join '.') } } - + function Get-PodeConsoleKey { if ([Console]::IsInputRedirected -or ![Console]::KeyAvailable) { @@ -1477,7 +1477,7 @@ function ConvertTo-PodeResponseContent { { $_ -match '^(.*\/)?(.*\+)?xml$' } { if ($InputObject -isnot [string]) { $temp = @(foreach ($item in $InputObject) { - New-Object psobject -Property $item + [pscustomobject]$item }) return ($temp | ConvertTo-Xml -Depth $Depth -As String -NoTypeInformation) @@ -1491,7 +1491,7 @@ function ConvertTo-PodeResponseContent { { $_ -ilike '*/csv' } { if ($InputObject -isnot [string]) { $temp = @(foreach ($item in $InputObject) { - New-Object psobject -Property $item + [pscustomobject]$item }) if (Test-PodeIsPSCore) { @@ -1575,10 +1575,10 @@ function ConvertFrom-PodeRequestContent { # if the request is compressed, attempt to uncompress it if (![string]::IsNullOrWhiteSpace($TransferEncoding)) { # create a compressed stream to decompress the req bytes - $ms = New-Object -TypeName System.IO.MemoryStream + $ms = [System.IO.MemoryStream]::new() $ms.Write($Request.RawBody, 0, $Request.RawBody.Length) $null = $ms.Seek(0, 0) - $stream = New-Object "System.IO.Compression.$($TransferEncoding)Stream"($ms, [System.IO.Compression.CompressionMode]::Decompress) + $stream = Get-PodeCompressionStream -InputStream $ms -Encoding $TransferEncoding -Mode Decompress # read the decompressed bytes $Content = Read-PodeStreamToEnd -Stream $stream -Encoding $Request.ContentEncoding @@ -3724,7 +3724,7 @@ function Resolve-PodeObjectArray { if ($Property -is [hashtable]) { # If the hashtable has only one item, convert it to a PowerShell object if ($Property.Count -eq 1) { - return New-Object psobject -Property $Property + return [pscustomobject]$Property } else { # If the hashtable has more than one item, recursively resolve each item @@ -3746,6 +3746,6 @@ function Resolve-PodeObjectArray { } else { # For any other type, convert it to a PowerShell object - return New-Object psobject -Property $Property + return [pscustomobject]$Property } } \ No newline at end of file diff --git a/src/Private/ScopedVariables.ps1 b/src/Private/ScopedVariables.ps1 index 062546864..cf06304e4 100644 --- a/src/Private/ScopedVariables.ps1 +++ b/src/Private/ScopedVariables.ps1 @@ -305,8 +305,8 @@ function Convert-PodeScopedVariableUsingVariable { $UsingVariables ) # Create a list of variable expressions for replacement - $varsList = New-Object 'System.Collections.Generic.List`1[System.Management.Automation.Language.VariableExpressionAst]' - $newParams = New-Object System.Collections.ArrayList + $varsList = [System.Collections.Generic.List[System.Management.Automation.Language.VariableExpressionAst]]::new() + $newParams = [System.Collections.ArrayList]::new() foreach ($usingVar in $UsingVariables) { foreach ($subExp in $usingVar.SubExpressions) { diff --git a/src/Private/Server.ps1 b/src/Private/Server.ps1 index 63b63f8a9..547c3fa60 100644 --- a/src/Private/Server.ps1 +++ b/src/Private/Server.ps1 @@ -331,10 +331,10 @@ function Restart-PodeInternalServer { # recreate the session tokens Close-PodeDisposable -Disposable $PodeContext.Tokens.Cancellation - $PodeContext.Tokens.Cancellation = New-Object System.Threading.CancellationTokenSource + $PodeContext.Tokens.Cancellation = [System.Threading.CancellationTokenSource]::new() Close-PodeDisposable -Disposable $PodeContext.Tokens.Restart - $PodeContext.Tokens.Restart = New-Object System.Threading.CancellationTokenSource + $PodeContext.Tokens.Restart = [System.Threading.CancellationTokenSource]::new() # reload the configuration $PodeContext.Server.Configuration = Open-PodeConfiguration -Context $PodeContext diff --git a/src/Private/Serverless.ps1 b/src/Private/Serverless.ps1 index 98a178718..7bf51f3b8 100644 --- a/src/Private/Serverless.ps1 +++ b/src/Private/Serverless.ps1 @@ -22,7 +22,7 @@ function Start-PodeAzFuncServer { $request = $Data.Request # setup the response - $response = New-Object -TypeName HttpResponseContext + $response = [HttpResponseContext]::new() $response.StatusCode = 200 $response.Headers = @{} diff --git a/src/Private/Sessions.ps1 b/src/Private/Sessions.ps1 index 4be09c45e..4e9bc870c 100644 --- a/src/Private/Sessions.ps1 +++ b/src/Private/Sessions.ps1 @@ -232,7 +232,7 @@ function Remove-PodeSessionInternal { } function Get-PodeSessionInMemStore { - $store = New-Object -TypeName psobject + $store = [psobject]::new() # add in-mem storage $store | Add-Member -MemberType NoteProperty -Name Memory -Value @{} diff --git a/src/Private/Streams.ps1 b/src/Private/Streams.ps1 index 98bbf9d22..d8e007187 100644 --- a/src/Private/Streams.ps1 +++ b/src/Private/Streams.ps1 @@ -125,7 +125,7 @@ function ConvertFrom-PodeValueToByteArray { # Initialize a buffer to read data in chunks $buffer = [byte[]]::new(64 * 1024) - $ms = New-Object -TypeName System.IO.MemoryStream + $ms = [System.IO.MemoryStream]::new() $read = 0 # Read data from the stream and write it to the memory stream @@ -289,4 +289,38 @@ function Remove-PodeNewLineBytesFromArray { } return $Bytes[0..$length] -} \ No newline at end of file +} + +function Get-PodeCompressionStream { + param ( + [Parameter(Mandatory = $true)] + [System.IO.Stream] + $InputStream, + + [Parameter(Mandatory = $true)] + [ValidateSet('gzip', 'deflate')] + [string] + $Encoding, + + [Parameter(Mandatory = $true)] + [System.IO.Compression.CompressionMode] + $Mode + ) + + $leaveOpen = $Mode -eq [System.IO.Compression.CompressionMode]::Compress + + switch ($Encoding.ToLower()) { + 'gzip' { + return [System.IO.Compression.GZipStream]::new($InputStream, $Mode, $leaveOpen) + } + + 'deflate' { + return [System.IO.Compression.DeflateStream]::new($InputStream, $Mode, $leaveOpen) + } + + default { + #TODO: localize + throw "Unsupported encoding: $Encoding" + } + } +} diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index e46bb932a..84738c2ff 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -249,8 +249,8 @@ function Write-PodeTextResponse { # check if we need to compress the response if ($PodeContext.Server.Web.Compression.Enabled -and ![string]::IsNullOrWhiteSpace($WebEvent.AcceptEncoding)) { try { - $ms = New-Object -TypeName System.IO.MemoryStream - $stream = New-Object "System.IO.Compression.$($WebEvent.AcceptEncoding)Stream"($ms, [System.IO.Compression.CompressionMode]::Compress, $true) + $ms = [System.IO.MemoryStream]::new() + $stream = Get-PodeCompressionStream -InputStream $ms -Encoding $WebEvent.AcceptEncoding -Mode Compress $stream.Write($Bytes, 0, $Bytes.Length) $stream.Close() $ms.Position = 0 @@ -274,7 +274,7 @@ function Write-PodeTextResponse { $res.ContentLength64 = $Bytes.Length try { - $ms = New-Object -TypeName System.IO.MemoryStream + $ms = [System.IO.MemoryStream]::new() $ms.Write($Bytes, 0, $Bytes.Length) $ms.WriteTo($res.OutputStream) } diff --git a/tests/integration/RestApi.Https.Tests.ps1 b/tests/integration/RestApi.Https.Tests.ps1 index 0e9184124..c40e898cc 100644 --- a/tests/integration/RestApi.Https.Tests.ps1 +++ b/tests/integration/RestApi.Https.Tests.ps1 @@ -21,7 +21,7 @@ Describe 'REST API Requests' { } } '@ - [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy + [System.Net.ServicePointManager]::CertificatePolicy = [TrustAllCertsPolicy]::new() } else { if ($version -ge [version]'7.4.0') { @@ -279,8 +279,8 @@ Describe 'REST API Requests' { # compress the message using gzip $bytes = [System.Text.Encoding]::UTF8.GetBytes($message) - $ms = New-Object -TypeName System.IO.MemoryStream - $gzip = New-Object System.IO.Compression.GZipStream($ms, [IO.Compression.CompressionMode]::Compress, $true) + $ms = [System.IO.MemoryStream]::new() + $gzip = [System.IO.Compression.GZipStream]::new($ms, [IO.Compression.CompressionMode]::Compress, $true) $gzip.Write($bytes, 0, $bytes.Length) $gzip.Close() @@ -317,8 +317,8 @@ Describe 'REST API Requests' { # compress the message using deflate $bytes = [System.Text.Encoding]::UTF8.GetBytes($message) - $ms = New-Object -TypeName System.IO.MemoryStream - $deflate = New-Object System.IO.Compression.DeflateStream($ms, [IO.Compression.CompressionMode]::Compress, $true) + $ms = [System.IO.MemoryStream]::new() + $deflate = [System.IO.Compression.DeflateStream]::new($ms, [IO.Compression.CompressionMode]::Compress, $true) $deflate.Write($bytes, 0, $bytes.Length) $deflate.Close() @@ -356,8 +356,8 @@ Describe 'REST API Requests' { # compress the message using gzip $bytes = [System.Text.Encoding]::UTF8.GetBytes($message) - $ms = New-Object -TypeName System.IO.MemoryStream - $gzip = New-Object System.IO.Compression.GZipStream($ms, [IO.Compression.CompressionMode]::Compress, $true) + $ms = [System.IO.MemoryStream]::new() + $gzip = [System.IO.Compression.GZipStream]::new($ms, [IO.Compression.CompressionMode]::Compress, $true) $gzip.Write($bytes, 0, $bytes.Length) $gzip.Close() diff --git a/tests/integration/RestApi.Tests.ps1 b/tests/integration/RestApi.Tests.ps1 index 4bd8a4233..e2fd92cde 100644 --- a/tests/integration/RestApi.Tests.ps1 +++ b/tests/integration/RestApi.Tests.ps1 @@ -167,8 +167,8 @@ Describe 'REST API Requests' { # compress the message using gzip $bytes = [System.Text.Encoding]::UTF8.GetBytes($message) - $ms = New-Object -TypeName System.IO.MemoryStream - $gzip = New-Object System.IO.Compression.GZipStream($ms, [IO.Compression.CompressionMode]::Compress, $true) + $ms = [System.IO.MemoryStream]::new() + $gzip = [System.IO.Compression.GZipStream]::new($ms, [IO.Compression.CompressionMode]::Compress, $true) $gzip.Write($bytes, 0, $bytes.Length) $gzip.Close() $ms.Position = 0 @@ -184,8 +184,8 @@ Describe 'REST API Requests' { # compress the message using deflate $bytes = [System.Text.Encoding]::UTF8.GetBytes($message) - $ms = New-Object -TypeName System.IO.MemoryStream - $gzip = New-Object System.IO.Compression.DeflateStream($ms, [IO.Compression.CompressionMode]::Compress, $true) + $ms = [System.IO.MemoryStream]::new() + $gzip = [System.IO.Compression.DeflateStream]::new($ms, [IO.Compression.CompressionMode]::Compress, $true) $gzip.Write($bytes, 0, $bytes.Length) $gzip.Close() $ms.Position = 0 @@ -201,8 +201,8 @@ Describe 'REST API Requests' { # compress the message using gzip $bytes = [System.Text.Encoding]::UTF8.GetBytes($message) - $ms = New-Object -TypeName System.IO.MemoryStream - $gzip = New-Object System.IO.Compression.GZipStream($ms, [IO.Compression.CompressionMode]::Compress, $true) + $ms = [System.IO.MemoryStream]::new() + $gzip = [System.IO.Compression.GZipStream]::new($ms, [IO.Compression.CompressionMode]::Compress, $true) $gzip.Write($bytes, 0, $bytes.Length) $gzip.Close() $ms.Position = 0 diff --git a/tests/unit/Logging.Tests.ps1 b/tests/unit/Logging.Tests.ps1 index c7cbf1991..1353ea076 100644 --- a/tests/unit/Logging.Tests.ps1 +++ b/tests/unit/Logging.Tests.ps1 @@ -31,7 +31,7 @@ Describe 'Get-PodeLogger' { Describe 'Write-PodeLog' { It 'Does nothing when logging disabled' { Mock Test-PodeLoggerEnabled { return $false } - $PodeContext = @{ LogsToProcess = New-Object System.Collections.ArrayList } + $PodeContext = @{ LogsToProcess = [System.Collections.ArrayList]::new() } Write-PodeLog -Name 'test' -InputObject 'test' @@ -40,7 +40,7 @@ Describe 'Write-PodeLog' { It 'Adds a log item' { Mock Test-PodeLoggerEnabled { return $true } - $PodeContext = @{ LogsToProcess = New-Object System.Collections.ArrayList } + $PodeContext = @{ LogsToProcess = [System.Collections.ArrayList]::new() } Write-PodeLog -Name 'test' -InputObject 'test' @@ -53,7 +53,7 @@ Describe 'Write-PodeLog' { Describe 'Write-PodeErrorLog' { It 'Does nothing when logging disabled' { Mock Test-PodeLoggerEnabled { return $false } - $PodeContext = @{ LogsToProcess = New-Object System.Collections.ArrayList } + $PodeContext = @{ LogsToProcess = [System.Collections.ArrayList]::new() } Write-PodeLog -Name 'test' -InputObject 'test' @@ -67,7 +67,7 @@ Describe 'Write-PodeErrorLog' { } } } - $PodeContext = @{ LogsToProcess = New-Object System.Collections.ArrayList } + $PodeContext = @{ LogsToProcess = [System.Collections.ArrayList]::new() } try { throw 'some error' } catch { @@ -85,7 +85,7 @@ Describe 'Write-PodeErrorLog' { } } } - $PodeContext = @{ LogsToProcess = New-Object System.Collections.ArrayList } + $PodeContext = @{ LogsToProcess = [System.Collections.ArrayList]::new() } $exp = [exception]::new('some error') Write-PodeErrorLog -Exception $exp @@ -101,7 +101,7 @@ Describe 'Write-PodeErrorLog' { } } } - $PodeContext = @{ LogsToProcess = New-Object System.Collections.ArrayList } + $PodeContext = @{ LogsToProcess = [System.Collections.ArrayList]::new() } $exp = [exception]::new('some error') Write-PodeErrorLog -Exception $exp -Level Verbose diff --git a/tests/unit/Server.Tests.ps1 b/tests/unit/Server.Tests.ps1 index 222f7af1d..05ef5167a 100644 --- a/tests/unit/Server.Tests.ps1 +++ b/tests/unit/Server.Tests.ps1 @@ -111,8 +111,8 @@ Describe 'Restart-PodeInternalServer' { It 'Resetting the server values' { $PodeContext = @{ Tokens = @{ - Cancellation = New-Object System.Threading.CancellationTokenSource - Restart = New-Object System.Threading.CancellationTokenSource + Cancellation = [ystem.Threading.CancellationTokenSource]::new() + Restart = [System.Threading.CancellationTokenSource]::new() } Server = @{ Routes = @{ From 2dbab3507359b1f5265918260e40d936a611744f Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Sun, 22 Sep 2024 11:35:37 +0100 Subject: [PATCH 166/177] #1361: fix tests, add localised error --- src/Locales/ar/Pode.psd1 | 1 + src/Locales/de/Pode.psd1 | 1 + src/Locales/en-us/Pode.psd1 | 581 +++++++++++++++--------------- src/Locales/en/Pode.psd1 | 1 + src/Locales/es/Pode.psd1 | 1 + src/Locales/fr/Pode.psd1 | 1 + src/Locales/it/Pode.psd1 | 1 + src/Locales/ja/Pode.psd1 | 1 + src/Locales/ko/Pode.psd1 | 1 + src/Locales/nl/Pode.psd1 | 1 + src/Locales/pl/Pode.psd1 | 1 + src/Locales/pt/Pode.psd1 | 1 + src/Locales/zh/Pode.psd1 | 1 + src/Private/Serverless.ps1 | 6 +- src/Private/Streams.ps1 | 4 +- tests/unit/Localization.Tests.ps1 | 5 +- tests/unit/Server.Tests.ps1 | 3 +- tests/unit/Serverless.Tests.ps1 | 2 +- 18 files changed, 315 insertions(+), 298 deletions(-) diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 8037a5947..8ae7eadc0 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -289,4 +289,5 @@ scheduleProcessDoesNotExistExceptionMessage = 'عملية الجدول الزمني غير موجودة: {0}' definitionTagChangeNotAllowedExceptionMessage = 'لا يمكن تغيير علامة التعريف لمسار.' getRequestBodyNotAllowedExceptionMessage = 'لا يمكن أن تحتوي عمليات {0} على محتوى الطلب.' + unsupportedStreamCompressionEncodingExceptionMessage = 'تشفير الضغط غير مدعوم للتشفير {0}' } diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index 8fe33f3f0..21ee786e3 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -289,4 +289,5 @@ scheduleProcessDoesNotExistExceptionMessage = "Der Aufgabenplanerprozess '{0}' existiert nicht." definitionTagChangeNotAllowedExceptionMessage = 'Definitionstag für eine Route kann nicht geändert werden.' getRequestBodyNotAllowedExceptionMessage = '{0}-Operationen können keinen Anforderungstext haben.' + unsupportedStreamCompressionEncodingExceptionMessage = 'Die Stream-Komprimierungskodierung wird nicht unterstützt: {0}' } \ No newline at end of file diff --git a/src/Locales/en-us/Pode.psd1 b/src/Locales/en-us/Pode.psd1 index aa26c31ee..63c32a969 100644 --- a/src/Locales/en-us/Pode.psd1 +++ b/src/Locales/en-us/Pode.psd1 @@ -1,292 +1,293 @@ @{ - schemaValidationRequiresPowerShell610ExceptionMessage = 'Schema validation requires PowerShell version 6.1.0 or greater.' - customAccessPathOrScriptBlockRequiredExceptionMessage = 'A Path or ScriptBlock is required for sourcing the Custom access values.' - operationIdMustBeUniqueForArrayExceptionMessage = 'OperationID: {0} has to be unique and cannot be applied to an array.' - endpointNotDefinedForRedirectingExceptionMessage = "An endpoint named '{0}' has not been defined for redirecting." - filesHaveChangedMessage = 'The following files have changed:' - iisAspnetcoreTokenMissingExceptionMessage = 'IIS ASPNETCORE_TOKEN is missing.' - minValueGreaterThanMaxExceptionMessage = 'Min value for {0} should not be greater than the max value.' - noLogicPassedForRouteExceptionMessage = 'No logic passed for Route: {0}' - scriptPathDoesNotExistExceptionMessage = 'The script path does not exist: {0}' - mutexAlreadyExistsExceptionMessage = 'A mutex with the following name already exists: {0}' - listeningOnEndpointsMessage = 'Listening on the following {0} endpoint(s) [{1} thread(s)]:' - unsupportedFunctionInServerlessContextExceptionMessage = 'The {0} function is not supported in a serverless context.' - expectedNoJwtSignatureSuppliedExceptionMessage = 'Expected no JWT signature to be supplied.' - secretAlreadyMountedExceptionMessage = "A Secret with the name '{0}' has already been mounted." - failedToAcquireLockExceptionMessage = 'Failed to acquire a lock on the object.' - noPathSuppliedForStaticRouteExceptionMessage = '[{0}]: No Path supplied for Static Route.' - invalidHostnameSuppliedExceptionMessage = 'Invalid hostname supplied: {0}' - authMethodAlreadyDefinedExceptionMessage = 'Authentication method already defined: {0}' - csrfCookieRequiresSecretExceptionMessage = "When using cookies for CSRF, a Secret is required. You can either supply a Secret or set the Cookie global secret - (Set-PodeCookieSecret '' -Global)" - nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 'A non-empty ScriptBlock is required to create a Page Route.' - noPropertiesMutuallyExclusiveExceptionMessage = "The parameter 'NoProperties' is mutually exclusive with 'Properties', 'MinProperties' and 'MaxProperties'" - incompatiblePodeDllExceptionMessage = 'An existing incompatible Pode.DLL version {0} is loaded. Version {1} is required. Open a new Powershell/pwsh session and retry.' - accessMethodDoesNotExistExceptionMessage = 'Access method does not exist: {0}.' - scheduleAlreadyDefinedExceptionMessage = '[Schedule] {0}: Schedule already defined.' - secondsValueCannotBeZeroOrLessExceptionMessage = 'Seconds value cannot be 0 or less for {0}' - pathToLoadNotFoundExceptionMessage = 'Path to load {0} not found: {1}' - failedToImportModuleExceptionMessage = 'Failed to import module: {0}' - endpointNotExistExceptionMessage = "Endpoint with protocol '{0}' and address '{1}' or local address '{2}' does not exist." - terminatingMessage = 'Terminating...' - noCommandsSuppliedToConvertToRoutesExceptionMessage = 'No commands supplied to convert to Routes.' - invalidTaskTypeExceptionMessage = 'Task type is invalid, expected either [System.Threading.Tasks.Task] or [hashtable]' - alreadyConnectedToWebSocketExceptionMessage = "Already connected to WebSocket with name '{0}'" - crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = 'The CRLF message end check is only supported on TCP endpoints.' - testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = "'Test-PodeOAComponentschema' need to be enabled using 'Enable-PodeOpenApi -EnableSchemaValidation'" - adModuleNotInstalledExceptionMessage = 'Active Directory module is not installed.' - cronExpressionInvalidExceptionMessage = 'Cron expression should only consist of 5 parts: {0}' - noSessionToSetOnResponseExceptionMessage = 'There is no session available to set on the response.' - valueOutOfRangeExceptionMessage = "Value '{0}' for {1} is invalid, should be between {2} and {3}" - loggingMethodAlreadyDefinedExceptionMessage = 'Logging method already defined: {0}' - noSecretForHmac256ExceptionMessage = 'No secret supplied for HMAC256 hash.' - eolPowerShellWarningMessage = '[WARNING] Pode {0} has not been tested on PowerShell {1}, as it is EOL.' - runspacePoolFailedToLoadExceptionMessage = '{0} RunspacePool failed to load.' - noEventRegisteredExceptionMessage = 'No {0} event registered: {1}' - scheduleCannotHaveNegativeLimitExceptionMessage = '[Schedule] {0}: Cannot have a negative limit.' - openApiRequestStyleInvalidForParameterExceptionMessage = 'OpenApi request Style cannot be {0} for a {1} parameter.' - openApiDocumentNotCompliantExceptionMessage = 'OpenAPI document is not compliant.' - taskDoesNotExistExceptionMessage = "Task '{0}' does not exist." - scopedVariableNotFoundExceptionMessage = 'Scoped Variable not found: {0}' - sessionsRequiredForCsrfExceptionMessage = 'Sessions are required to use CSRF unless you want to use cookies.' - nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 'A non-empty ScriptBlock is required for the logging method.' - credentialsPassedWildcardForHeadersLiteralExceptionMessage = 'When Credentials is passed, The * wildcard for Headers will be taken as a literal string and not a wildcard.' - podeNotInitializedExceptionMessage = 'Pode has not been initialized.' - multipleEndpointsForGuiMessage = 'Multiple endpoints defined, only the first will be used for the GUI.' - operationIdMustBeUniqueExceptionMessage = 'OperationID: {0} has to be unique.' - invalidJsonJwtExceptionMessage = 'Invalid JSON value found in JWT' - noAlgorithmInJwtHeaderExceptionMessage = 'No algorithm supplied in JWT Header.' - openApiVersionPropertyMandatoryExceptionMessage = 'OpenApi Version property is mandatory.' - limitValueCannotBeZeroOrLessExceptionMessage = 'Limit value cannot be 0 or less for {0}' - timerDoesNotExistExceptionMessage = "Timer '{0}' does not exist." - openApiGenerationDocumentErrorMessage = 'OpenAPI generation document error:' - routeAlreadyContainsCustomAccessExceptionMessage = "Route '[{0}] {1}' already contains Custom Access with name '{2}'" - maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 'Maximum concurrent WebSocket threads cannot be less than the minimum of {0} but got: {1}' - middlewareAlreadyDefinedExceptionMessage = '[Middleware] {0}: Middleware already defined.' - invalidAtomCharacterExceptionMessage = 'Invalid atom character: {0}' - invalidCronAtomFormatExceptionMessage = 'Invalid cron atom format found: {0}' - cacheStorageNotFoundForRetrieveExceptionMessage = "Cache storage with name '{0}' not found when attempting to retrieve cached item '{1}'" - headerMustHaveNameInEncodingContextExceptionMessage = 'Header must have a name when used in an encoding context.' - moduleDoesNotContainFunctionExceptionMessage = 'Module {0} does not contain function {1} to convert to a Route.' - pathToIconForGuiDoesNotExistExceptionMessage = 'Path to the icon for GUI does not exist: {0}' - noTitleSuppliedForPageExceptionMessage = 'No title supplied for {0} page.' - certificateSuppliedForNonHttpsWssEndpointExceptionMessage = 'Certificate supplied for non-HTTPS/WSS endpoint.' - cannotLockNullObjectExceptionMessage = 'Cannot lock an object that is null.' - showPodeGuiOnlyAvailableOnWindowsExceptionMessage = 'Show-PodeGui is currently only available for Windows PowerShell and PowerShell 7+ on Windows OS.' - unlockSecretButNoScriptBlockExceptionMessage = 'Unlock secret supplied for custom Secret Vault type, but not Unlock ScriptBlock supplied.' - invalidIpAddressExceptionMessage = 'The IP address supplied is invalid: {0}' - maxDaysInvalidExceptionMessage = 'MaxDays must be 0 or greater, but got: {0}' - noRemoveScriptBlockForVaultExceptionMessage = "No Remove ScriptBlock supplied for removing secrets from the vault '{0}'" - noSecretExpectedForNoSignatureExceptionMessage = 'Expected no secret to be supplied for no signature.' - noCertificateFoundExceptionMessage = "No certificate could be found in {0}{1} for '{2}'" - minValueInvalidExceptionMessage = "Min value '{0}' for {1} is invalid, should be greater than/equal to {2}" - accessRequiresAuthenticationOnRoutesExceptionMessage = 'Access requires Authentication to be supplied on Routes.' - noSecretForHmac384ExceptionMessage = 'No secret supplied for HMAC384 hash.' - windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = 'Windows Local Authentication support is for Windows OS only.' - definitionTagNotDefinedExceptionMessage = 'DefinitionTag {0} does not exist.' - noComponentInDefinitionExceptionMessage = 'No component of type {0} named {1} is available in the {2} definition.' - noSmtpHandlersDefinedExceptionMessage = 'No SMTP handlers have been defined.' - sessionMiddlewareAlreadyInitializedExceptionMessage = 'Session Middleware has already been initialized.' - reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = "The 'pathItems' reusable component feature is not available in OpenAPI v3.0." - wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 'The * wildcard for Headers is incompatible with the AutoHeaders switch.' - noDataForFileUploadedExceptionMessage = "No data for file '{0}' was uploaded in the request." - sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = 'SSE can only be configured on requests with an Accept header value of text/event-stream' - noSessionAvailableToSaveExceptionMessage = 'There is no session available to save.' - pathParameterRequiresRequiredSwitchExceptionMessage = "If the parameter location is 'Path', the switch parameter 'Required' is mandatory." - noOpenApiUrlSuppliedExceptionMessage = 'No OpenAPI URL supplied for {0}.' - maximumConcurrentSchedulesInvalidExceptionMessage = 'Maximum concurrent schedules must be >=1 but got: {0}' - snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = 'Snapins are only supported on Windows PowerShell.' - eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = 'Event Viewer logging only supported on Windows OS.' - parametersMutuallyExclusiveExceptionMessage = "Parameters '{0}' and '{1}' are mutually exclusive." - pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 'The PathItems feature is not supported in OpenAPI v3.0.x' - openApiParameterRequiresNameExceptionMessage = 'The OpenApi parameter requires a name to be specified.' - maximumConcurrentTasksLessThanMinimumExceptionMessage = 'Maximum concurrent tasks cannot be less than the minimum of {0} but got: {1}' - noSemaphoreFoundExceptionMessage = "No semaphore found called '{0}'" - singleValueForIntervalExceptionMessage = 'You can only supply a single {0} value when using intervals.' - jwtNotYetValidExceptionMessage = 'The JWT is not yet valid for use.' - verbAlreadyDefinedForUrlExceptionMessage = '[Verb] {0}: Already defined for {1}' - noSecretNamedMountedExceptionMessage = "No Secret named '{0}' has been mounted." - moduleOrVersionNotFoundExceptionMessage = 'Module or version not found on {0}: {1}@{2}' - noScriptBlockSuppliedExceptionMessage = 'No ScriptBlock supplied.' - noSecretVaultRegisteredExceptionMessage = "No Secret Vault with the name '{0}' has been registered." - nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = 'A Name is required for the endpoint if the RedirectTo parameter is supplied.' - openApiLicenseObjectRequiresNameExceptionMessage = "The OpenAPI object 'license' required the property 'name'. Use -LicenseName parameter." - sourcePathDoesNotExistForStaticRouteExceptionMessage = '{0}: The Source path supplied for Static Route does not exist: {1}' - noNameForWebSocketDisconnectExceptionMessage = 'No Name for a WebSocket to disconnect from supplied.' - certificateExpiredExceptionMessage = "The certificate '{0}' has expired: {1}" - secretVaultUnlockExpiryDateInPastExceptionMessage = 'Secret Vault unlock expiry date is in the past (UTC): {0}' - invalidWebExceptionTypeExceptionMessage = 'Exception is of an invalid type, should be either WebException or HttpRequestException, but got: {0}' - invalidSecretValueTypeExceptionMessage = 'Secret value is of an invalid type. Expected types: String, SecureString, HashTable, Byte[], or PSCredential. But got: {0}' - explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 'The Explicit TLS mode is only supported on SMTPS and TCPS endpoints.' - discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = "The parameter 'DiscriminatorMapping' can only be used when 'DiscriminatorProperty' is present." - scriptErrorExceptionMessage = "Error '{0}' in script {1} {2} (line {3}) char {4} executing {5} on {6} object '{7}' Class: {8} BaseClass: {9}" - cannotSupplyIntervalForQuarterExceptionMessage = 'Cannot supply interval value for every quarter.' - scheduleEndTimeMustBeInFutureExceptionMessage = '[Schedule] {0}: The EndTime value must be in the future.' - invalidJwtSignatureSuppliedExceptionMessage = 'Invalid JWT signature supplied.' - noSetScriptBlockForVaultExceptionMessage = "No Set ScriptBlock supplied for updating/creating secrets in the vault '{0}'" - accessMethodNotExistForMergingExceptionMessage = 'Access method does not exist for merging: {0}' - defaultAuthNotInListExceptionMessage = "The Default Authentication '{0}' is not in the Authentication list supplied." - parameterHasNoNameExceptionMessage = "The Parameter has no name. Please give this component a name using the 'Name' parameter." - methodPathAlreadyDefinedForUrlExceptionMessage = '[{0}] {1}: Already defined for {2}' - fileWatcherAlreadyDefinedExceptionMessage = "A File Watcher named '{0}' has already been defined." - noServiceHandlersDefinedExceptionMessage = 'No Service handlers have been defined.' - secretRequiredForCustomSessionStorageExceptionMessage = 'A Secret is required when using custom session storage.' - secretManagementModuleNotInstalledExceptionMessage = 'Microsoft.PowerShell.SecretManagement module not installed.' - noPathSuppliedForRouteExceptionMessage = 'No Path supplied for the Route.' - validationOfAnyOfSchemaNotSupportedExceptionMessage = "Validation of a schema that includes 'anyof' is not supported." - iisAuthSupportIsForWindowsOnlyExceptionMessage = 'IIS Authentication support is for Windows OS only.' - oauth2InnerSchemeInvalidExceptionMessage = 'OAuth2 InnerScheme can only be one of either Basic or Form authentication, but got: {0}' - noRoutePathSuppliedForPageExceptionMessage = 'No route path supplied for {0} page.' - cacheStorageNotFoundForExistsExceptionMessage = "Cache storage with name '{0}' not found when attempting to check if cached item '{1}' exists." - handlerAlreadyDefinedExceptionMessage = '[{0}] {1}: Handler already defined.' - sessionsNotConfiguredExceptionMessage = 'Sessions have not been configured.' - propertiesTypeObjectAssociationExceptionMessage = 'Only properties of type Object can be associated with {0}.' - sessionsRequiredForSessionPersistentAuthExceptionMessage = 'Sessions are required to use session persistent authentication.' - invalidPathWildcardOrDirectoryExceptionMessage = 'The Path supplied cannot be a wildcard or a directory: {0}' - accessMethodAlreadyDefinedExceptionMessage = 'Access method already defined: {0}' - parametersValueOrExternalValueMandatoryExceptionMessage = "Parameters 'Value' or 'ExternalValue' are mandatory" - maximumConcurrentTasksInvalidExceptionMessage = 'Maximum concurrent tasks must be >=1 but got: {0}' - cannotCreatePropertyWithoutTypeExceptionMessage = 'Cannot create the property because no type is defined.' - authMethodNotExistForMergingExceptionMessage = 'Authentication method does not exist for merging: {0}' - maxValueInvalidExceptionMessage = "Max value '{0}' for {1} is invalid, should be less than/equal to {2}" - endpointAlreadyDefinedExceptionMessage = "An endpoint named '{0}' has already been defined." - eventAlreadyRegisteredExceptionMessage = '{0} event already registered: {1}' - parameterNotSuppliedInRequestExceptionMessage = "A parameter called '{0}' was not supplied in the request or has no data available." - cacheStorageNotFoundForSetExceptionMessage = "Cache storage with name '{0}' not found when attempting to set cached item '{1}'" - methodPathAlreadyDefinedExceptionMessage = '[{0}] {1}: Already defined.' - errorLoggingAlreadyEnabledExceptionMessage = 'Error Logging has already been enabled.' - valueForUsingVariableNotFoundExceptionMessage = "Value for '`$using:{0}' could not be found." - rapidPdfDoesNotSupportOpenApi31ExceptionMessage = "The Document tool RapidPdf doesn't support OpenAPI 3.1" - oauth2ClientSecretRequiredExceptionMessage = 'OAuth2 requires a Client Secret when not using PKCE.' - invalidBase64JwtExceptionMessage = 'Invalid Base64 encoded value found in JWT' - noSessionToCalculateDataHashExceptionMessage = 'No session available to calculate data hash.' - cacheStorageNotFoundForRemoveExceptionMessage = "Cache storage with name '{0}' not found when attempting to remove cached item '{1}'" - csrfMiddlewareNotInitializedExceptionMessage = 'CSRF Middleware has not been initialized.' - infoTitleMandatoryMessage = 'info.title is mandatory.' - typeCanOnlyBeAssociatedWithObjectExceptionMessage = 'Type {0} can only be associated with an Object.' - userFileDoesNotExistExceptionMessage = 'The user file does not exist: {0}' - routeParameterNeedsValidScriptblockExceptionMessage = 'The Route parameter needs a valid, not empty, scriptblock.' - nextTriggerCalculationErrorExceptionMessage = 'Looks like something went wrong trying to calculate the next trigger datetime: {0}' - cannotLockValueTypeExceptionMessage = 'Cannot lock a [ValueType]' - failedToCreateOpenSslCertExceptionMessage = 'Failed to create OpenSSL cert: {0}' - jwtExpiredExceptionMessage = 'The JWT has expired.' - openingGuiMessage = 'Opening the GUI.' - multiTypePropertiesRequireOpenApi31ExceptionMessage = 'Multi-type properties require OpenApi Version 3.1 or above.' - noNameForWebSocketRemoveExceptionMessage = 'No Name for a WebSocket to remove supplied.' - maxSizeInvalidExceptionMessage = 'MaxSize must be 0 or greater, but got: {0}' - iisShutdownMessage = '(IIS Shutdown)' - cannotUnlockValueTypeExceptionMessage = 'Cannot unlock a [ValueType]' - noJwtSignatureForAlgorithmExceptionMessage = 'No JWT signature supplied for {0}.' - maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 'Maximum concurrent WebSocket threads must be >=1 but got: {0}' - acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 'The Acknowledge message is only supported on SMTP and TCP endpoints.' - failedToConnectToUrlExceptionMessage = 'Failed to connect to URL: {0}' - failedToAcquireMutexOwnershipExceptionMessage = 'Failed to acquire mutex ownership. Mutex name: {0}' - sessionsRequiredForOAuth2WithPKCEExceptionMessage = 'Sessions are required to use OAuth2 with PKCE' - failedToConnectToWebSocketExceptionMessage = 'Failed to connect to WebSocket: {0}' - unsupportedObjectExceptionMessage = 'Unsupported object' - failedToParseAddressExceptionMessage = "Failed to parse '{0}' as a valid IP/Host:Port address" - mustBeRunningWithAdminPrivilegesExceptionMessage = 'Must be running with administrator privileges to listen on non-localhost addresses.' - specificationMessage = 'Specification' - cacheStorageNotFoundForClearExceptionMessage = "Cache storage with name '{0}' not found when attempting to clear the cache." - restartingServerMessage = 'Restarting server...' - cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = "Cannot supply an interval when the parameter 'Every' is set to None." - unsupportedJwtAlgorithmExceptionMessage = 'The JWT algorithm is not currently supported: {0}' - websocketsNotConfiguredForSignalMessagesExceptionMessage = 'WebSockets have not been configured to send signal messages.' - invalidLogicTypeInHashtableMiddlewareExceptionMessage = 'A Hashtable Middleware supplied has an invalid Logic type. Expected ScriptBlock, but got: {0}' - maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 'Maximum concurrent schedules cannot be less than the minimum of {0} but got: {1}' - failedToAcquireSemaphoreOwnershipExceptionMessage = 'Failed to acquire semaphore ownership. Semaphore name: {0}' - propertiesParameterWithoutNameExceptionMessage = 'The Properties parameters cannot be used if the Property has no name.' - customSessionStorageMethodNotImplementedExceptionMessage = "The custom session storage does not implement the required '{0}()' method." - authenticationMethodDoesNotExistExceptionMessage = 'Authentication method does not exist: {0}' - webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = 'The Webhooks feature is not supported in OpenAPI v3.0.x' - invalidContentTypeForSchemaExceptionMessage = "Invalid 'content-type' found for schema: {0}" - noUnlockScriptBlockForVaultExceptionMessage = "No Unlock ScriptBlock supplied for unlocking the vault '{0}'" - definitionTagMessage = 'Definition {0}:' - failedToOpenRunspacePoolExceptionMessage = 'Failed to open RunspacePool: {0}' - failedToCloseRunspacePoolExceptionMessage = 'Failed to close RunspacePool: {0}' - verbNoLogicPassedExceptionMessage = '[Verb] {0}: No logic passed' - noMutexFoundExceptionMessage = "No mutex found called '{0}'" - documentationMessage = 'Documentation' - timerAlreadyDefinedExceptionMessage = '[Timer] {0}: Timer already defined.' - invalidPortExceptionMessage = 'The port cannot be negative: {0}' - viewsFolderNameAlreadyExistsExceptionMessage = 'The Views folder name already exists: {0}' - noNameForWebSocketResetExceptionMessage = 'No Name for a WebSocket to reset supplied.' - mergeDefaultAuthNotInListExceptionMessage = "The MergeDefault Authentication '{0}' is not in the Authentication list supplied." - descriptionRequiredExceptionMessage = 'A Description is required for Path:{0} Response:{1}' - pageNameShouldBeAlphaNumericExceptionMessage = 'The Page name should be a valid Alphanumeric value: {0}' - defaultValueNotBooleanOrEnumExceptionMessage = 'The default value is not a boolean and is not part of the enum.' - openApiComponentSchemaDoesNotExistExceptionMessage = "The OpenApi component schema {0} doesn't exist." - timerParameterMustBeGreaterThanZeroExceptionMessage = '[Timer] {0}: {1} must be greater than 0.' - taskTimedOutExceptionMessage = 'Task has timed out after {0}ms.' - scheduleStartTimeAfterEndTimeExceptionMessage = '[Schedule] {0}: Cannot have a StartTime after the EndTime' - infoVersionMandatoryMessage = 'info.version is mandatory.' - cannotUnlockNullObjectExceptionMessage = 'Cannot unlock an object that is null.' - nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 'A non-empty ScriptBlock is required for the Custom authentication scheme.' - nonEmptyScriptBlockRequiredForAuthMethodExceptionMessage = 'A non-empty ScriptBlock is required for the authentication method.' - validationOfOneOfSchemaNotSupportedExceptionMessage = "Validation of a schema that includes 'oneof' is not supported." - routeParameterCannotBeNullExceptionMessage = "The parameter 'Route' cannot be null." - cacheStorageAlreadyExistsExceptionMessage = "Cache Storage with name '{0}' already exists." - loggingMethodRequiresValidScriptBlockExceptionMessage = "The supplied output Method for the '{0}' Logging method requires a valid ScriptBlock." - scopedVariableAlreadyDefinedExceptionMessage = 'Scoped Variable already defined: {0}' - oauth2RequiresAuthorizeUrlExceptionMessage = "OAuth2 requires an 'AuthoriseUrl' property to be supplied." - pathNotExistExceptionMessage = 'Path does not exist: {0}' - noDomainServerNameForWindowsAdAuthExceptionMessage = 'No domain server name has been supplied for Windows AD authentication' - suppliedDateAfterScheduleEndTimeExceptionMessage = 'Supplied date is after the end time of the schedule at {0}' - wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 'The * wildcard for Methods is incompatible with the AutoMethods switch.' - cannotSupplyIntervalForYearExceptionMessage = 'Cannot supply interval value for every year.' - missingComponentsMessage = 'Missing component(s)' - invalidStrictTransportSecurityDurationExceptionMessage = 'Invalid Strict-Transport-Security duration supplied: {0}. It should be greater than 0.' - noSecretForHmac512ExceptionMessage = 'No secret supplied for HMAC512 hash.' - daysInMonthExceededExceptionMessage = '{0} only has {1} days, but {2} was supplied.' - nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 'A non-empty ScriptBlock is required for the Custom logging output method.' - encodingAttributeOnlyAppliesToMultipartExceptionMessage = 'The encoding attribute only applies to multipart and application/x-www-form-urlencoded request bodies.' - suppliedDateBeforeScheduleStartTimeExceptionMessage = 'Supplied date is before the start time of the schedule at {0}' - unlockSecretRequiredExceptionMessage = "An 'UnlockSecret' property is required when using Microsoft.PowerShell.SecretStore" - noLogicPassedForMethodRouteExceptionMessage = '[{0}] {1}: No logic passed.' - bodyParserAlreadyDefinedForContentTypeExceptionMessage = 'A body-parser is already defined for the {0} content-type.' - invalidJwtSuppliedExceptionMessage = 'Invalid JWT supplied.' - sessionsRequiredForFlashMessagesExceptionMessage = 'Sessions are required to use Flash messages.' - semaphoreAlreadyExistsExceptionMessage = 'A semaphore with the following name already exists: {0}' - invalidJwtHeaderAlgorithmSuppliedExceptionMessage = 'Invalid JWT header algorithm supplied.' - oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = "The OAuth2 provider does not support the 'password' grant_type required by using an InnerScheme." - invalidAliasFoundExceptionMessage = 'Invalid {0} alias found: {1}' - scheduleDoesNotExistExceptionMessage = "Schedule '{0}' does not exist." - accessMethodNotExistExceptionMessage = 'Access method does not exist: {0}' - oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = "The OAuth2 provider does not support the 'code' response_type." - untestedPowerShellVersionWarningMessage = '[WARNING] Pode {0} has not been tested on PowerShell {1}, as it was not available when Pode was released.' - secretVaultAlreadyRegisteredAutoImportExceptionMessage = "A Secret Vault with the name '{0}' has already been registered while auto-importing Secret Vaults." - schemeRequiresValidScriptBlockExceptionMessage = "The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock." - serverLoopingMessage = 'Server looping every {0}secs' - certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 'Certificate Thumbprints/Name are only supported on Windows OS.' - sseConnectionNameRequiredExceptionMessage = "An SSE connection Name is required, either from -Name or `$WebEvent.Sse.Name" - invalidMiddlewareTypeExceptionMessage = 'One of the Middlewares supplied is an invalid type. Expected either a ScriptBlock or Hashtable, but got: {0}' - noSecretForJwtSignatureExceptionMessage = 'No secret supplied for JWT signature.' - modulePathDoesNotExistExceptionMessage = 'The module path does not exist: {0}' - taskAlreadyDefinedExceptionMessage = '[Task] {0}: Task already defined.' - verbAlreadyDefinedExceptionMessage = '[Verb] {0}: Already defined' - clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 'Client certificates are only supported on HTTPS endpoints.' - endpointNameNotExistExceptionMessage = "Endpoint with name '{0}' does not exist." - middlewareNoLogicSuppliedExceptionMessage = '[Middleware]: No logic supplied in ScriptBlock.' - scriptBlockRequiredForMergingUsersExceptionMessage = 'A Scriptblock for merging multiple authenticated users into 1 object is required When Valid is All.' - secretVaultAlreadyRegisteredExceptionMessage = "A Secret Vault with the name '{0}' has already been registered{1}." - deprecatedTitleVersionDescriptionWarningMessage = "WARNING: Title, Version, and Description on 'Enable-PodeOpenApi' are deprecated. Please use 'Add-PodeOAInfo' instead." - undefinedOpenApiReferencesMessage = 'Undefined OpenAPI References:' - doneMessage = 'Done' - swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = "This version on Swagger-Editor doesn't support OpenAPI 3.1" - durationMustBeZeroOrGreaterExceptionMessage = 'Duration must be 0 or greater, but got: {0}s' - viewsPathDoesNotExistExceptionMessage = 'The Views path does not exist: {0}' - discriminatorIncompatibleWithAllOfExceptionMessage = "The parameter 'Discriminator' is incompatible with 'allOf'." - noNameForWebSocketSendMessageExceptionMessage = 'No Name for a WebSocket to send message to supplied.' - hashtableMiddlewareNoLogicExceptionMessage = 'A Hashtable Middleware supplied has no Logic defined.' - openApiInfoMessage = 'OpenAPI Info:' - invalidSchemeForAuthValidatorExceptionMessage = "The supplied '{0}' Scheme for the '{1}' authentication validator requires a valid ScriptBlock." - sseFailedToBroadcastExceptionMessage = 'SSE failed to broadcast due to defined SSE broadcast level for {0}: {1}' - adModuleWindowsOnlyExceptionMessage = 'Active Directory module only available on Windows OS.' - requestLoggingAlreadyEnabledExceptionMessage = 'Request Logging has already been enabled.' - invalidAccessControlMaxAgeDurationExceptionMessage = 'Invalid Access-Control-Max-Age duration supplied: {0}. Should be greater than 0.' - openApiDefinitionAlreadyExistsExceptionMessage = 'OpenAPI definition named {0} already exists.' - renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." - taskProcessDoesNotExistExceptionMessage = 'Task process does not exist: {0}' - scheduleProcessDoesNotExistExceptionMessage = 'Schedule process does not exist: {0}' - definitionTagChangeNotAllowedExceptionMessage = 'Definition Tag for a Route cannot be changed.' - getRequestBodyNotAllowedExceptionMessage = '{0} operations cannot have a Request Body.' + schemaValidationRequiresPowerShell610ExceptionMessage = 'Schema validation requires PowerShell version 6.1.0 or greater.' + customAccessPathOrScriptBlockRequiredExceptionMessage = 'A Path or ScriptBlock is required for sourcing the Custom access values.' + operationIdMustBeUniqueForArrayExceptionMessage = 'OperationID: {0} has to be unique and cannot be applied to an array.' + endpointNotDefinedForRedirectingExceptionMessage = "An endpoint named '{0}' has not been defined for redirecting." + filesHaveChangedMessage = 'The following files have changed:' + iisAspnetcoreTokenMissingExceptionMessage = 'IIS ASPNETCORE_TOKEN is missing.' + minValueGreaterThanMaxExceptionMessage = 'Min value for {0} should not be greater than the max value.' + noLogicPassedForRouteExceptionMessage = 'No logic passed for Route: {0}' + scriptPathDoesNotExistExceptionMessage = 'The script path does not exist: {0}' + mutexAlreadyExistsExceptionMessage = 'A mutex with the following name already exists: {0}' + listeningOnEndpointsMessage = 'Listening on the following {0} endpoint(s) [{1} thread(s)]:' + unsupportedFunctionInServerlessContextExceptionMessage = 'The {0} function is not supported in a serverless context.' + expectedNoJwtSignatureSuppliedExceptionMessage = 'Expected no JWT signature to be supplied.' + secretAlreadyMountedExceptionMessage = "A Secret with the name '{0}' has already been mounted." + failedToAcquireLockExceptionMessage = 'Failed to acquire a lock on the object.' + noPathSuppliedForStaticRouteExceptionMessage = '[{0}]: No Path supplied for Static Route.' + invalidHostnameSuppliedExceptionMessage = 'Invalid hostname supplied: {0}' + authMethodAlreadyDefinedExceptionMessage = 'Authentication method already defined: {0}' + csrfCookieRequiresSecretExceptionMessage = "When using cookies for CSRF, a Secret is required. You can either supply a Secret or set the Cookie global secret - (Set-PodeCookieSecret '' -Global)" + nonEmptyScriptBlockRequiredForPageRouteExceptionMessage = 'A non-empty ScriptBlock is required to create a Page Route.' + noPropertiesMutuallyExclusiveExceptionMessage = "The parameter 'NoProperties' is mutually exclusive with 'Properties', 'MinProperties' and 'MaxProperties'" + incompatiblePodeDllExceptionMessage = 'An existing incompatible Pode.DLL version {0} is loaded. Version {1} is required. Open a new Powershell/pwsh session and retry.' + accessMethodDoesNotExistExceptionMessage = 'Access method does not exist: {0}.' + scheduleAlreadyDefinedExceptionMessage = '[Schedule] {0}: Schedule already defined.' + secondsValueCannotBeZeroOrLessExceptionMessage = 'Seconds value cannot be 0 or less for {0}' + pathToLoadNotFoundExceptionMessage = 'Path to load {0} not found: {1}' + failedToImportModuleExceptionMessage = 'Failed to import module: {0}' + endpointNotExistExceptionMessage = "Endpoint with protocol '{0}' and address '{1}' or local address '{2}' does not exist." + terminatingMessage = 'Terminating...' + noCommandsSuppliedToConvertToRoutesExceptionMessage = 'No commands supplied to convert to Routes.' + invalidTaskTypeExceptionMessage = 'Task type is invalid, expected either [System.Threading.Tasks.Task] or [hashtable]' + alreadyConnectedToWebSocketExceptionMessage = "Already connected to WebSocket with name '{0}'" + crlfMessageEndCheckOnlySupportedOnTcpEndpointsExceptionMessage = 'The CRLF message end check is only supported on TCP endpoints.' + testPodeOAComponentSchemaNeedToBeEnabledExceptionMessage = "'Test-PodeOAComponentschema' need to be enabled using 'Enable-PodeOpenApi -EnableSchemaValidation'" + adModuleNotInstalledExceptionMessage = 'Active Directory module is not installed.' + cronExpressionInvalidExceptionMessage = 'Cron expression should only consist of 5 parts: {0}' + noSessionToSetOnResponseExceptionMessage = 'There is no session available to set on the response.' + valueOutOfRangeExceptionMessage = "Value '{0}' for {1} is invalid, should be between {2} and {3}" + loggingMethodAlreadyDefinedExceptionMessage = 'Logging method already defined: {0}' + noSecretForHmac256ExceptionMessage = 'No secret supplied for HMAC256 hash.' + eolPowerShellWarningMessage = '[WARNING] Pode {0} has not been tested on PowerShell {1}, as it is EOL.' + runspacePoolFailedToLoadExceptionMessage = '{0} RunspacePool failed to load.' + noEventRegisteredExceptionMessage = 'No {0} event registered: {1}' + scheduleCannotHaveNegativeLimitExceptionMessage = '[Schedule] {0}: Cannot have a negative limit.' + openApiRequestStyleInvalidForParameterExceptionMessage = 'OpenApi request Style cannot be {0} for a {1} parameter.' + openApiDocumentNotCompliantExceptionMessage = 'OpenAPI document is not compliant.' + taskDoesNotExistExceptionMessage = "Task '{0}' does not exist." + scopedVariableNotFoundExceptionMessage = 'Scoped Variable not found: {0}' + sessionsRequiredForCsrfExceptionMessage = 'Sessions are required to use CSRF unless you want to use cookies.' + nonEmptyScriptBlockRequiredForLoggingMethodExceptionMessage = 'A non-empty ScriptBlock is required for the logging method.' + credentialsPassedWildcardForHeadersLiteralExceptionMessage = 'When Credentials is passed, The * wildcard for Headers will be taken as a literal string and not a wildcard.' + podeNotInitializedExceptionMessage = 'Pode has not been initialized.' + multipleEndpointsForGuiMessage = 'Multiple endpoints defined, only the first will be used for the GUI.' + operationIdMustBeUniqueExceptionMessage = 'OperationID: {0} has to be unique.' + invalidJsonJwtExceptionMessage = 'Invalid JSON value found in JWT' + noAlgorithmInJwtHeaderExceptionMessage = 'No algorithm supplied in JWT Header.' + openApiVersionPropertyMandatoryExceptionMessage = 'OpenApi Version property is mandatory.' + limitValueCannotBeZeroOrLessExceptionMessage = 'Limit value cannot be 0 or less for {0}' + timerDoesNotExistExceptionMessage = "Timer '{0}' does not exist." + openApiGenerationDocumentErrorMessage = 'OpenAPI generation document error:' + routeAlreadyContainsCustomAccessExceptionMessage = "Route '[{0}] {1}' already contains Custom Access with name '{2}'" + maximumConcurrentWebSocketThreadsLessThanMinimumExceptionMessage = 'Maximum concurrent WebSocket threads cannot be less than the minimum of {0} but got: {1}' + middlewareAlreadyDefinedExceptionMessage = '[Middleware] {0}: Middleware already defined.' + invalidAtomCharacterExceptionMessage = 'Invalid atom character: {0}' + invalidCronAtomFormatExceptionMessage = 'Invalid cron atom format found: {0}' + cacheStorageNotFoundForRetrieveExceptionMessage = "Cache storage with name '{0}' not found when attempting to retrieve cached item '{1}'" + headerMustHaveNameInEncodingContextExceptionMessage = 'Header must have a name when used in an encoding context.' + moduleDoesNotContainFunctionExceptionMessage = 'Module {0} does not contain function {1} to convert to a Route.' + pathToIconForGuiDoesNotExistExceptionMessage = 'Path to the icon for GUI does not exist: {0}' + noTitleSuppliedForPageExceptionMessage = 'No title supplied for {0} page.' + certificateSuppliedForNonHttpsWssEndpointExceptionMessage = 'Certificate supplied for non-HTTPS/WSS endpoint.' + cannotLockNullObjectExceptionMessage = 'Cannot lock an object that is null.' + showPodeGuiOnlyAvailableOnWindowsExceptionMessage = 'Show-PodeGui is currently only available for Windows PowerShell and PowerShell 7+ on Windows OS.' + unlockSecretButNoScriptBlockExceptionMessage = 'Unlock secret supplied for custom Secret Vault type, but not Unlock ScriptBlock supplied.' + invalidIpAddressExceptionMessage = 'The IP address supplied is invalid: {0}' + maxDaysInvalidExceptionMessage = 'MaxDays must be 0 or greater, but got: {0}' + noRemoveScriptBlockForVaultExceptionMessage = "No Remove ScriptBlock supplied for removing secrets from the vault '{0}'" + noSecretExpectedForNoSignatureExceptionMessage = 'Expected no secret to be supplied for no signature.' + noCertificateFoundExceptionMessage = "No certificate could be found in {0}{1} for '{2}'" + minValueInvalidExceptionMessage = "Min value '{0}' for {1} is invalid, should be greater than/equal to {2}" + accessRequiresAuthenticationOnRoutesExceptionMessage = 'Access requires Authentication to be supplied on Routes.' + noSecretForHmac384ExceptionMessage = 'No secret supplied for HMAC384 hash.' + windowsLocalAuthSupportIsForWindowsOnlyExceptionMessage = 'Windows Local Authentication support is for Windows OS only.' + definitionTagNotDefinedExceptionMessage = 'DefinitionTag {0} does not exist.' + noComponentInDefinitionExceptionMessage = 'No component of type {0} named {1} is available in the {2} definition.' + noSmtpHandlersDefinedExceptionMessage = 'No SMTP handlers have been defined.' + sessionMiddlewareAlreadyInitializedExceptionMessage = 'Session Middleware has already been initialized.' + reusableComponentPathItemsNotAvailableInOpenApi30ExceptionMessage = "The 'pathItems' reusable component feature is not available in OpenAPI v3.0." + wildcardHeadersIncompatibleWithAutoHeadersExceptionMessage = 'The * wildcard for Headers is incompatible with the AutoHeaders switch.' + noDataForFileUploadedExceptionMessage = "No data for file '{0}' was uploaded in the request." + sseOnlyConfiguredOnEventStreamAcceptHeaderExceptionMessage = 'SSE can only be configured on requests with an Accept header value of text/event-stream' + noSessionAvailableToSaveExceptionMessage = 'There is no session available to save.' + pathParameterRequiresRequiredSwitchExceptionMessage = "If the parameter location is 'Path', the switch parameter 'Required' is mandatory." + noOpenApiUrlSuppliedExceptionMessage = 'No OpenAPI URL supplied for {0}.' + maximumConcurrentSchedulesInvalidExceptionMessage = 'Maximum concurrent schedules must be >=1 but got: {0}' + snapinsSupportedOnWindowsPowershellOnlyExceptionMessage = 'Snapins are only supported on Windows PowerShell.' + eventViewerLoggingSupportedOnWindowsOnlyExceptionMessage = 'Event Viewer logging only supported on Windows OS.' + parametersMutuallyExclusiveExceptionMessage = "Parameters '{0}' and '{1}' are mutually exclusive." + pathItemsFeatureNotSupportedInOpenApi30ExceptionMessage = 'The PathItems feature is not supported in OpenAPI v3.0.x' + openApiParameterRequiresNameExceptionMessage = 'The OpenApi parameter requires a name to be specified.' + maximumConcurrentTasksLessThanMinimumExceptionMessage = 'Maximum concurrent tasks cannot be less than the minimum of {0} but got: {1}' + noSemaphoreFoundExceptionMessage = "No semaphore found called '{0}'" + singleValueForIntervalExceptionMessage = 'You can only supply a single {0} value when using intervals.' + jwtNotYetValidExceptionMessage = 'The JWT is not yet valid for use.' + verbAlreadyDefinedForUrlExceptionMessage = '[Verb] {0}: Already defined for {1}' + noSecretNamedMountedExceptionMessage = "No Secret named '{0}' has been mounted." + moduleOrVersionNotFoundExceptionMessage = 'Module or version not found on {0}: {1}@{2}' + noScriptBlockSuppliedExceptionMessage = 'No ScriptBlock supplied.' + noSecretVaultRegisteredExceptionMessage = "No Secret Vault with the name '{0}' has been registered." + nameRequiredForEndpointIfRedirectToSuppliedExceptionMessage = 'A Name is required for the endpoint if the RedirectTo parameter is supplied.' + openApiLicenseObjectRequiresNameExceptionMessage = "The OpenAPI object 'license' required the property 'name'. Use -LicenseName parameter." + sourcePathDoesNotExistForStaticRouteExceptionMessage = '{0}: The Source path supplied for Static Route does not exist: {1}' + noNameForWebSocketDisconnectExceptionMessage = 'No Name for a WebSocket to disconnect from supplied.' + certificateExpiredExceptionMessage = "The certificate '{0}' has expired: {1}" + secretVaultUnlockExpiryDateInPastExceptionMessage = 'Secret Vault unlock expiry date is in the past (UTC): {0}' + invalidWebExceptionTypeExceptionMessage = 'Exception is of an invalid type, should be either WebException or HttpRequestException, but got: {0}' + invalidSecretValueTypeExceptionMessage = 'Secret value is of an invalid type. Expected types: String, SecureString, HashTable, Byte[], or PSCredential. But got: {0}' + explicitTlsModeOnlySupportedOnSmtpsTcpsEndpointsExceptionMessage = 'The Explicit TLS mode is only supported on SMTPS and TCPS endpoints.' + discriminatorMappingRequiresDiscriminatorPropertyExceptionMessage = "The parameter 'DiscriminatorMapping' can only be used when 'DiscriminatorProperty' is present." + scriptErrorExceptionMessage = "Error '{0}' in script {1} {2} (line {3}) char {4} executing {5} on {6} object '{7}' Class: {8} BaseClass: {9}" + cannotSupplyIntervalForQuarterExceptionMessage = 'Cannot supply interval value for every quarter.' + scheduleEndTimeMustBeInFutureExceptionMessage = '[Schedule] {0}: The EndTime value must be in the future.' + invalidJwtSignatureSuppliedExceptionMessage = 'Invalid JWT signature supplied.' + noSetScriptBlockForVaultExceptionMessage = "No Set ScriptBlock supplied for updating/creating secrets in the vault '{0}'" + accessMethodNotExistForMergingExceptionMessage = 'Access method does not exist for merging: {0}' + defaultAuthNotInListExceptionMessage = "The Default Authentication '{0}' is not in the Authentication list supplied." + parameterHasNoNameExceptionMessage = "The Parameter has no name. Please give this component a name using the 'Name' parameter." + methodPathAlreadyDefinedForUrlExceptionMessage = '[{0}] {1}: Already defined for {2}' + fileWatcherAlreadyDefinedExceptionMessage = "A File Watcher named '{0}' has already been defined." + noServiceHandlersDefinedExceptionMessage = 'No Service handlers have been defined.' + secretRequiredForCustomSessionStorageExceptionMessage = 'A Secret is required when using custom session storage.' + secretManagementModuleNotInstalledExceptionMessage = 'Microsoft.PowerShell.SecretManagement module not installed.' + noPathSuppliedForRouteExceptionMessage = 'No Path supplied for the Route.' + validationOfAnyOfSchemaNotSupportedExceptionMessage = "Validation of a schema that includes 'anyof' is not supported." + iisAuthSupportIsForWindowsOnlyExceptionMessage = 'IIS Authentication support is for Windows OS only.' + oauth2InnerSchemeInvalidExceptionMessage = 'OAuth2 InnerScheme can only be one of either Basic or Form authentication, but got: {0}' + noRoutePathSuppliedForPageExceptionMessage = 'No route path supplied for {0} page.' + cacheStorageNotFoundForExistsExceptionMessage = "Cache storage with name '{0}' not found when attempting to check if cached item '{1}' exists." + handlerAlreadyDefinedExceptionMessage = '[{0}] {1}: Handler already defined.' + sessionsNotConfiguredExceptionMessage = 'Sessions have not been configured.' + propertiesTypeObjectAssociationExceptionMessage = 'Only properties of type Object can be associated with {0}.' + sessionsRequiredForSessionPersistentAuthExceptionMessage = 'Sessions are required to use session persistent authentication.' + invalidPathWildcardOrDirectoryExceptionMessage = 'The Path supplied cannot be a wildcard or a directory: {0}' + accessMethodAlreadyDefinedExceptionMessage = 'Access method already defined: {0}' + parametersValueOrExternalValueMandatoryExceptionMessage = "Parameters 'Value' or 'ExternalValue' are mandatory" + maximumConcurrentTasksInvalidExceptionMessage = 'Maximum concurrent tasks must be >=1 but got: {0}' + cannotCreatePropertyWithoutTypeExceptionMessage = 'Cannot create the property because no type is defined.' + authMethodNotExistForMergingExceptionMessage = 'Authentication method does not exist for merging: {0}' + maxValueInvalidExceptionMessage = "Max value '{0}' for {1} is invalid, should be less than/equal to {2}" + endpointAlreadyDefinedExceptionMessage = "An endpoint named '{0}' has already been defined." + eventAlreadyRegisteredExceptionMessage = '{0} event already registered: {1}' + parameterNotSuppliedInRequestExceptionMessage = "A parameter called '{0}' was not supplied in the request or has no data available." + cacheStorageNotFoundForSetExceptionMessage = "Cache storage with name '{0}' not found when attempting to set cached item '{1}'" + methodPathAlreadyDefinedExceptionMessage = '[{0}] {1}: Already defined.' + errorLoggingAlreadyEnabledExceptionMessage = 'Error Logging has already been enabled.' + valueForUsingVariableNotFoundExceptionMessage = "Value for '`$using:{0}' could not be found." + rapidPdfDoesNotSupportOpenApi31ExceptionMessage = "The Document tool RapidPdf doesn't support OpenAPI 3.1" + oauth2ClientSecretRequiredExceptionMessage = 'OAuth2 requires a Client Secret when not using PKCE.' + invalidBase64JwtExceptionMessage = 'Invalid Base64 encoded value found in JWT' + noSessionToCalculateDataHashExceptionMessage = 'No session available to calculate data hash.' + cacheStorageNotFoundForRemoveExceptionMessage = "Cache storage with name '{0}' not found when attempting to remove cached item '{1}'" + csrfMiddlewareNotInitializedExceptionMessage = 'CSRF Middleware has not been initialized.' + infoTitleMandatoryMessage = 'info.title is mandatory.' + typeCanOnlyBeAssociatedWithObjectExceptionMessage = 'Type {0} can only be associated with an Object.' + userFileDoesNotExistExceptionMessage = 'The user file does not exist: {0}' + routeParameterNeedsValidScriptblockExceptionMessage = 'The Route parameter needs a valid, not empty, scriptblock.' + nextTriggerCalculationErrorExceptionMessage = 'Looks like something went wrong trying to calculate the next trigger datetime: {0}' + cannotLockValueTypeExceptionMessage = 'Cannot lock a [ValueType]' + failedToCreateOpenSslCertExceptionMessage = 'Failed to create OpenSSL cert: {0}' + jwtExpiredExceptionMessage = 'The JWT has expired.' + openingGuiMessage = 'Opening the GUI.' + multiTypePropertiesRequireOpenApi31ExceptionMessage = 'Multi-type properties require OpenApi Version 3.1 or above.' + noNameForWebSocketRemoveExceptionMessage = 'No Name for a WebSocket to remove supplied.' + maxSizeInvalidExceptionMessage = 'MaxSize must be 0 or greater, but got: {0}' + iisShutdownMessage = '(IIS Shutdown)' + cannotUnlockValueTypeExceptionMessage = 'Cannot unlock a [ValueType]' + noJwtSignatureForAlgorithmExceptionMessage = 'No JWT signature supplied for {0}.' + maximumConcurrentWebSocketThreadsInvalidExceptionMessage = 'Maximum concurrent WebSocket threads must be >=1 but got: {0}' + acknowledgeMessageOnlySupportedOnSmtpTcpEndpointsExceptionMessage = 'The Acknowledge message is only supported on SMTP and TCP endpoints.' + failedToConnectToUrlExceptionMessage = 'Failed to connect to URL: {0}' + failedToAcquireMutexOwnershipExceptionMessage = 'Failed to acquire mutex ownership. Mutex name: {0}' + sessionsRequiredForOAuth2WithPKCEExceptionMessage = 'Sessions are required to use OAuth2 with PKCE' + failedToConnectToWebSocketExceptionMessage = 'Failed to connect to WebSocket: {0}' + unsupportedObjectExceptionMessage = 'Unsupported object' + failedToParseAddressExceptionMessage = "Failed to parse '{0}' as a valid IP/Host:Port address" + mustBeRunningWithAdminPrivilegesExceptionMessage = 'Must be running with administrator privileges to listen on non-localhost addresses.' + specificationMessage = 'Specification' + cacheStorageNotFoundForClearExceptionMessage = "Cache storage with name '{0}' not found when attempting to clear the cache." + restartingServerMessage = 'Restarting server...' + cannotSupplyIntervalWhenEveryIsNoneExceptionMessage = "Cannot supply an interval when the parameter 'Every' is set to None." + unsupportedJwtAlgorithmExceptionMessage = 'The JWT algorithm is not currently supported: {0}' + websocketsNotConfiguredForSignalMessagesExceptionMessage = 'WebSockets have not been configured to send signal messages.' + invalidLogicTypeInHashtableMiddlewareExceptionMessage = 'A Hashtable Middleware supplied has an invalid Logic type. Expected ScriptBlock, but got: {0}' + maximumConcurrentSchedulesLessThanMinimumExceptionMessage = 'Maximum concurrent schedules cannot be less than the minimum of {0} but got: {1}' + failedToAcquireSemaphoreOwnershipExceptionMessage = 'Failed to acquire semaphore ownership. Semaphore name: {0}' + propertiesParameterWithoutNameExceptionMessage = 'The Properties parameters cannot be used if the Property has no name.' + customSessionStorageMethodNotImplementedExceptionMessage = "The custom session storage does not implement the required '{0}()' method." + authenticationMethodDoesNotExistExceptionMessage = 'Authentication method does not exist: {0}' + webhooksFeatureNotSupportedInOpenApi30ExceptionMessage = 'The Webhooks feature is not supported in OpenAPI v3.0.x' + invalidContentTypeForSchemaExceptionMessage = "Invalid 'content-type' found for schema: {0}" + noUnlockScriptBlockForVaultExceptionMessage = "No Unlock ScriptBlock supplied for unlocking the vault '{0}'" + definitionTagMessage = 'Definition {0}:' + failedToOpenRunspacePoolExceptionMessage = 'Failed to open RunspacePool: {0}' + failedToCloseRunspacePoolExceptionMessage = 'Failed to close RunspacePool: {0}' + verbNoLogicPassedExceptionMessage = '[Verb] {0}: No logic passed' + noMutexFoundExceptionMessage = "No mutex found called '{0}'" + documentationMessage = 'Documentation' + timerAlreadyDefinedExceptionMessage = '[Timer] {0}: Timer already defined.' + invalidPortExceptionMessage = 'The port cannot be negative: {0}' + viewsFolderNameAlreadyExistsExceptionMessage = 'The Views folder name already exists: {0}' + noNameForWebSocketResetExceptionMessage = 'No Name for a WebSocket to reset supplied.' + mergeDefaultAuthNotInListExceptionMessage = "The MergeDefault Authentication '{0}' is not in the Authentication list supplied." + descriptionRequiredExceptionMessage = 'A Description is required for Path:{0} Response:{1}' + pageNameShouldBeAlphaNumericExceptionMessage = 'The Page name should be a valid Alphanumeric value: {0}' + defaultValueNotBooleanOrEnumExceptionMessage = 'The default value is not a boolean and is not part of the enum.' + openApiComponentSchemaDoesNotExistExceptionMessage = "The OpenApi component schema {0} doesn't exist." + timerParameterMustBeGreaterThanZeroExceptionMessage = '[Timer] {0}: {1} must be greater than 0.' + taskTimedOutExceptionMessage = 'Task has timed out after {0}ms.' + scheduleStartTimeAfterEndTimeExceptionMessage = '[Schedule] {0}: Cannot have a StartTime after the EndTime' + infoVersionMandatoryMessage = 'info.version is mandatory.' + cannotUnlockNullObjectExceptionMessage = 'Cannot unlock an object that is null.' + nonEmptyScriptBlockRequiredForCustomAuthExceptionMessage = 'A non-empty ScriptBlock is required for the Custom authentication scheme.' + nonEmptyScriptBlockRequiredForAuthMethodExceptionMessage = 'A non-empty ScriptBlock is required for the authentication method.' + validationOfOneOfSchemaNotSupportedExceptionMessage = "Validation of a schema that includes 'oneof' is not supported." + routeParameterCannotBeNullExceptionMessage = "The parameter 'Route' cannot be null." + cacheStorageAlreadyExistsExceptionMessage = "Cache Storage with name '{0}' already exists." + loggingMethodRequiresValidScriptBlockExceptionMessage = "The supplied output Method for the '{0}' Logging method requires a valid ScriptBlock." + scopedVariableAlreadyDefinedExceptionMessage = 'Scoped Variable already defined: {0}' + oauth2RequiresAuthorizeUrlExceptionMessage = "OAuth2 requires an 'AuthoriseUrl' property to be supplied." + pathNotExistExceptionMessage = 'Path does not exist: {0}' + noDomainServerNameForWindowsAdAuthExceptionMessage = 'No domain server name has been supplied for Windows AD authentication' + suppliedDateAfterScheduleEndTimeExceptionMessage = 'Supplied date is after the end time of the schedule at {0}' + wildcardMethodsIncompatibleWithAutoMethodsExceptionMessage = 'The * wildcard for Methods is incompatible with the AutoMethods switch.' + cannotSupplyIntervalForYearExceptionMessage = 'Cannot supply interval value for every year.' + missingComponentsMessage = 'Missing component(s)' + invalidStrictTransportSecurityDurationExceptionMessage = 'Invalid Strict-Transport-Security duration supplied: {0}. It should be greater than 0.' + noSecretForHmac512ExceptionMessage = 'No secret supplied for HMAC512 hash.' + daysInMonthExceededExceptionMessage = '{0} only has {1} days, but {2} was supplied.' + nonEmptyScriptBlockRequiredForCustomLoggingExceptionMessage = 'A non-empty ScriptBlock is required for the Custom logging output method.' + encodingAttributeOnlyAppliesToMultipartExceptionMessage = 'The encoding attribute only applies to multipart and application/x-www-form-urlencoded request bodies.' + suppliedDateBeforeScheduleStartTimeExceptionMessage = 'Supplied date is before the start time of the schedule at {0}' + unlockSecretRequiredExceptionMessage = "An 'UnlockSecret' property is required when using Microsoft.PowerShell.SecretStore" + noLogicPassedForMethodRouteExceptionMessage = '[{0}] {1}: No logic passed.' + bodyParserAlreadyDefinedForContentTypeExceptionMessage = 'A body-parser is already defined for the {0} content-type.' + invalidJwtSuppliedExceptionMessage = 'Invalid JWT supplied.' + sessionsRequiredForFlashMessagesExceptionMessage = 'Sessions are required to use Flash messages.' + semaphoreAlreadyExistsExceptionMessage = 'A semaphore with the following name already exists: {0}' + invalidJwtHeaderAlgorithmSuppliedExceptionMessage = 'Invalid JWT header algorithm supplied.' + oauth2ProviderDoesNotSupportPasswordGrantTypeExceptionMessage = "The OAuth2 provider does not support the 'password' grant_type required by using an InnerScheme." + invalidAliasFoundExceptionMessage = 'Invalid {0} alias found: {1}' + scheduleDoesNotExistExceptionMessage = "Schedule '{0}' does not exist." + accessMethodNotExistExceptionMessage = 'Access method does not exist: {0}' + oauth2ProviderDoesNotSupportCodeResponseTypeExceptionMessage = "The OAuth2 provider does not support the 'code' response_type." + untestedPowerShellVersionWarningMessage = '[WARNING] Pode {0} has not been tested on PowerShell {1}, as it was not available when Pode was released.' + secretVaultAlreadyRegisteredAutoImportExceptionMessage = "A Secret Vault with the name '{0}' has already been registered while auto-importing Secret Vaults." + schemeRequiresValidScriptBlockExceptionMessage = "The supplied scheme for the '{0}' authentication validator requires a valid ScriptBlock." + serverLoopingMessage = 'Server looping every {0}secs' + certificateThumbprintsNameSupportedOnWindowsExceptionMessage = 'Certificate Thumbprints/Name are only supported on Windows OS.' + sseConnectionNameRequiredExceptionMessage = "An SSE connection Name is required, either from -Name or `$WebEvent.Sse.Name" + invalidMiddlewareTypeExceptionMessage = 'One of the Middlewares supplied is an invalid type. Expected either a ScriptBlock or Hashtable, but got: {0}' + noSecretForJwtSignatureExceptionMessage = 'No secret supplied for JWT signature.' + modulePathDoesNotExistExceptionMessage = 'The module path does not exist: {0}' + taskAlreadyDefinedExceptionMessage = '[Task] {0}: Task already defined.' + verbAlreadyDefinedExceptionMessage = '[Verb] {0}: Already defined' + clientCertificatesOnlySupportedOnHttpsEndpointsExceptionMessage = 'Client certificates are only supported on HTTPS endpoints.' + endpointNameNotExistExceptionMessage = "Endpoint with name '{0}' does not exist." + middlewareNoLogicSuppliedExceptionMessage = '[Middleware]: No logic supplied in ScriptBlock.' + scriptBlockRequiredForMergingUsersExceptionMessage = 'A Scriptblock for merging multiple authenticated users into 1 object is required When Valid is All.' + secretVaultAlreadyRegisteredExceptionMessage = "A Secret Vault with the name '{0}' has already been registered{1}." + deprecatedTitleVersionDescriptionWarningMessage = "WARNING: Title, Version, and Description on 'Enable-PodeOpenApi' are deprecated. Please use 'Add-PodeOAInfo' instead." + undefinedOpenApiReferencesMessage = 'Undefined OpenAPI References:' + doneMessage = 'Done' + swaggerEditorDoesNotSupportOpenApi31ExceptionMessage = "This version on Swagger-Editor doesn't support OpenAPI 3.1" + durationMustBeZeroOrGreaterExceptionMessage = 'Duration must be 0 or greater, but got: {0}s' + viewsPathDoesNotExistExceptionMessage = 'The Views path does not exist: {0}' + discriminatorIncompatibleWithAllOfExceptionMessage = "The parameter 'Discriminator' is incompatible with 'allOf'." + noNameForWebSocketSendMessageExceptionMessage = 'No Name for a WebSocket to send message to supplied.' + hashtableMiddlewareNoLogicExceptionMessage = 'A Hashtable Middleware supplied has no Logic defined.' + openApiInfoMessage = 'OpenAPI Info:' + invalidSchemeForAuthValidatorExceptionMessage = "The supplied '{0}' Scheme for the '{1}' authentication validator requires a valid ScriptBlock." + sseFailedToBroadcastExceptionMessage = 'SSE failed to broadcast due to defined SSE broadcast level for {0}: {1}' + adModuleWindowsOnlyExceptionMessage = 'Active Directory module only available on Windows OS.' + requestLoggingAlreadyEnabledExceptionMessage = 'Request Logging has already been enabled.' + invalidAccessControlMaxAgeDurationExceptionMessage = 'Invalid Access-Control-Max-Age duration supplied: {0}. Should be greater than 0.' + openApiDefinitionAlreadyExistsExceptionMessage = 'OpenAPI definition named {0} already exists.' + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." + taskProcessDoesNotExistExceptionMessage = 'Task process does not exist: {0}' + scheduleProcessDoesNotExistExceptionMessage = 'Schedule process does not exist: {0}' + definitionTagChangeNotAllowedExceptionMessage = 'Definition Tag for a Route cannot be changed.' + getRequestBodyNotAllowedExceptionMessage = '{0} operations cannot have a Request Body.' + unsupportedStreamCompressionEncodingExceptionMessage = 'Unsupported stream compression encoding: {0}' } \ No newline at end of file diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 084d582f0..04fb77bee 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -289,4 +289,5 @@ scheduleProcessDoesNotExistExceptionMessage = 'Schedule process does not exist: {0}' definitionTagChangeNotAllowedExceptionMessage = 'Definition Tag for a Route cannot be changed.' getRequestBodyNotAllowedExceptionMessage = '{0} operations cannot have a Request Body.' + unsupportedStreamCompressionEncodingExceptionMessage = 'Unsupported stream compression encoding: {0}' } \ No newline at end of file diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 3ffa01b37..76e82f66b 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -289,4 +289,5 @@ scheduleProcessDoesNotExistExceptionMessage = "El proceso del programación '{0}' no existe." definitionTagChangeNotAllowedExceptionMessage = 'La etiqueta de definición para una Route no se puede cambiar.' getRequestBodyNotAllowedExceptionMessage = 'Las operaciones {0} no pueden tener un cuerpo de solicitud.' + unsupportedStreamCompressionEncodingExceptionMessage = 'La codificación de compresión de transmisión no es compatible: {0}' } \ No newline at end of file diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index 6c058f1c8..f93325790 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -289,5 +289,6 @@ scheduleProcessDoesNotExistExceptionMessage = "Le processus de l'horaire '{0}' n'existe pas." definitionTagChangeNotAllowedExceptionMessage = 'Le tag de définition pour une Route ne peut pas être modifié.' getRequestBodyNotAllowedExceptionMessage = 'Les opérations {0} ne peuvent pas avoir de corps de requête.' + unsupportedStreamCompressionEncodingExceptionMessage = "La compression de flux {0} n'est pas prise en charge." } diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index 80f855556..63e8e7ef0 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -289,4 +289,5 @@ scheduleProcessDoesNotExistExceptionMessage = "Il processo della programma '{0}' non esiste." definitionTagChangeNotAllowedExceptionMessage = 'Il tag di definizione per una Route non può essere cambiato.' getRequestBodyNotAllowedExceptionMessage = 'Le operazioni {0} non possono avere un corpo della richiesta.' + unsupportedStreamCompressionEncodingExceptionMessage = 'La compressione dello stream non è supportata per la codifica {0}' } \ No newline at end of file diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index eff3aa371..b1af7854d 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -289,4 +289,5 @@ scheduleProcessDoesNotExistExceptionMessage = 'スケジュールプロセスが存在しません: {0}' definitionTagChangeNotAllowedExceptionMessage = 'Routeの定義タグは変更できません。' getRequestBodyNotAllowedExceptionMessage = '{0}操作にはリクエストボディを含めることはできません。' + unsupportedStreamCompressionEncodingExceptionMessage = 'サポートされていないストリーム圧縮エンコーディングが提供されました: {0}' } \ No newline at end of file diff --git a/src/Locales/ko/Pode.psd1 b/src/Locales/ko/Pode.psd1 index 247dd7ae1..4ca2966eb 100644 --- a/src/Locales/ko/Pode.psd1 +++ b/src/Locales/ko/Pode.psd1 @@ -289,4 +289,5 @@ scheduleProcessDoesNotExistExceptionMessage = '스케줄 프로세스가 존재하지 않습니다: {0}' definitionTagChangeNotAllowedExceptionMessage = 'Route에 대한 정의 태그는 변경할 수 없습니다.' getRequestBodyNotAllowedExceptionMessage = '{0} 작업에는 요청 본문이 있을 수 없습니다.' + unsupportedStreamCompressionEncodingExceptionMessage = '지원되지 않는 스트림 압축 인코딩: {0}' } \ No newline at end of file diff --git a/src/Locales/nl/Pode.psd1 b/src/Locales/nl/Pode.psd1 index 916b37ce4..e1d4121c2 100644 --- a/src/Locales/nl/Pode.psd1 +++ b/src/Locales/nl/Pode.psd1 @@ -289,4 +289,5 @@ scheduleProcessDoesNotExistExceptionMessage = "Schema-proces '{0}' bestaat niet." definitionTagChangeNotAllowedExceptionMessage = 'Definitietag voor een route kan niet worden gewijzigd.' getRequestBodyNotAllowedExceptionMessage = '{0}-operaties kunnen geen Request Body hebben.' + unsupportedStreamCompressionEncodingExceptionMessage = 'Niet-ondersteunde streamcompressie-encodering: {0}' } \ No newline at end of file diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index 1e85dbd3b..681761d06 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -289,4 +289,5 @@ scheduleProcessDoesNotExistExceptionMessage = "Proces harmonogramu '{0}' nie istnieje." definitionTagChangeNotAllowedExceptionMessage = 'Tag definicji dla Route nie może zostać zmieniony.' getRequestBodyNotAllowedExceptionMessage = 'Operacje {0} nie mogą mieć treści żądania.' + unsupportedStreamCompressionEncodingExceptionMessage = 'Kodowanie kompresji strumienia nie jest obsługiwane: {0}' } \ No newline at end of file diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index 8e4bf0b9e..a994d46cf 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -289,4 +289,5 @@ scheduleProcessDoesNotExistExceptionMessage = "O processo do cronograma '{0}' não existe." definitionTagChangeNotAllowedExceptionMessage = 'A Tag de definição para uma Route não pode ser alterada.' getRequestBodyNotAllowedExceptionMessage = 'As operações {0} não podem ter um corpo de solicitação.' + unsupportedStreamCompressionEncodingExceptionMessage = 'A codificação de compressão de fluxo não é suportada.' } \ No newline at end of file diff --git a/src/Locales/zh/Pode.psd1 b/src/Locales/zh/Pode.psd1 index 5604f41f9..c0dba34c6 100644 --- a/src/Locales/zh/Pode.psd1 +++ b/src/Locales/zh/Pode.psd1 @@ -289,4 +289,5 @@ scheduleProcessDoesNotExistExceptionMessage = "计划进程 '{0}' 不存在。" definitionTagChangeNotAllowedExceptionMessage = 'Route的定义标签无法更改。' getRequestBodyNotAllowedExceptionMessage = '{0} 操作不能包含请求体。' + unsupportedStreamCompressionEncodingExceptionMessage = '不支持的流压缩编码: {0}' } \ No newline at end of file diff --git a/src/Private/Serverless.ps1 b/src/Private/Serverless.ps1 index 7bf51f3b8..a0cebb6b1 100644 --- a/src/Private/Serverless.ps1 +++ b/src/Private/Serverless.ps1 @@ -22,7 +22,7 @@ function Start-PodeAzFuncServer { $request = $Data.Request # setup the response - $response = [HttpResponseContext]::new() + $response = New-PodeAzFuncResponse $response.StatusCode = 200 $response.Headers = @{} @@ -125,6 +125,10 @@ function Start-PodeAzFuncServer { } } +function New-PodeAzFuncResponse { + return [HttpResponseContext]::new() +} + function Start-PodeAwsLambdaServer { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')] param( diff --git a/src/Private/Streams.ps1 b/src/Private/Streams.ps1 index d8e007187..261ca3586 100644 --- a/src/Private/Streams.ps1 +++ b/src/Private/Streams.ps1 @@ -319,8 +319,8 @@ function Get-PodeCompressionStream { } default { - #TODO: localize - throw "Unsupported encoding: $Encoding" + # Unsupported stream compression encoding: $Encoding + throw ($PodeLocale.unsupportedStreamCompressionEncodingExceptionMessage -f $Encoding) } } } diff --git a/tests/unit/Localization.Tests.ps1 b/tests/unit/Localization.Tests.ps1 index 5c4e7a1d5..593d3d215 100644 --- a/tests/unit/Localization.Tests.ps1 +++ b/tests/unit/Localization.Tests.ps1 @@ -54,14 +54,13 @@ Describe 'Localization Check' { } } - - It 'Check `throw` is not using a static string in [<_>]' -ForEach ($sourceFiles) { + It "Check 'throw' is not using a static string in [<_>]" -ForEach ($sourceFiles) { ( Get-Content -Path $_ -Raw) -match 'throw\s*["\'']' | Should -BeFalse } Describe 'Verifying Language [<_>]' -ForEach ($languageDirs) { - BeforeAll { + BeforeAll { $content = Import-LocalizedData -FileName 'Pode.psd1' -BaseDirectory $localizationDir -UICulture (Split-Path $_ -Leaf) } it 'Language resource file exist' { diff --git a/tests/unit/Server.Tests.ps1 b/tests/unit/Server.Tests.ps1 index 05ef5167a..6056b581c 100644 --- a/tests/unit/Server.Tests.ps1 +++ b/tests/unit/Server.Tests.ps1 @@ -108,10 +108,11 @@ Describe 'Restart-PodeInternalServer' { Mock Close-PodeDisposable { } Mock Invoke-PodeEvent { } } + It 'Resetting the server values' { $PodeContext = @{ Tokens = @{ - Cancellation = [ystem.Threading.CancellationTokenSource]::new() + Cancellation = [System.Threading.CancellationTokenSource]::new() Restart = [System.Threading.CancellationTokenSource]::new() } Server = @{ diff --git a/tests/unit/Serverless.Tests.ps1 b/tests/unit/Serverless.Tests.ps1 index 325bc3336..66f29c59c 100644 --- a/tests/unit/Serverless.Tests.ps1 +++ b/tests/unit/Serverless.Tests.ps1 @@ -17,7 +17,7 @@ Describe 'Start-PodeAzFuncServer' { Mock Get-PodeRouteValidateMiddleware { } Mock Get-PodeBodyMiddleware { } Mock Get-PodeCookieMiddleware { } - Mock New-Object { return @{} } + Mock New-PodeAzFuncResponse { return @{} } Mock Get-PodeHeader { return 'some-value' } Mock Invoke-PodeScriptBlock { } Mock Write-Host { } From c4b378c9fd3c7c85c766f0c0e106db6da2d91aa9 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Mon, 23 Sep 2024 08:27:36 -0700 Subject: [PATCH 167/177] remove trail space --- src/Public/Tasks.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Public/Tasks.ps1 b/src/Public/Tasks.ps1 index c526a9169..b782469a6 100644 --- a/src/Public/Tasks.ps1 +++ b/src/Public/Tasks.ps1 @@ -483,7 +483,6 @@ function Wait-PodeTask { throw ($PodeLocale.invalidTaskTypeExceptionMessage) } } - <# .SYNOPSIS From b444349d2ee4b8c974cba910113f306f7df64156 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Mon, 23 Sep 2024 17:03:29 -0700 Subject: [PATCH 168/177] Update SSE.ps1 --- src/Public/SSE.ps1 | 90 ++++++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 38 deletions(-) diff --git a/src/Public/SSE.ps1 b/src/Public/SSE.ps1 index 07b708612..2d82665af 100644 --- a/src/Public/SSE.ps1 +++ b/src/Public/SSE.ps1 @@ -201,8 +201,11 @@ Send-PodeSseEvent -Name 'Actions' -Group 'admins' -Data @{ Message = 'A message' Send-PodeSseEvent -Name 'Actions' -Data @{ Message = 'A message' } -ID 123 -EventType 'action' #> function Send-PodeSseEvent { - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = 'WebEvent')] param( + [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] + $Data, + [Parameter(Mandatory = $true, ParameterSetName = 'Name')] [string] $Name, @@ -223,9 +226,6 @@ function Send-PodeSseEvent { [string] $EventType, - [Parameter(Mandatory = $true)] - $Data, - [Parameter()] [int] $Depth = 10, @@ -235,50 +235,64 @@ function Send-PodeSseEvent { $FromEvent ) - # do nothing if no value - if (($null -eq $Data) -or ([string]::IsNullOrEmpty($Data))) { - return - } - # jsonify the value - if ($Data -isnot [string]) { - if ($Depth -le 0) { - $Data = (ConvertTo-Json -InputObject $Data -Compress) - } - else { - $Data = (ConvertTo-Json -InputObject $Data -Depth $Depth -Compress) + begin { + $pipelineValue = @() + # do nothing if no value + if (($null -eq $Data) -or ([string]::IsNullOrEmpty($Data))) { + return } } - # send directly back to current connection - if ($FromEvent -and $WebEvent.Sse.IsLocal) { - $null = Wait-PodeTask -Task $WebEvent.Response.SendSseEvent($EventType, $Data, $Id) - return + process { + if ($PSCmdlet.ParameterSetName -eq 'Value') { + $pipelineValue += $_ + } } - # from event and global? - if ($FromEvent) { - $Name = $WebEvent.Sse.Name - $Group = $WebEvent.Sse.Group - $ClientId = $WebEvent.Sse.ClientId - } + end { + if ($pipelineValue.Count -gt 1) { + $Data = $pipelineValue + } + # jsonify the value + if ($Data -isnot [string]) { + if ($Depth -le 0) { + $Data = (ConvertTo-Json -InputObject $Data -Compress) + } + else { + $Data = (ConvertTo-Json -InputObject $Data -Depth $Depth -Compress) + } + } - # error if no name - if ([string]::IsNullOrEmpty($Name)) { - # An SSE connection Name is required, either from -Name or $WebEvent.Sse.Name - throw ($PodeLocale.sseConnectionNameRequiredExceptionMessage) - } + # send directly back to current connection + if ($FromEvent -and $WebEvent.Sse.IsLocal) { + $null = Wait-PodeTask -Task $WebEvent.Response.SendSseEvent($EventType, $Data, $Id) + return + } - # check if broadcast level - if (!(Test-PodeSseBroadcastLevel -Name $Name -Group $Group -ClientId $ClientId)) { - # SSE failed to broadcast due to defined SSE broadcast level - throw ($PodeLocale.sseFailedToBroadcastExceptionMessage -f $Name, (Get-PodeSseBroadcastLevel -Name $Name)) - } + # from event and global? + if ($FromEvent) { + $Name = $WebEvent.Sse.Name + $Group = $WebEvent.Sse.Group + $ClientId = $WebEvent.Sse.ClientId + } - # send event - $PodeContext.Server.Http.Listener.SendSseEvent($Name, $Group, $ClientId, $EventType, $Data, $Id) -} + # error if no name + if ([string]::IsNullOrEmpty($Name)) { + # An SSE connection Name is required, either from -Name or $WebEvent.Sse.Name + throw ($PodeLocale.sseConnectionNameRequiredExceptionMessage) + } + + # check if broadcast level + if (!(Test-PodeSseBroadcastLevel -Name $Name -Group $Group -ClientId $ClientId)) { + # SSE failed to broadcast due to defined SSE broadcast level + throw ($PodeLocale.sseFailedToBroadcastExceptionMessage -f $Name, (Get-PodeSseBroadcastLevel -Name $Name)) + } + # send event + $PodeContext.Server.Http.Listener.SendSseEvent($Name, $Group, $ClientId, $EventType, $Data, $Id) + } +} <# .SYNOPSIS Close one or more SSE connections. From 23c07ba26894f67208159f84267649b059abf1d5 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Wed, 25 Sep 2024 14:16:53 -0700 Subject: [PATCH 169/177] replace Get-PodeOrderedDictionaryClone with Copy-PodeDeepClone --- src/Private/Helpers.ps1 | 67 ++++++++++++++++++++++++++++++++----- src/Public/OAComponents.ps1 | 2 +- src/Public/OpenApi.ps1 | 2 +- src/Public/Routes.ps1 | 2 +- 4 files changed, 61 insertions(+), 12 deletions(-) diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index 21108cc6e..dfb70d1c2 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -3750,19 +3750,68 @@ function Resolve-PodeObjectArray { } } +<# +.SYNOPSIS + Creates a deep clone of a PSObject by serializing and deserializing the object. + +.DESCRIPTION + The Copy-PodeDeepClone function takes a PSObject as input and creates a deep clone of it. + This is achieved by serializing the object using the PSSerializer class, and then + deserializing it back into a new instance. This method ensures that nested objects, arrays, + and other complex structures are copied fully, without sharing references between the original + and the cloned object. + +.PARAMETER InputObject + The PSObject that you want to deep clone. This object will be serialized and then deserialized + to create a deep copy. -function Get-PodeOrderedDictionaryClone { +.PARAMETER Deep + Specifies the depth for the serialization. The depth controls how deeply nested objects + and properties are serialized. The default value is 10. + +.INPUTS + [PSObject] - The function accepts a PSObject to deep clone. + +.OUTPUTS + [PSObject] - The function returns a new PSObject that is a deep clone of the original. + +.EXAMPLE + $originalObject = [PSCustomObject]@{ + Name = 'John Doe' + Age = 30 + Address = [PSCustomObject]@{ + Street = '123 Main St' + City = 'Anytown' + Zip = '12345' + } + } + + $clonedObject = $originalObject | Copy-PodeDeepClone -Deep 15 + + # The $clonedObject is now a deep clone of $originalObject. + # Changes to $clonedObject will not affect $originalObject and vice versa. + +.NOTES + This function uses the System.Management.Automation.PSSerializer class, which is available in + PowerShell 5.1 and later versions. The default depth parameter is set to 10 to handle nested + objects appropriately, but it can be customized via the -Deep parameter. + This is an internal function and may change in future releases of Pode. +#> +function Copy-PodeDeepClone { param ( - [System.Collections.Specialized.OrderedDictionary]$Original + [Parameter(Mandatory, ValueFromPipeline)] + [PSObject]$InputObject, + + [Parameter()] + [int]$Deep = 10 ) - # Create a new ordered dictionary to hold the clone - $clone = [System.Collections.Specialized.OrderedDictionary]::new() + process { + # Serialize the object to XML format using PSSerializer + # The depth parameter controls how deeply nested objects are serialized + $xmlSerializer = [System.Management.Automation.PSSerializer]::Serialize($InputObject, $Deep) - # Copy each key-value pair from the original to the clone - foreach ($key in $Original.Keys) { - $clone.Add($key, $Original[$key]) + # Deserialize the XML back into a new PSObject, creating a deep clone of the original + return [System.Management.Automation.PSSerializer]::Deserialize($xmlSerializer) } - - return $clone } \ No newline at end of file diff --git a/src/Public/OAComponents.ps1 b/src/Public/OAComponents.ps1 index 6602156cd..8fd892b26 100644 --- a/src/Public/OAComponents.ps1 +++ b/src/Public/OAComponents.ps1 @@ -751,7 +751,7 @@ function Add-PodeOAComponentPathItem { } #add the default OpenApi responses if ( $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses) { - $refRoute.OpenApi.Responses = Get-PodeOrderedDictionaryClone -Source $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses + $refRoute.OpenApi.Responses = Copy-PodeDeepClone -InputObject $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses } $PodeContext.Server.OpenAPI.Definitions[$tag].components.pathItems[$Name] = $refRoute } diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index a128aa139..33125b972 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -3238,7 +3238,7 @@ function Add-PodeOAExternalRoute { foreach ($tag in $DefinitionTag) { #add the default OpenApi responses if ( $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses) { - $extRoute.OpenApi.Responses = Get-PodeOrderedDictionaryClone -Source $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses + $extRoute.OpenApi.Responses = Copy-PodeDeepClone -InputObject $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses } if (! (Test-PodeOAComponentExternalPath -DefinitionTag $tag -Name $Path)) { $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.externalPath[$Path] = [ordered]@{} diff --git a/src/Public/Routes.ps1 b/src/Public/Routes.ps1 index 4f138f4a9..32694734a 100644 --- a/src/Public/Routes.ps1 +++ b/src/Public/Routes.ps1 @@ -399,7 +399,7 @@ function Add-PodeRoute { if ( $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.defaultResponses) { $DefaultResponse = [ordered]@{} foreach ($tag in $DefinitionTag) { - $DefaultResponse[$tag] = Get-PodeOrderedDictionaryClone -Source $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses + $DefaultResponse[$tag] = Copy-PodeDeepClone -InputObject $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses } } From 5465d03c7d49c6da15e0508105b9923efa53cbaf Mon Sep 17 00:00:00 2001 From: mdaneri Date: Wed, 25 Sep 2024 15:08:03 -0700 Subject: [PATCH 170/177] Removed unnecessary Piping --- src/Private/Helpers.ps1 | 201 +++++++++++------------------------ src/Private/Responses.ps1 | 112 +++++++++---------- src/Private/Server.ps1 | 8 +- tests/unit/Helpers.Tests.ps1 | 19 ---- 4 files changed, 117 insertions(+), 223 deletions(-) diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index 595e4e9a7..765194895 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -924,80 +924,19 @@ function Remove-PodeEmptyItemsFromArray { [CmdletBinding()] [OutputType([System.Object[]])] param( - [Parameter(ValueFromPipeline = $true)] + [Parameter()] $Array ) - begin { - # Initialize an array to hold piped-in values - $pipelineValue = @() + # Set Array to the array of values + if ($pipelineValue.Count -gt 1) { + $Array = $pipelineValue } - process { - # Add the current piped-in value to the array - $pipelineValue += $_ + if ($null -eq $Array) { + return @() } - end { - # Set Array to the array of values - if ($pipelineValue.Count -gt 1) { - $Array = $pipelineValue - } - if ($null -eq $Array) { - return @() - } - return @( @($Array -ne ([string]::Empty)) -ne $null ) - } -} + return @( @($Array -ne ([string]::Empty)) -ne $null ) -function Remove-PodeNullKeysFromHashtable { - param( - [Parameter(ValueFromPipeline = $true)] - [hashtable] - $Hashtable - ) - begin { - $pipelineItemCount = 0 - } - - process { - $pipelineItemCount++ - } - - end { - if ($pipelineItemCount -gt 1) { - throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) - } - foreach ($key in ($Hashtable.Clone()).Keys) { - if ($null -eq $Hashtable[$key]) { - $null = $Hashtable.Remove($key) - continue - } - - if (($Hashtable[$key] -is [string]) -and [string]::IsNullOrEmpty($Hashtable[$key])) { - $null = $Hashtable.Remove($key) - continue - } - - if ($Hashtable[$key] -is [array]) { - if (($Hashtable[$key].Length -eq 1) -and ($null -eq $Hashtable[$key][0])) { - $null = $Hashtable.Remove($key) - continue - } - - foreach ($item in $Hashtable[$key]) { - if (($item -is [hashtable]) -or ($item -is [System.Collections.Specialized.OrderedDictionary])) { - $item | Remove-PodeNullKeysFromHashtable - } - } - - continue - } - - if (($Hashtable[$key] -is [hashtable]) -or ($Hashtable[$key] -is [System.Collections.Specialized.OrderedDictionary])) { - $Hashtable[$key] | Remove-PodeNullKeysFromHashtable - continue - } - } - } } <# @@ -1143,7 +1082,7 @@ function Test-PodeValidNetworkFailure { function ConvertFrom-PodeHeaderQValue { param( - [Parameter(ValueFromPipeline = $true)] + [Parameter()] [string] $Value ) @@ -1442,7 +1381,7 @@ function New-PodeRequestException { function ConvertTo-PodeResponseContent { param( - [Parameter(Position = 0, ValueFromPipeline = $true)] + [Parameter()] $InputObject, [Parameter()] @@ -1460,32 +1399,31 @@ function ConvertTo-PodeResponseContent { [switch] $AsHtml ) - process { - # split for the main content type - $ContentType = Split-PodeContentType -ContentType $ContentType + # split for the main content type + $ContentType = Split-PodeContentType -ContentType $ContentType - # if there is no content-type then convert straight to string - if ([string]::IsNullOrWhiteSpace($ContentType)) { - return ([string]$InputObject) - } + # if there is no content-type then convert straight to string + if ([string]::IsNullOrWhiteSpace($ContentType)) { + return ([string]$InputObject) + } - # run action for the content type - switch ($ContentType) { - { $_ -match '^(.*\/)?(.*\+)?json$' } { - if ($InputObject -isnot [string]) { - if ($Depth -le 0) { - return (ConvertTo-Json -InputObject $InputObject -Compress) - } - else { - return (ConvertTo-Json -InputObject $InputObject -Depth $Depth -Compress) - } + # run action for the content type + switch ($ContentType) { + { $_ -match '^(.*\/)?(.*\+)?json$' } { + if ($InputObject -isnot [string]) { + if ($Depth -le 0) { + return (ConvertTo-Json -InputObject $InputObject -Compress) } - - if ([string]::IsNullOrWhiteSpace($InputObject)) { - return '{}' + else { + return (ConvertTo-Json -InputObject $InputObject -Depth $Depth -Compress) } } + if ([string]::IsNullOrWhiteSpace($InputObject)) { + return '{}' + } + } + { $_ -match '^(.*\/)?(.*\+)?yaml$' } { if ($InputObject -isnot [string]) { if ($Depth -le 0) { @@ -1496,10 +1434,10 @@ function ConvertTo-PodeResponseContent { } } - if ([string]::IsNullOrWhiteSpace($InputObject)) { - return '[]' - } + if ([string]::IsNullOrWhiteSpace($InputObject)) { + return '[]' } + } { $_ -match '^(.*\/)?(.*\+)?xml$' } { if ($InputObject -isnot [string]) { @@ -1507,13 +1445,13 @@ function ConvertTo-PodeResponseContent { [pscustomobject]$item }) - return ($temp | ConvertTo-Xml -Depth $Depth -As String -NoTypeInformation) - } + return ($temp | ConvertTo-Xml -Depth $Depth -As String -NoTypeInformation) + } - if ([string]::IsNullOrWhiteSpace($InputObject)) { - return [string]::Empty - } + if ([string]::IsNullOrWhiteSpace($InputObject)) { + return [string]::Empty } + } { $_ -ilike '*/csv' } { if ($InputObject -isnot [string]) { @@ -1521,40 +1459,39 @@ function ConvertTo-PodeResponseContent { [pscustomobject]$item }) - if (Test-PodeIsPSCore) { - $temp = ($temp | ConvertTo-Csv -Delimiter $Delimiter -IncludeTypeInformation:$false) - } - else { - $temp = ($temp | ConvertTo-Csv -Delimiter $Delimiter -NoTypeInformation) - } - - return ($temp -join ([environment]::NewLine)) + if (Test-PodeIsPSCore) { + $temp = ($temp | ConvertTo-Csv -Delimiter $Delimiter -IncludeTypeInformation:$false) } - - if ([string]::IsNullOrWhiteSpace($InputObject)) { - return [string]::Empty + else { + $temp = ($temp | ConvertTo-Csv -Delimiter $Delimiter -NoTypeInformation) } + + return ($temp -join ([environment]::NewLine)) } - { $_ -ilike '*/html' } { - if ($InputObject -isnot [string]) { - return (($InputObject | ConvertTo-Html) -join ([environment]::NewLine)) - } + if ([string]::IsNullOrWhiteSpace($InputObject)) { + return [string]::Empty + } + } - if ([string]::IsNullOrWhiteSpace($InputObject)) { - return [string]::Empty - } + { $_ -ilike '*/html' } { + if ($InputObject -isnot [string]) { + return (($InputObject | ConvertTo-Html) -join ([environment]::NewLine)) } - { $_ -ilike '*/markdown' } { - if ($AsHtml -and ($PSVersionTable.PSVersion.Major -ge 7)) { - return ($InputObject | ConvertFrom-Markdown).Html - } + if ([string]::IsNullOrWhiteSpace($InputObject)) { + return [string]::Empty } } - return ([string]$InputObject) + { $_ -ilike '*/markdown' } { + if ($AsHtml -and ($PSVersionTable.PSVersion.Major -ge 7)) { + return ($InputObject | ConvertFrom-Markdown).Html + } + } } + + return ([string]$InputObject) } function ConvertFrom-PodeRequestContent { @@ -3085,29 +3022,17 @@ function Find-PodeModuleFile { #> function Clear-PodeHashtableInnerKey { param( - [Parameter(ValueFromPipeline = $true)] + [Parameter()] [hashtable] $InputObject ) - begin { - $pipelineItemCount = 0 - } - process { - $pipelineItemCount++ + if (Test-PodeIsEmpty $InputObject) { + return } - end { - if ($pipelineItemCount -gt 1) { - throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) - } - if (Test-PodeIsEmpty $InputObject) { - return - } - - $InputObject.Keys.Clone() | ForEach-Object { - $InputObject[$_].Clear() - } + $InputObject.Keys.Clone() | ForEach-Object { + $InputObject[$_].Clear() } } diff --git a/src/Private/Responses.ps1 b/src/Private/Responses.ps1 index 075daa0c0..f16cd7e9c 100644 --- a/src/Private/Responses.ps1 +++ b/src/Private/Responses.ps1 @@ -133,7 +133,7 @@ This is an internal function and may change in future releases of Pode. function Write-PodeFileResponseInternal { [CmdletBinding()] param ( - [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true)] [ValidateNotNull()] [string] $Path, @@ -159,80 +159,68 @@ function Write-PodeFileResponseInternal { [switch] $FileBrowser ) - begin { - $pipelineItemCount = 0 - } - - process { - $pipelineItemCount++ - } - end { - if ($pipelineItemCount -gt 1) { - throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) - } - # Attempt to retrieve information about the path - $pathInfo = Test-PodePath -Path $Path -Force -ReturnItem -FailOnDirectory:(!$FileBrowser) + # Attempt to retrieve information about the path + $pathInfo = Test-PodePath -Path $Path -Force -ReturnItem -FailOnDirectory:(!$FileBrowser) - if (!$pathinfo) { - return - } + if (!$pathinfo) { + return + } - # Check if the path is a directory - if ( $pathInfo.PSIsContainer) { - # If directory browsing is enabled, use the directory response function - Write-PodeDirectoryResponseInternal -Path $Path - } - else { - # are we dealing with a dynamic file for the view engine? (ignore html) - # Determine if the file is dynamic and should be processed by the view engine - $mainExt = $pathInfo.Extension.TrimStart('.') + # Check if the path is a directory + if ( $pathInfo.PSIsContainer) { + # If directory browsing is enabled, use the directory response function + Write-PodeDirectoryResponseInternal -Path $Path + } + else { + # are we dealing with a dynamic file for the view engine? (ignore html) + # Determine if the file is dynamic and should be processed by the view engine + $mainExt = $pathInfo.Extension.TrimStart('.') - # generate dynamic content - if (![string]::IsNullOrWhiteSpace($mainExt) -and ( + # generate dynamic content + if (![string]::IsNullOrWhiteSpace($mainExt) -and ( ($mainExt -ieq 'pode') -or ($mainExt -ieq $PodeContext.Server.ViewEngine.Extension -and $PodeContext.Server.ViewEngine.IsDynamic) - ) - ) { - # Process dynamic content with the view engine - $content = Get-PodeFileContentUsingViewEngine -Path $Path -Data $Data + ) + ) { + # Process dynamic content with the view engine + $content = Get-PodeFileContentUsingViewEngine -Path $Path -Data $Data - # Determine the correct content type for the response - # get the sub-file extension, if empty, use original - $subExt = [System.IO.Path]::GetExtension($pathInfo.BaseName).TrimStart('.') + # Determine the correct content type for the response + # get the sub-file extension, if empty, use original + $subExt = [System.IO.Path]::GetExtension($pathInfo.BaseName).TrimStart('.') - $subExt = (Protect-PodeValue -Value $subExt -Default $mainExt) + $subExt = (Protect-PodeValue -Value $subExt -Default $mainExt) - $ContentType = (Protect-PodeValue -Value $ContentType -Default (Get-PodeContentType -Extension $subExt)) + $ContentType = (Protect-PodeValue -Value $ContentType -Default (Get-PodeContentType -Extension $subExt)) - # Write the processed content as the HTTP response - Write-PodeTextResponse -Value $content -ContentType $ContentType -StatusCode $StatusCode - } - # this is a static file - else { - try { - if (Test-PodeIsPSCore) { - $content = (Get-Content -Path $Path -Raw -AsByteStream) - } - else { - $content = (Get-Content -Path $Path -Raw -Encoding byte) - } - # Determine and set the content type for static files - $ContentType = Protect-PodeValue -Value $ContentType -Default (Get-PodeContentType -Extension $mainExt) - # Write the file content as the HTTP response - Write-PodeTextResponse -Bytes $content -ContentType $ContentType -MaxAge $MaxAge -StatusCode $StatusCode -Cache:$Cache - return - } - catch [System.UnauthorizedAccessException] { - $statusCode = 401 + # Write the processed content as the HTTP response + Write-PodeTextResponse -Value $content -ContentType $ContentType -StatusCode $StatusCode + } + # this is a static file + else { + try { + if (Test-PodeIsPSCore) { + $content = (Get-Content -Path $Path -Raw -AsByteStream) } - catch { - $statusCode = 400 + else { + $content = (Get-Content -Path $Path -Raw -Encoding byte) } - # If the file does not exist, set the HTTP response status code appropriately - Set-PodeResponseStatus -Code $StatusCode - + # Determine and set the content type for static files + $ContentType = Protect-PodeValue -Value $ContentType -Default (Get-PodeContentType -Extension $mainExt) + # Write the file content as the HTTP response + Write-PodeTextResponse -Bytes $content -ContentType $ContentType -MaxAge $MaxAge -StatusCode $StatusCode -Cache:$Cache + return } + catch [System.UnauthorizedAccessException] { + $statusCode = 401 + } + catch { + $statusCode = 400 + } + # If the file does not exist, set the HTTP response status code appropriately + Set-PodeResponseStatus -Code $StatusCode + } } } diff --git a/src/Private/Server.ps1 b/src/Private/Server.ps1 index 547c3fa60..ea4fa1f87 100644 --- a/src/Private/Server.ps1 +++ b/src/Private/Server.ps1 @@ -236,9 +236,9 @@ function Restart-PodeInternalServer { $PodeContext.Server.Modules.Clear() # clear up timers, schedules and loggers - $PodeContext.Server.Routes | Clear-PodeHashtableInnerKey - $PodeContext.Server.Handlers | Clear-PodeHashtableInnerKey - $PodeContext.Server.Events | Clear-PodeHashtableInnerKey + Clear-PodeHashtableInnerKey -InputObject $PodeContext.Server.Routes + Clear-PodeHashtableInnerKey -InputObject $PodeContext.Server.Handlers + Clear-PodeHashtableInnerKey -InputObject $PodeContext.Server.Events if ($null -ne $PodeContext.Server.Verbs) { $PodeContext.Server.Verbs.Clear() @@ -271,7 +271,7 @@ function Restart-PodeInternalServer { # clear security headers $PodeContext.Server.Security.Headers.Clear() - $PodeContext.Server.Security.Cache | Clear-PodeHashtableInnerKey + Clear-PodeHashtableInnerKey -InputObject $PodeContext.Server.Security.Cache # clear endpoints $PodeContext.Server.Endpoints.Clear() diff --git a/tests/unit/Helpers.Tests.ps1 b/tests/unit/Helpers.Tests.ps1 index 2fff34c43..76c2c716a 100644 --- a/tests/unit/Helpers.Tests.ps1 +++ b/tests/unit/Helpers.Tests.ps1 @@ -1315,25 +1315,6 @@ Describe 'Out-PodeHost' { } } -Describe 'Remove-PodeNullKeysFromHashtable' { - It 'Removes all null values keys' { - $ht = @{ - Value1 = $null - Value2 = @{ - Value3 = @() - Value4 = $null - } - } - - $ht | Remove-PodeNullKeysFromHashtable - - $ht.ContainsKey('Value1') | Should -Be $false - $ht.ContainsKey('Value2') | Should -Be $true - $ht.Value2.ContainsKey('Value3') | Should -Be $true - $ht.Value2.ContainsKey('Value4') | Should -Be $false - } -} - Describe 'Get-PodeDefaultPort' { It 'Returns default port for http' { Get-PodeDefaultPort -Protocol Http | Should -Be 8080 From 71b3567234f4125ea5d1cb99d320ff686cadb39d Mon Sep 17 00:00:00 2001 From: mdaneri Date: Thu, 26 Sep 2024 14:26:19 -0700 Subject: [PATCH 171/177] Rename Copy-PodeDeepClone to Copy-PodeObjectDeepClone --- src/Private/Helpers.ps1 | 12 ++++++------ src/Public/OAComponents.ps1 | 2 +- src/Public/OpenApi.ps1 | 2 +- src/Public/Routes.ps1 | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index dfb70d1c2..786132744 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -3755,7 +3755,7 @@ function Resolve-PodeObjectArray { Creates a deep clone of a PSObject by serializing and deserializing the object. .DESCRIPTION - The Copy-PodeDeepClone function takes a PSObject as input and creates a deep clone of it. + The Copy-PodeObjectDeepClone function takes a PSObject as input and creates a deep clone of it. This is achieved by serializing the object using the PSSerializer class, and then deserializing it back into a new instance. This method ensures that nested objects, arrays, and other complex structures are copied fully, without sharing references between the original @@ -3765,7 +3765,7 @@ function Resolve-PodeObjectArray { The PSObject that you want to deep clone. This object will be serialized and then deserialized to create a deep copy. -.PARAMETER Deep +.PARAMETER Depth Specifies the depth for the serialization. The depth controls how deeply nested objects and properties are serialized. The default value is 10. @@ -3786,7 +3786,7 @@ function Resolve-PodeObjectArray { } } - $clonedObject = $originalObject | Copy-PodeDeepClone -Deep 15 + $clonedObject = $originalObject | Copy-PodeObjectDeepClone -Deep 15 # The $clonedObject is now a deep clone of $originalObject. # Changes to $clonedObject will not affect $originalObject and vice versa. @@ -3797,19 +3797,19 @@ function Resolve-PodeObjectArray { objects appropriately, but it can be customized via the -Deep parameter. This is an internal function and may change in future releases of Pode. #> -function Copy-PodeDeepClone { +function Copy-PodeObjectDeepClone { param ( [Parameter(Mandatory, ValueFromPipeline)] [PSObject]$InputObject, [Parameter()] - [int]$Deep = 10 + [int]$Depth = 10 ) process { # Serialize the object to XML format using PSSerializer # The depth parameter controls how deeply nested objects are serialized - $xmlSerializer = [System.Management.Automation.PSSerializer]::Serialize($InputObject, $Deep) + $xmlSerializer = [System.Management.Automation.PSSerializer]::Serialize($InputObject, $Depth) # Deserialize the XML back into a new PSObject, creating a deep clone of the original return [System.Management.Automation.PSSerializer]::Deserialize($xmlSerializer) diff --git a/src/Public/OAComponents.ps1 b/src/Public/OAComponents.ps1 index 8fd892b26..386b0e838 100644 --- a/src/Public/OAComponents.ps1 +++ b/src/Public/OAComponents.ps1 @@ -751,7 +751,7 @@ function Add-PodeOAComponentPathItem { } #add the default OpenApi responses if ( $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses) { - $refRoute.OpenApi.Responses = Copy-PodeDeepClone -InputObject $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses + $refRoute.OpenApi.Responses = Copy-PodeObjectDeepClone -InputObject $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses } $PodeContext.Server.OpenAPI.Definitions[$tag].components.pathItems[$Name] = $refRoute } diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index 33125b972..e910e331c 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -3238,7 +3238,7 @@ function Add-PodeOAExternalRoute { foreach ($tag in $DefinitionTag) { #add the default OpenApi responses if ( $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses) { - $extRoute.OpenApi.Responses = Copy-PodeDeepClone -InputObject $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses + $extRoute.OpenApi.Responses = Copy-PodeObjectDeepClone -InputObject $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses } if (! (Test-PodeOAComponentExternalPath -DefinitionTag $tag -Name $Path)) { $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.externalPath[$Path] = [ordered]@{} diff --git a/src/Public/Routes.ps1 b/src/Public/Routes.ps1 index 32694734a..3f444f52b 100644 --- a/src/Public/Routes.ps1 +++ b/src/Public/Routes.ps1 @@ -399,7 +399,7 @@ function Add-PodeRoute { if ( $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.defaultResponses) { $DefaultResponse = [ordered]@{} foreach ($tag in $DefinitionTag) { - $DefaultResponse[$tag] = Copy-PodeDeepClone -InputObject $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses + $DefaultResponse[$tag] = Copy-PodeObjectDeepClone -InputObject $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses } } From 061a98459995200f844042e4ef4f78435077c300 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Fri, 27 Sep 2024 09:35:45 +0100 Subject: [PATCH 172/177] #1392: fix for User being needlessly splatted when passed to scriptblock, and fixes session scoped var when remapping --- examples/Web-AuthFormFile.ps1 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/Web-AuthFormFile.ps1 b/examples/Web-AuthFormFile.ps1 index f15add1be..70f55c320 100644 --- a/examples/Web-AuthFormFile.ps1 +++ b/examples/Web-AuthFormFile.ps1 @@ -60,17 +60,21 @@ Start-PodeServer -Threads 2 { Enable-PodeSessionMiddleware -Duration 120 -Extend # setup form auth against user file (
in HTML) - New-PodeAuthScheme -Form | Add-PodeAuthUserFile -Name 'Login' -FilePath './users/users.json' -FailureUrl '/login' -SuccessUrl '/' + New-PodeAuthScheme -Form | Add-PodeAuthUserFile -Name 'Login' -FilePath './users/users.json' -FailureUrl '/login' -SuccessUrl '/' -ScriptBlock { + param($user) + return @{ User = $user } + } # home page: # redirects to login page if not authenticated Add-PodeRoute -Method Get -Path '/' -Authentication Login -ScriptBlock { $WebEvent.Session.Data.Views++ + $session:TestData | Out-Default Write-PodeViewResponse -Path 'auth-home' -Data @{ Username = $WebEvent.Auth.User.Name - Views = $WebEvent.Session.Data.Views + Views = $WebEvent.Session.Data.Views } } From e55dd4c6a68e44f5daf776a08816d72fde773112 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Fri, 27 Sep 2024 09:38:25 +0100 Subject: [PATCH 173/177] #1392: helps if you're in the right folder to push all changes! --- src/Private/Authentication.ps1 | 9 +++------ src/Private/ScopedVariables.ps1 | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Private/Authentication.ps1 b/src/Private/Authentication.ps1 index 03f0187c4..f5a2273fd 100644 --- a/src/Private/Authentication.ps1 +++ b/src/Private/Authentication.ps1 @@ -856,13 +856,10 @@ function Invoke-PodeAuthInbuiltScriptBlock { $ScriptBlock, [Parameter()] - $UsingVariables, - - [switch] - $NoSplat + $UsingVariables ) - return (Invoke-PodeScriptBlock -ScriptBlock $ScriptBlock -Arguments $User -UsingVariables $UsingVariables -Return -Splat:(!$NoSplat)) + return (Invoke-PodeScriptBlock -ScriptBlock $ScriptBlock -Arguments $User -UsingVariables $UsingVariables -Return) } function Get-PodeAuthWindowsLocalMethod { @@ -1175,7 +1172,7 @@ function Invoke-PodeAuthValidation { if ($result.Success -and !$auth.PassOne) { # invoke scriptblock, or use result of merge default if ($null -ne $auth.ScriptBlock.Script) { - $result = Invoke-PodeAuthInbuiltScriptBlock -User $results -ScriptBlock $auth.ScriptBlock.Script -UsingVariables $auth.ScriptBlock.UsingVariables -NoSplat + $result = Invoke-PodeAuthInbuiltScriptBlock -User $results -ScriptBlock $auth.ScriptBlock.Script -UsingVariables $auth.ScriptBlock.UsingVariables } else { $result = $results[$auth.MergeDefault] diff --git a/src/Private/ScopedVariables.ps1 b/src/Private/ScopedVariables.ps1 index cf06304e4..2991e13e3 100644 --- a/src/Private/ScopedVariables.ps1 +++ b/src/Private/ScopedVariables.ps1 @@ -69,7 +69,7 @@ function Add-PodeScopedVariableInbuiltSecret { function Add-PodeScopedVariableInbuiltSession { Add-PodeScopedVariable -Name 'session' ` - -SetReplace "`$WebEvent.Session.Data.'{{name}}'" ` + -SetReplace "`$WebEvent.Session.Data.'{{name}}' = " ` -GetReplace "`$WebEvent.Session.Data.'{{name}}'" } From f9e7cf38889f4eda0d6f078120994159add63e50 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 27 Sep 2024 08:15:16 -0700 Subject: [PATCH 174/177] Fix secrets --- src/Private/Helpers.ps1 | 6 +--- src/Private/OpenApi.ps1 | 75 +++++++++++++++++++++++++---------------- src/Public/SSE.ps1 | 2 -- src/Public/Secrets.ps1 | 26 +++++++------- 4 files changed, 59 insertions(+), 50 deletions(-) diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index 765194895..aadbb836a 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -926,11 +926,7 @@ function Remove-PodeEmptyItemsFromArray { param( [Parameter()] $Array - ) - # Set Array to the array of values - if ($pipelineValue.Count -gt 1) { - $Array = $pipelineValue - } + ) if ($null -eq $Array) { return @() } diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index c0b9437ea..3883c71be 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -40,42 +40,45 @@ function ConvertTo-PodeOAObjectSchema { ) begin { - $pipelineItemCount = 0 + $pipelineItemCount = 0 # Initialize counter to track items in the pipeline. } process { - - $pipelineItemCount++ + $pipelineItemCount++ # Increment the counter for each item in the pipeline. } end { + # Throw an error if more than one item is passed in the pipeline. if ($pipelineItemCount -gt 1) { throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) } - # Ensure all content types are valid MIME types + + # Ensure all content types are valid MIME types. foreach ($type in $Content.Keys) { if ($type -inotmatch '^(application|audio|image|message|model|multipart|text|video|\*)\/[\w\.\-\*]+(;[\s]*(charset|boundary)=[\w\.\-\*]+)*$|^"\*\/\*"$') { # Invalid content-type found for schema: $($type) throw ($PodeLocale.invalidContentTypeForSchemaExceptionMessage -f $type) } } - # manage generic schema json conversion issue - if ( $Content.ContainsKey('*/*')) { - $Content['"*/*"'] = $Content['*/*'] + + # Manage a specific case where a generic schema conversion issue may arise. + if ($Content.ContainsKey('*/*')) { + $Content['"*/*"'] = $Content['*/*'] # Adjust the key format for schema compatibility. $Content.Remove('*/*') } - # convert each schema to OpenAPI format - # Initialize an empty hashtable for the schema + + # Initialize an empty hashtable for the schema object. $obj = @{} - # Process each content type + # Get all the content keys (MIME types) to iterate through. $types = [string[]]$Content.Keys foreach ($type in $types) { - # Initialize schema structure for the type - $obj[$type] = @{ } + # Initialize schema structure for each type. + $obj[$type] = @{} - # Handle upload content, array structures, and shared component schema references + # Handle file upload content, arrays, and shared component schema references. if ($Content[$type].__upload) { + # Check if the content is an array. if ($Content[$type].__array) { $upload = $Content[$type].__content.__upload } @@ -83,10 +86,12 @@ function ConvertTo-PodeOAObjectSchema { $upload = $Content[$type].__upload } - if ($type -ieq 'multipart/form-data' -and $upload.content ) { - if ((Test-PodeOAVersion -Version 3.1 -DefinitionTag $DefinitionTag ) -and $upload.partContentMediaType) { - foreach ($key in $upload.content.Properties ) { - if ($key.type -eq 'string' -and $key.format -and $key.format -ieq 'binary' -or $key.format -ieq 'base64') { + # Handle specific multipart/form-data content processing. + if ($type -ieq 'multipart/form-data' -and $upload.content) { + if ((Test-PodeOAVersion -Version 3.1 -DefinitionTag $DefinitionTag) -and $upload.partContentMediaType) { + # Iterate through properties to set content media type and remove format for binaries. + foreach ($key in $upload.content.Properties) { + if ($key.type -eq 'string' -and ($key.format -ieq 'binary' -or $key.format -ieq 'base64')) { $key.ContentMediaType = $PartContentMediaType $key.remove('format') break @@ -96,6 +101,7 @@ function ConvertTo-PodeOAObjectSchema { $newContent = $upload.content } else { + # Handle OpenAPI v3.0 specific content encoding. if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag) { $newContent = [ordered]@{ 'type' = 'string' @@ -103,6 +109,7 @@ function ConvertTo-PodeOAObjectSchema { } } else { + # Handle Base64 content encoding. if ($ContentEncoding -ieq 'Base64') { $newContent = [ordered]@{ 'type' = 'string' @@ -111,6 +118,8 @@ function ConvertTo-PodeOAObjectSchema { } } } + + # Update the content with the new encoding information. if ($Content[$type].__array) { $Content[$type].__content = $newContent } @@ -119,6 +128,7 @@ function ConvertTo-PodeOAObjectSchema { } } + # Process arrays and object properties based on content type. if ($Content[$type].__array) { $isArray = $true $item = $Content[$type].__content @@ -126,16 +136,17 @@ function ConvertTo-PodeOAObjectSchema { 'type' = 'array' 'items' = $null } - if ( $Content[$type].__title) { + # Include additional metadata if present. + if ($Content[$type].__title) { $obj[$type].schema.title = $Content[$type].__title } - if ( $Content[$type].__uniqueItems) { + if ($Content[$type].__uniqueItems) { $obj[$type].schema.uniqueItems = $Content[$type].__uniqueItems } - if ( $Content[$type].__maxItems) { + if ($Content[$type].__maxItems) { $obj[$type].schema.__maxItems = $Content[$type].__maxItems } - if ( $Content[$type].minItems) { + if ($Content[$type].minItems) { $obj[$type].schema.minItems = $Content[$type].__minItems } } @@ -143,11 +154,12 @@ function ConvertTo-PodeOAObjectSchema { $item = $Content[$type] $isArray = $false } - # Add set schema objects or empty content + + # Add schema objects or handle empty content. if ($item -is [string]) { - if (![string]::IsNullOrEmpty($item )) { - #Check for empty reference - if (@('string', 'integer' , 'number', 'boolean' ) -icontains $item) { + if (![string]::IsNullOrEmpty($item)) { + # Handle basic type definitions or references. + if (@('string', 'integer', 'number', 'boolean') -icontains $item) { if ($isArray) { $obj[$type].schema.items = @{ 'type' = $item.ToLower() @@ -160,6 +172,7 @@ function ConvertTo-PodeOAObjectSchema { } } else { + # Handle component references. Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $item -PostValidation if ($isArray) { $obj[$type].schema.items = @{ @@ -174,17 +187,20 @@ function ConvertTo-PodeOAObjectSchema { } } else { - # Create an empty content + # Create an empty content entry. $obj[$type] = @{} } } else { if ($item.Count -eq 0) { - $result = @{} + $result = @{} # Create an empty object if the item count is zero. } else { + # Convert each property to a PodeOpenAPI schema property. $result = ($item | ConvertTo-PodeOASchemaProperty -DefinitionTag $DefinitionTag) } + + # Handle the Properties parameter case. if ($Properties) { if ($item.Name) { $obj[$type].schema = @{ @@ -194,11 +210,12 @@ function ConvertTo-PodeOAObjectSchema { } } else { - # The Properties parameters cannot be used if the Property has no name + # Throw an error if Properties parameter is used without a name. throw ($PodeLocale.propertiesParameterWithoutNameExceptionMessage) } } else { + # Assign the resulting schema to the correct array or object location. if ($isArray) { $obj[$type].schema.items = $result } @@ -209,7 +226,7 @@ function ConvertTo-PodeOAObjectSchema { } } - return $obj + return $obj # Return the final OpenAPI schema object. } } diff --git a/src/Public/SSE.ps1 b/src/Public/SSE.ps1 index 2d82665af..72c2fd91d 100644 --- a/src/Public/SSE.ps1 +++ b/src/Public/SSE.ps1 @@ -245,9 +245,7 @@ function Send-PodeSseEvent { } process { - if ($PSCmdlet.ParameterSetName -eq 'Value') { $pipelineValue += $_ - } } end { diff --git a/src/Public/Secrets.ps1 b/src/Public/Secrets.ps1 index 80d857842..782f659cf 100644 --- a/src/Public/Secrets.ps1 +++ b/src/Public/Secrets.ps1 @@ -674,19 +674,18 @@ function Update-PodeSecret { # No Secret named has been mounted throw ($PodeLocale.noSecretNamedMountedExceptionMessage -f $Name) } - # Initialize an array to hold piped-in values - $pipelineValue = @() + + $pipelineItemCount = 0 # Initialize counter to track items in the pipeline. } process { - # Add the current piped-in value to the array - $pipelineValue += $_ + $pipelineItemCount++ # Increment the counter for each item in the pipeline. } end { - # Set InputObject to the array of values - if ($pipelineValue.Count -gt 1) { - $InputObject = $pipelineValue + # Throw an error if more than one item is passed in the pipeline. + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) } # make sure the value type is correct @@ -923,19 +922,18 @@ function Set-PodeSecret { # No Secret Vault with the name has been registered throw ($PodeLocale.noSecretVaultRegisteredExceptionMessage -f $Vault) } - # Initialize an array to hold piped-in values - $pipelineValue = @() + + $pipelineItemCount = 0 # Initialize counter to track items in the pipeline. } process { - # Add the current piped-in value to the array - $pipelineValue += $_ + $pipelineItemCount++ # Increment the counter for each item in the pipeline. } end { - # Set InputObject to the array of values - if ($pipelineValue.Count -gt 1) { - $InputObject = $pipelineValue + # Throw an error if more than one item is passed in the pipeline. + if ($pipelineItemCount -gt 1) { + throw ($PodeLocale.fnDoesNotAcceptArrayAsPipelineInputExceptionMessage -f $($MyInvocation.MyCommand.Name)) } # make sure the value type is correct From afa1723bb15d2f4b6c1c981431d0a3c2baf79a28 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Fri, 27 Sep 2024 09:08:45 -0700 Subject: [PATCH 175/177] post merge fixes --- src/Private/OpenApi.ps1 | 303 ++++++++++++++++++++-------------------- 1 file changed, 150 insertions(+), 153 deletions(-) diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index ac749e0a6..2acb348d3 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -193,7 +193,7 @@ function ConvertTo-PodeOAObjectSchema { } else { if ($item.Count -eq 0) { - $result =[ordered]@{} # Create an empty object if the item count is zero. + $result = [ordered]@{} # Create an empty object if the item count is zero. } else { # Convert each property to a PodeOpenAPI schema property. @@ -504,69 +504,69 @@ function ConvertTo-PodeOASchemaProperty { $schema['readOnly'] = $Property.readOnly } - if ($Property.example) { - if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag ) { - $schema['example'] = $Property.example - } - else { - if ($Property.example -is [Array]) { - $schema['examples'] = $Property.example + if ($Property.example) { + if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag ) { + $schema['example'] = $Property.example } else { - $schema['examples'] = @( $Property.example) + if ($Property.example -is [Array]) { + $schema['examples'] = $Property.example + } + else { + $schema['examples'] = @( $Property.example) + } } } - } - if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag ) { - if ($Property.ContainsKey('minimum')) { - $schema['minimum'] = $Property.minimum - } + if (Test-PodeOAVersion -Version 3.0 -DefinitionTag $DefinitionTag ) { + if ($Property.ContainsKey('minimum')) { + $schema['minimum'] = $Property.minimum + } - if ($Property.ContainsKey('maximum')) { - $schema['maximum'] = $Property.maximum - } + if ($Property.ContainsKey('maximum')) { + $schema['maximum'] = $Property.maximum + } if ($Property.exclusiveMaximum) { $schema['exclusiveMaximum'] = $Property.exclusiveMaximum } - if ($Property.exclusiveMinimum) { - $schema['exclusiveMinimum'] = $Property.exclusiveMinimum - } - } - else { - if ($Property.ContainsKey('maximum')) { - if ($Property.exclusiveMaximum) { - $schema['exclusiveMaximum'] = $Property.maximum - } - else { - $schema['maximum'] = $Property.maximum + if ($Property.exclusiveMinimum) { + $schema['exclusiveMinimum'] = $Property.exclusiveMinimum } } - if ($Property.ContainsKey('minimum')) { - if ($Property.exclusiveMinimum) { - $schema['exclusiveMinimum'] = $Property.minimum + else { + if ($Property.ContainsKey('maximum')) { + if ($Property.exclusiveMaximum) { + $schema['exclusiveMaximum'] = $Property.maximum + } + else { + $schema['maximum'] = $Property.maximum + } } - else { - $schema['minimum'] = $Property.minimum + if ($Property.ContainsKey('minimum')) { + if ($Property.exclusiveMinimum) { + $schema['exclusiveMinimum'] = $Property.minimum + } + else { + $schema['minimum'] = $Property.minimum + } } } - } - if ($Property.multipleOf) { - $schema['multipleOf'] = $Property.multipleOf - } + if ($Property.multipleOf) { + $schema['multipleOf'] = $Property.multipleOf + } if ($Property.pattern) { $schema['pattern'] = $Property.pattern } - if ($Property.ContainsKey('minLength')) { - $schema['minLength'] = $Property.minLength - } + if ($Property.ContainsKey('minLength')) { + $schema['minLength'] = $Property.minLength + } - if ($Property.ContainsKey('maxLength')) { - $schema['maxLength'] = $Property.maxLength - } + if ($Property.ContainsKey('maxLength')) { + $schema['maxLength'] = $Property.maxLength + } if ($Property.xml ) { $schema['xml'] = $Property.xml @@ -581,91 +581,91 @@ function ConvertTo-PodeOASchemaProperty { } } - # are we using an array? - if ($Property.array) { - if ($Property.ContainsKey('maxItems') ) { - $schema['maxItems'] = $Property.maxItems - } + # are we using an array? + if ($Property.array) { + if ($Property.ContainsKey('maxItems') ) { + $schema['maxItems'] = $Property.maxItems + } - if ($Property.ContainsKey('minItems') ) { - $schema['minItems'] = $Property.minItems - } + if ($Property.ContainsKey('minItems') ) { + $schema['minItems'] = $Property.minItems + } if ($Property.uniqueItems ) { $schema['uniqueItems'] = $Property.uniqueItems } - $schema['type'] = 'array' - if ($Property.type -ieq 'schema') { - Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $Property['schema'] -PostValidation - $schema['items'] = [ordered]@{ '$ref' = "#/components/schemas/$($Property['schema'])" } - } - else { - $Property.array = $false - if ($Property.xml) { - $xmlFromProperties = $Property.xml - $Property.Remove('xml') - } - $schema['items'] = ($Property | ConvertTo-PodeOASchemaProperty -DefinitionTag $DefinitionTag) - $Property.array = $true - if ($xmlFromProperties) { - $Property.xml = $xmlFromProperties + $schema['type'] = 'array' + if ($Property.type -ieq 'schema') { + Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $Property['schema'] -PostValidation + $schema['items'] = [ordered]@{ '$ref' = "#/components/schemas/$($Property['schema'])" } } + else { + $Property.array = $false + if ($Property.xml) { + $xmlFromProperties = $Property.xml + $Property.Remove('xml') + } + $schema['items'] = ($Property | ConvertTo-PodeOASchemaProperty -DefinitionTag $DefinitionTag) + $Property.array = $true + if ($xmlFromProperties) { + $Property.xml = $xmlFromProperties + } - if ($Property.xmlItemName) { - $schema.items.xml = [ordered]@{'name' = $Property.xmlItemName } + if ($Property.xmlItemName) { + $schema.items.xml = [ordered]@{'name' = $Property.xmlItemName } + } } + return $schema } - return $schema - } - else { - #format is not applicable to array - if ($Property.format) { - $schema['format'] = $Property.format - } + else { + #format is not applicable to array + if ($Property.format) { + $schema['format'] = $Property.format + } - # schema refs - if ($Property.type -ieq 'schema') { - Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $Property['schema'] -PostValidation - $schema = [ordered]@{ - '$ref' = "#/components/schemas/$($Property['schema'])" + # schema refs + if ($Property.type -ieq 'schema') { + Test-PodeOAComponentInternal -Field schemas -DefinitionTag $DefinitionTag -Name $Property['schema'] -PostValidation + $schema = [ordered]@{ + '$ref' = "#/components/schemas/$($Property['schema'])" + } + } + #only if it's not an array + if ($Property.enum ) { + $schema['enum'] = $Property.enum } } - #only if it's not an array - if ($Property.enum ) { - $schema['enum'] = $Property.enum - } - } if ($Property.object) { # are we using an object? $Property.object = $false - $schema = [ordered]@{ - type = 'object' - properties = (ConvertTo-PodeOASchemaObjectProperty -DefinitionTag $DefinitionTag -Properties $Property) - } - $Property.object = $true - if ($Property.required) { - $schema['required'] = @($Property.name) + $schema = [ordered]@{ + type = 'object' + properties = (ConvertTo-PodeOASchemaObjectProperty -DefinitionTag $DefinitionTag -Properties $Property) + } + $Property.object = $true + if ($Property.required) { + $schema['required'] = @($Property.name) + } } - } - if ($Property.type -ieq 'object') { - $schema['properties'] = [ordered]@{} - foreach ($prop in $Property.properties) { - if ( @('allOf', 'oneOf', 'anyOf') -icontains $prop.type) { - switch ($prop.type.ToLower()) { - 'allof' { $prop.type = 'allOf' } - 'oneof' { $prop.type = 'oneOf' } - 'anyof' { $prop.type = 'anyOf' } - } - if ($prop.name) { - $schema['properties'] += ConvertTo-PodeOAofProperty -DefinitionTag $DefinitionTag -Property $prop - } - else { - $schema += ConvertTo-PodeOAofProperty -DefinitionTag $DefinitionTag -Property $prop - } + if ($Property.type -ieq 'object') { + $schema['properties'] = [ordered]@{} + foreach ($prop in $Property.properties) { + if ( @('allOf', 'oneOf', 'anyOf') -icontains $prop.type) { + switch ($prop.type.ToLower()) { + 'allof' { $prop.type = 'allOf' } + 'oneof' { $prop.type = 'oneOf' } + 'anyof' { $prop.type = 'anyOf' } + } + if ($prop.name) { + $schema['properties'] += ConvertTo-PodeOAofProperty -DefinitionTag $DefinitionTag -Property $prop + } + else { + $schema += ConvertTo-PodeOAofProperty -DefinitionTag $DefinitionTag -Property $prop + } } } @@ -688,19 +688,19 @@ function ConvertTo-PodeOASchemaProperty { $schema['minProperties'] = $Property.minProperties } - if ($Property.maxProperties) { - $schema['maxProperties'] = $Property.maxProperties - } - #Fix an issue when additionalProperties has an assigned value of $false - if ($Property.ContainsKey('additionalProperties')) { - if ($Property.additionalProperties) { - $schema['additionalProperties'] = $Property.additionalProperties | ConvertTo-PodeOASchemaProperty -DefinitionTag $DefinitionTag + if ($Property.maxProperties) { + $schema['maxProperties'] = $Property.maxProperties } - else { - #the value is $false - $schema['additionalProperties'] = $false + #Fix an issue when additionalProperties has an assigned value of $false + if ($Property.ContainsKey('additionalProperties')) { + if ($Property.additionalProperties) { + $schema['additionalProperties'] = $Property.additionalProperties | ConvertTo-PodeOASchemaProperty -DefinitionTag $DefinitionTag + } + else { + #the value is $false + $schema['additionalProperties'] = $false + } } - } if ($Property.discriminator) { $schema['discriminator'] = $Property.discriminator @@ -1849,46 +1849,43 @@ function ConvertTo-PodeOAHeaderProperty { begin { # Initialize an array to hold piped-in values $pipelineValue = @() + $elems = [ordered]@{} + } - - $elems = @{} - -} - -process { - # Add the current piped-in value to the array - $pipelineValue += $_ -} - -end { - # Set Headers to the array of values - if ($pipelineValue.Count -gt 1) { - $Headers = $pipelineValue + process { + # Add the current piped-in value to the array + $pipelineValue += $_ } - foreach ($e in $Headers) { - # Ensure each header has a name - if ($e.name) { - $elems.$($e.name) = @{} - # Add description if present - if ($e.description) { - $elems.$($e.name).description = $e.description - } - # Define the schema, including the type and any additional properties - $elems.$($e.name).schema = @{ - type = $($e.type) - } - foreach ($k in $e.keys) { - if (@('name', 'description') -notcontains $k) { - $elems.$($e.name).schema.$k = $e.$k + end { + # Set Headers to the array of values + if ($pipelineValue.Count -gt 1) { + $Headers = $pipelineValue + } + + foreach ($e in $Headers) { + # Ensure each header has a name + if ($e.name) { + $elems.$($e.name) = @{} + # Add description if present + if ($e.description) { + $elems.$($e.name).description = $e.description + } + # Define the schema, including the type and any additional properties + $elems.$($e.name).schema = @{ + type = $($e.type) + } + foreach ($k in $e.keys) { + if (@('name', 'description') -notcontains $k) { + $elems.$($e.name).schema.$k = $e.$k + } } } + else { + # Header requires a name when used in an encoding context + throw ($PodeLocale.headerMustHaveNameInEncodingContextExceptionMessage) + } } - else { - # Header requires a name when used in an encoding context - throw ($PodeLocale.headerMustHaveNameInEncodingContextExceptionMessage) - } - } return $elems } From f38bb3254bdec3267bfe7a35a35323e3e9b0ea2e Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Sat, 28 Sep 2024 17:54:50 +0100 Subject: [PATCH 176/177] ignore accepted PSAnalyzer warnings --- PSScriptAnalyzerSettings.psd1 | 4 +- examples/Web-Sse.ps1 | 4 +- src/Private/Helpers.ps1 | 2 +- src/Private/Timers.ps1 | 2 +- src/Public/Access.ps1 | 1 + src/Public/Authentication.ps1 | 1 + src/Public/Events.ps1 | 1 + src/Public/FileWatchers.ps1 | 4 +- src/Public/Flash.ps1 | 2 + src/Public/Handlers.ps1 | 4 +- src/Public/Logging.ps1 | 1 + src/Public/OpenApi.ps1 | 179 +++++++++++++++++---------------- src/Public/Responses.ps1 | 40 ++++---- src/Public/Routes.ps1 | 6 +- src/Public/Runspaces.ps1 | 8 +- src/Public/SSE.ps1 | 2 +- src/Public/Schedules.ps1 | 2 + src/Public/ScopedVariables.ps1 | 6 ++ src/Public/Security.ps1 | 4 + src/Public/State.ps1 | 1 + src/Public/Tasks.ps1 | 6 +- src/Public/Threading.ps1 | 3 + src/Public/Timers.ps1 | 2 + src/Public/Utilities.ps1 | 3 + src/Public/Verbs.ps1 | 2 + 25 files changed, 168 insertions(+), 122 deletions(-) diff --git a/PSScriptAnalyzerSettings.psd1 b/PSScriptAnalyzerSettings.psd1 index 21e8d8a5e..15486f3d7 100644 --- a/PSScriptAnalyzerSettings.psd1 +++ b/PSScriptAnalyzerSettings.psd1 @@ -25,7 +25,9 @@ 'PSUseProcessBlockForPipelineCommand', 'PSAvoidUsingConvertToSecureStringWithPlainText', 'PSReviewUnusedParameter', - 'PSAvoidAssignmentToAutomaticVariable' + 'PSAvoidAssignmentToAutomaticVariable', + 'PSUseBOMForUnicodeEncodedFile', + 'PSAvoidTrailingWhitespace' ) } \ No newline at end of file diff --git a/examples/Web-Sse.ps1 b/examples/Web-Sse.ps1 index d676ff4e9..188564b27 100644 --- a/examples/Web-Sse.ps1 +++ b/examples/Web-Sse.ps1 @@ -49,9 +49,9 @@ Start-PodeServer -Threads 3 { # open local sse connection, and send back data Add-PodeRoute -Method Get -Path '/data' -ScriptBlock { ConvertTo-PodeSseConnection -Name 'Data' -Scope Local - Send-PodeSseEvent -Id 1234 -EventType Action -Data 'hello, there!' + Send-PodeSseEvent -Id 1234 -EventType Action -Data 'hello, there!' -FromEvent Start-Sleep -Seconds 3 - Send-PodeSseEvent -Id 1337 -EventType BoldOne -Data 'general kenobi' + Send-PodeSseEvent -Id 1337 -EventType BoldOne -Data 'general kenobi' -FromEvent } # home page to get sse events diff --git a/src/Private/Helpers.ps1 b/src/Private/Helpers.ps1 index b583566a1..0bdc9237b 100644 --- a/src/Private/Helpers.ps1 +++ b/src/Private/Helpers.ps1 @@ -926,7 +926,7 @@ function Remove-PodeEmptyItemsFromArray { param( [Parameter()] $Array - ) + ) if ($null -eq $Array) { return @() } diff --git a/src/Private/Timers.ps1 b/src/Private/Timers.ps1 index d5a3ac3d7..48b19ba9a 100644 --- a/src/Private/Timers.ps1 +++ b/src/Private/Timers.ps1 @@ -80,7 +80,7 @@ function Start-PodeTimerRunspace { } } - Add-PodeRunspace -Type Timers -Name "Scheduler" -ScriptBlock $script + Add-PodeRunspace -Type Timers -Name 'Scheduler' -ScriptBlock $script } function Invoke-PodeInternalTimer { diff --git a/src/Public/Access.ps1 b/src/Public/Access.ps1 index c1a1a920d..ebf1cb3b5 100644 --- a/src/Public/Access.ps1 +++ b/src/Public/Access.ps1 @@ -388,6 +388,7 @@ The Name of the Access method. if (Test-PodeAccessExists -Name 'Example') { } #> function Test-PodeAccessExists { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param( [Parameter(Mandatory = $true)] diff --git a/src/Public/Authentication.ps1 b/src/Public/Authentication.ps1 index a007e1153..64d6ea2df 100644 --- a/src/Public/Authentication.ps1 +++ b/src/Public/Authentication.ps1 @@ -1102,6 +1102,7 @@ The Name of the Authentication method. if (Test-PodeAuthExists -Name BasicAuth) { ... } #> function Test-PodeAuthExists { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] [OutputType([bool])] param( diff --git a/src/Public/Events.ps1 b/src/Public/Events.ps1 index 9d129667c..b3f800a0d 100644 --- a/src/Public/Events.ps1 +++ b/src/Public/Events.ps1 @@ -202,6 +202,7 @@ Use-PodeEvents Use-PodeEvents -Path './my-events' #> function Use-PodeEvents { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param( [Parameter()] diff --git a/src/Public/FileWatchers.ps1 b/src/Public/FileWatchers.ps1 index 8b4a4aeca..e1cda2023 100644 --- a/src/Public/FileWatchers.ps1 +++ b/src/Public/FileWatchers.ps1 @@ -143,7 +143,7 @@ function Add-PodeFileWatcher { # test if we have the file watcher already if (Test-PodeFileWatcher -Name $Name) { - # A File Watcher named has already been defined + # A File Watcher named has already been defined throw ($PodeLocale.fileWatcherAlreadyDefinedExceptionMessage -f $Name) } @@ -292,6 +292,7 @@ Removes all File Watchers. Clear-PodeFileWatchers #> function Clear-PodeFileWatchers { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() @@ -315,6 +316,7 @@ Use-PodeFileWatchers Use-PodeFileWatchers -Path './my-watchers' #> function Use-PodeFileWatchers { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param( [Parameter()] diff --git a/src/Public/Flash.ps1 b/src/Public/Flash.ps1 index 6f42a4b3c..0c9364d70 100644 --- a/src/Public/Flash.ps1 +++ b/src/Public/Flash.ps1 @@ -57,6 +57,7 @@ Clears all of the flash messages currently stored in the session. Clear-PodeFlashMessages #> function Clear-PodeFlashMessages { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() @@ -127,6 +128,7 @@ Returns all of the names for each of the messages currently being stored. This d Get-PodeFlashMessageNames #> function Get-PodeFlashMessageNames { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] [OutputType([System.Object[]])] param() diff --git a/src/Public/Handlers.ps1 b/src/Public/Handlers.ps1 index 59c31ba58..244570397 100644 --- a/src/Public/Handlers.ps1 +++ b/src/Public/Handlers.ps1 @@ -59,7 +59,7 @@ function Add-PodeHandler { # ensure handler isn't already set if ($PodeContext.Server.Handlers[$Type].ContainsKey($Name)) { - # [Type] Name: Handler already defined + # [Type] Name: Handler already defined throw ($PodeLocale.handlerAlreadyDefinedExceptionMessage -f $Type, $Name) } @@ -132,6 +132,7 @@ The Type of Handlers to remove. Clear-PodeHandlers -Type Smtp #> function Clear-PodeHandlers { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param( [Parameter()] @@ -167,6 +168,7 @@ Use-PodeHandlers Use-PodeHandlers -Path './my-handlers' #> function Use-PodeHandlers { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param( [Parameter()] diff --git a/src/Public/Logging.ps1 b/src/Public/Logging.ps1 index 18a004c7f..727a1fcd3 100644 --- a/src/Public/Logging.ps1 +++ b/src/Public/Logging.ps1 @@ -501,6 +501,7 @@ Clears all Logging methods that have been configured. Clear-PodeLoggers #> function Clear-PodeLoggers { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index cdf8250f1..4a07a4d29 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -651,15 +651,15 @@ function Add-PodeOAResponse { $code = "$($StatusCode)" } - # add the respones to the routes - foreach ($r in @($Route)) { - foreach ($tag in $DefinitionTag) { - if (! $r.OpenApi.Responses.$tag) { - $r.OpenApi.Responses.$tag = [ordered]@{} + # add the respones to the routes + foreach ($r in @($Route)) { + foreach ($tag in $DefinitionTag) { + if (! $r.OpenApi.Responses.$tag) { + $r.OpenApi.Responses.$tag = [ordered]@{} + } + $r.OpenApi.Responses.$tag[$code] = New-PodeOResponseInternal -DefinitionTag $tag -Params $PSBoundParameters } - $r.OpenApi.Responses.$tag[$code] = New-PodeOResponseInternal -DefinitionTag $tag -Params $PSBoundParameters } - } if ($PassThru) { return $Route @@ -809,16 +809,16 @@ function Set-PodeOARequest { $r.OpenApi.Parameters = @($Parameters) } - if ($null -ne $RequestBody) { - # Only 'POST', 'PUT', 'PATCH' can have a request body - if (('POST', 'PUT', 'PATCH') -inotcontains $r.Method ) { - # {0} operations cannot have a Request Body. - throw ($PodeLocale.getRequestBodyNotAllowedExceptionMessage -f $r.Method) + if ($null -ne $RequestBody) { + # Only 'POST', 'PUT', 'PATCH' can have a request body + if (('POST', 'PUT', 'PATCH') -inotcontains $r.Method ) { + # {0} operations cannot have a Request Body. + throw ($PodeLocale.getRequestBodyNotAllowedExceptionMessage -f $r.Method) + } + $r.OpenApi.RequestBody = $RequestBody } - $r.OpenApi.RequestBody = $RequestBody - } - } + } if ($PassThru) { return $Route @@ -892,6 +892,7 @@ New-PodeOARequestBody -Content @{'multipart/form-data' = function New-PodeOARequestBody { [CmdletBinding(DefaultParameterSetName = 'BuiltIn' )] [OutputType([hashtable])] + [OutputType([System.Collections.Specialized.OrderedDictionary])] param( [Parameter(Mandatory = $true, ParameterSetName = 'Reference')] [string] @@ -1360,27 +1361,27 @@ function ConvertTo-PodeOAParameter { $prop['allowReserved'] = $AllowReserved.IsPresent } - if ($Example ) { - $prop.example = $Example - } - elseif ($Examples) { - $prop.examples = $Examples + if ($Example ) { + $prop.example = $Example + } + elseif ($Examples) { + $prop.examples = $Examples + } } } - } - elseif ($PSCmdlet.ParameterSetName -ieq 'Reference') { - # return a reference - Test-PodeOAComponentInternal -Field parameters -DefinitionTag $DefinitionTag -Name $Reference -PostValidation - $prop = [ordered]@{ - '$ref' = "#/components/parameters/$Reference" - } - foreach ($tag in $DefinitionTag) { - if ($PodeContext.Server.OpenAPI.Definitions[$tag].components.parameters.$Reference.In -eq 'Header' -and $PodeContext.Server.Security.autoHeaders) { - Add-PodeSecurityHeader -Name 'Access-Control-Allow-Headers' -Value $Reference -Append + elseif ($PSCmdlet.ParameterSetName -ieq 'Reference') { + # return a reference + Test-PodeOAComponentInternal -Field parameters -DefinitionTag $DefinitionTag -Name $Reference -PostValidation + $prop = [ordered]@{ + '$ref' = "#/components/parameters/$Reference" + } + foreach ($tag in $DefinitionTag) { + if ($PodeContext.Server.OpenAPI.Definitions[$tag].components.parameters.$Reference.In -eq 'Header' -and $PodeContext.Server.Security.autoHeaders) { + Add-PodeSecurityHeader -Name 'Access-Control-Allow-Headers' -Value $Reference -Append + } } } - } - else { + else { if (!$Name ) { if ($Property.name) { @@ -1633,17 +1634,17 @@ function Set-PodeOARouteInfo { $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag - foreach ($r in @($Route)) { - if ((Compare-Object -ReferenceObject $r.OpenApi.DefinitionTag -DifferenceObject $DefinitionTag).Count -ne 0) { - if ($r.OpenApi.IsDefTagConfigured ) { - # Definition Tag for a Route cannot be changed. - throw ($PodeLocale.definitionTagChangeNotAllowedExceptionMessage) - } - else { - $r.OpenApi.DefinitionTag = $DefinitionTag - $r.OpenApi.IsDefTagConfigured = $true + foreach ($r in @($Route)) { + if ((Compare-Object -ReferenceObject $r.OpenApi.DefinitionTag -DifferenceObject $DefinitionTag).Count -ne 0) { + if ($r.OpenApi.IsDefTagConfigured ) { + # Definition Tag for a Route cannot be changed. + throw ($PodeLocale.definitionTagChangeNotAllowedExceptionMessage) + } + else { + $r.OpenApi.DefinitionTag = $DefinitionTag + $r.OpenApi.IsDefTagConfigured = $true + } } - } if ($OperationId) { if ($Route.Count -gt 1) { @@ -2712,28 +2713,28 @@ function Add-PodeOACallBack { $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag - foreach ($r in @($Route)) { - foreach ($tag in $DefinitionTag) { - if ($Reference) { - Test-PodeOAComponentInternal -Field callbacks -DefinitionTag $tag -Name $Reference -PostValidation - if (!$Name) { - $Name = $Reference - } - if (! $r.OpenApi.CallBacks.ContainsKey($tag)) { - $r.OpenApi.CallBacks[$tag] = [ordered]@{} - } - $r.OpenApi.CallBacks[$tag].$Name = [ordered]@{ - '$ref' = "#/components/callbacks/$Reference" + foreach ($r in @($Route)) { + foreach ($tag in $DefinitionTag) { + if ($Reference) { + Test-PodeOAComponentInternal -Field callbacks -DefinitionTag $tag -Name $Reference -PostValidation + if (!$Name) { + $Name = $Reference + } + if (! $r.OpenApi.CallBacks.ContainsKey($tag)) { + $r.OpenApi.CallBacks[$tag] = [ordered]@{} + } + $r.OpenApi.CallBacks[$tag].$Name = [ordered]@{ + '$ref' = "#/components/callbacks/$Reference" + } } - } - else { - if (! $r.OpenApi.CallBacks.ContainsKey($tag)) { - $r.OpenApi.CallBacks[$tag] = [ordered]@{} + else { + if (! $r.OpenApi.CallBacks.ContainsKey($tag)) { + $r.OpenApi.CallBacks[$tag] = [ordered]@{} + } + $r.OpenApi.CallBacks[$tag].$Name = New-PodeOAComponentCallBackInternal -Params $PSBoundParameters -DefinitionTag $tag } - $r.OpenApi.CallBacks[$tag].$Name = New-PodeOAComponentCallBackInternal -Params $PSBoundParameters -DefinitionTag $tag } } - } if ($PassThru) { return $Route @@ -3307,36 +3308,36 @@ function Add-PodeOAExternalRoute { end { $DefinitionTag = Test-PodeOADefinitionTag -Tag $DefinitionTag - switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { - 'builtin' { - - # ensure the route has appropriate slashes - $Path = Update-PodeRouteSlash -Path $Path - $OpenApiPath = ConvertTo-PodeOpenApiRoutePath -Path $Path - $Path = Resolve-PodePlaceholder -Path $Path - $extRoute = @{ - Method = $Method.ToLower() - Path = $Path - Local = $false - OpenApi = @{ - Path = $OpenApiPath - Responses = $null - Parameters = $null - RequestBody = $null - callbacks = [ordered]@{} - Authentication = @() - Servers = $Servers - DefinitionTag = $DefinitionTag - } - } - foreach ($tag in $DefinitionTag) { - #add the default OpenApi responses - if ( $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses) { - $extRoute.OpenApi.Responses = Copy-PodeObjectDeepClone -InputObject $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses - } - if (! (Test-PodeOAComponentExternalPath -DefinitionTag $tag -Name $Path)) { - $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.externalPath[$Path] = [ordered]@{} + switch ($PSCmdlet.ParameterSetName.ToLowerInvariant()) { + 'builtin' { + + # ensure the route has appropriate slashes + $Path = Update-PodeRouteSlash -Path $Path + $OpenApiPath = ConvertTo-PodeOpenApiRoutePath -Path $Path + $Path = Resolve-PodePlaceholder -Path $Path + $extRoute = @{ + Method = $Method.ToLower() + Path = $Path + Local = $false + OpenApi = @{ + Path = $OpenApiPath + Responses = $null + Parameters = $null + RequestBody = $null + callbacks = [ordered]@{} + Authentication = @() + Servers = $Servers + DefinitionTag = $DefinitionTag + } } + foreach ($tag in $DefinitionTag) { + #add the default OpenApi responses + if ( $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses) { + $extRoute.OpenApi.Responses = Copy-PodeObjectDeepClone -InputObject $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses + } + if (! (Test-PodeOAComponentExternalPath -DefinitionTag $tag -Name $Path)) { + $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.externalPath[$Path] = [ordered]@{} + } $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.externalPath.$Path[$Method] = $extRoute } diff --git a/src/Public/Responses.ps1 b/src/Public/Responses.ps1 index d2958d383..9aedf0fd6 100644 --- a/src/Public/Responses.ps1 +++ b/src/Public/Responses.ps1 @@ -270,20 +270,20 @@ function Write-PodeTextResponse { } } - # check if we need to compress the response - if ($PodeContext.Server.Web.Compression.Enabled -and ![string]::IsNullOrWhiteSpace($WebEvent.AcceptEncoding)) { - try { - $ms = [System.IO.MemoryStream]::new() - $stream = Get-PodeCompressionStream -InputStream $ms -Encoding $WebEvent.AcceptEncoding -Mode Compress - $stream.Write($Bytes, 0, $Bytes.Length) - $stream.Close() - $ms.Position = 0 - $Bytes = $ms.ToArray() - } - finally { - if ($null -ne $stream) { + # check if we need to compress the response + if ($PodeContext.Server.Web.Compression.Enabled -and ![string]::IsNullOrWhiteSpace($WebEvent.AcceptEncoding)) { + try { + $ms = [System.IO.MemoryStream]::new() + $stream = Get-PodeCompressionStream -InputStream $ms -Encoding $WebEvent.AcceptEncoding -Mode Compress + $stream.Write($Bytes, 0, $Bytes.Length) $stream.Close() + $ms.Position = 0 + $Bytes = $ms.ToArray() } + finally { + if ($null -ne $stream) { + $stream.Close() + } if ($null -ne $ms) { $ms.Close() @@ -297,15 +297,15 @@ function Write-PodeTextResponse { # write the content to the response stream $res.ContentLength64 = $Bytes.Length - try { - $ms = [System.IO.MemoryStream]::new() - $ms.Write($Bytes, 0, $Bytes.Length) - $ms.WriteTo($res.OutputStream) - } - catch { - if ((Test-PodeValidNetworkFailure $_.Exception)) { - return + try { + $ms = [System.IO.MemoryStream]::new() + $ms.Write($Bytes, 0, $Bytes.Length) + $ms.WriteTo($res.OutputStream) } + catch { + if ((Test-PodeValidNetworkFailure $_.Exception)) { + return + } $_ | Write-PodeErrorLog throw diff --git a/src/Public/Routes.ps1 b/src/Public/Routes.ps1 index 51df6fd55..9af545f77 100644 --- a/src/Public/Routes.ps1 +++ b/src/Public/Routes.ps1 @@ -399,7 +399,7 @@ function Add-PodeRoute { if ( $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.defaultResponses) { $DefaultResponse = [ordered]@{} foreach ($tag in $DefinitionTag) { - $DefaultResponse[$tag] = Copy-PodeObjectDeepClone -InputObject $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses + $DefaultResponse[$tag] = Copy-PodeObjectDeepClone -InputObject $PodeContext.Server.OpenAPI.Definitions[$tag].hiddenComponents.defaultResponses } } @@ -1835,6 +1835,7 @@ Clear-PodeRoutes Clear-PodeRoutes -Method Get #> function Clear-PodeRoutes { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param( [Parameter()] @@ -1864,6 +1865,7 @@ Removes all added static Routes. Clear-PodeStaticRoutes #> function Clear-PodeStaticRoutes { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() @@ -1881,6 +1883,7 @@ Removes all added Signal Routes. Clear-PodeSignalRoutes #> function Clear-PodeSignalRoutes { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() @@ -2598,6 +2601,7 @@ Use-PodeRoutes Use-PodeRoutes -Path './my-routes' -IfExists Skip #> function Use-PodeRoutes { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param( [Parameter()] diff --git a/src/Public/Runspaces.ps1 b/src/Public/Runspaces.ps1 index 5b83b6089..286a0aacd 100644 --- a/src/Public/Runspaces.ps1 +++ b/src/Public/Runspaces.ps1 @@ -18,7 +18,8 @@ #> function Set-PodeCurrentRunspaceName { - param ( + [CmdletBinding()] + param( [Parameter(Mandatory = $true)] [string] $Name @@ -26,7 +27,7 @@ function Set-PodeCurrentRunspaceName { # Get the current runspace $currentRunspace = [System.Management.Automation.Runspaces.Runspace]::DefaultRunspace - # Set the name of the current runspace if the name is not already set + # Set the name of the current runspace if the name is not already set if ( $currentRunspace.Name -ne $Name) { # Set the name of the current runspace $currentRunspace.Name = $Name @@ -49,6 +50,9 @@ function Set-PodeCurrentRunspaceName { This is an internal function and may change in future releases of Pode. #> function Get-PodeCurrentRunspaceName { + [CmdletBinding()] + param() + # Get the current runspace $currentRunspace = [System.Management.Automation.Runspaces.Runspace]::DefaultRunspace diff --git a/src/Public/SSE.ps1 b/src/Public/SSE.ps1 index 72c2fd91d..c1d620139 100644 --- a/src/Public/SSE.ps1 +++ b/src/Public/SSE.ps1 @@ -245,7 +245,7 @@ function Send-PodeSseEvent { } process { - $pipelineValue += $_ + $pipelineValue += $_ } end { diff --git a/src/Public/Schedules.ps1 b/src/Public/Schedules.ps1 index 21a89c916..974a0341c 100644 --- a/src/Public/Schedules.ps1 +++ b/src/Public/Schedules.ps1 @@ -277,6 +277,7 @@ Removes all Schedules. Clear-PodeSchedules #> function Clear-PodeSchedules { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() @@ -556,6 +557,7 @@ Use-PodeSchedules Use-PodeSchedules -Path './my-schedules' #> function Use-PodeSchedules { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param( [Parameter()] diff --git a/src/Public/ScopedVariables.ps1 b/src/Public/ScopedVariables.ps1 index b268a54fc..a21805c13 100644 --- a/src/Public/ScopedVariables.ps1 +++ b/src/Public/ScopedVariables.ps1 @@ -23,6 +23,7 @@ $ScriptBlock, $usingVars = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock $ScriptBlock = Convert-PodeScopedVariables -ScriptBlock $ScriptBlock -Exclude Session, Using #> function Convert-PodeScopedVariables { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] [OutputType([System.Object[]])] [OutputType([scriptblock])] @@ -301,6 +302,10 @@ Removes all Scoped Variables. Clear-PodeScopedVariables #> function Clear-PodeScopedVariables { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] + [CmdletBinding()] + param() + $null = $PodeContext.Server.ScopedVariables.Clear() } @@ -357,6 +362,7 @@ Use-PodeScopedVariables Use-PodeScopedVariables -Path './my-vars' #> function Use-PodeScopedVariables { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param( [Parameter()] diff --git a/src/Public/Security.ps1 b/src/Public/Security.ps1 index 5a928c9e0..ee5ab7947 100644 --- a/src/Public/Security.ps1 +++ b/src/Public/Security.ps1 @@ -223,6 +223,7 @@ The Type to use. Set-PodeSecurityFrameOptions -Type SameOrigin #> function Set-PodeSecurityFrameOptions { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param( [Parameter(Mandatory = $true)] @@ -245,6 +246,7 @@ Removes definition for the X-Frame-Options header. Remove-PodeSecurityFrameOptions #> function Remove-PodeSecurityFrameOptions { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() @@ -1062,6 +1064,7 @@ Set a value for the X-Content-Type-Options header to "nosniff". Set-PodeSecurityContentTypeOptions #> function Set-PodeSecurityContentTypeOptions { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() @@ -1079,6 +1082,7 @@ Removes definitions for the X-Content-Type-Options header. Remove-PodeSecurityContentTypeOptions #> function Remove-PodeSecurityContentTypeOptions { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() diff --git a/src/Public/State.ps1 b/src/Public/State.ps1 index 282eaf1eb..1c841e586 100644 --- a/src/Public/State.ps1 +++ b/src/Public/State.ps1 @@ -131,6 +131,7 @@ $names = Get-PodeStateNames -Scope '' $names = Get-PodeStateNames -Pattern '^\w+[0-9]{0,2}$' #> function Get-PodeStateNames { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param( [Parameter()] diff --git a/src/Public/Tasks.ps1 b/src/Public/Tasks.ps1 index b782469a6..26477d7c6 100644 --- a/src/Public/Tasks.ps1 +++ b/src/Public/Tasks.ps1 @@ -196,8 +196,8 @@ function Invoke-PodeTask { throw ($PodeLocale.taskDoesNotExistExceptionMessage -f $Name) } - # run task logic - $task = Invoke-PodeInternalTask -Task $PodeContext.Tasks.Items[$Name] -ArgumentList $ArgumentList -Timeout $Timeout -TimeoutFrom $TimeoutFrom + # run task logic + $task = Invoke-PodeInternalTask -Task $PodeContext.Tasks.Items[$Name] -ArgumentList $ArgumentList -Timeout $Timeout -TimeoutFrom $TimeoutFrom # wait, and return result? if ($Wait) { @@ -245,6 +245,7 @@ Removes all Tasks. Clear-PodeTasks #> function Clear-PodeTasks { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() @@ -368,6 +369,7 @@ Use-PodeTasks Use-PodeTasks -Path './my-tasks' #> function Use-PodeTasks { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param( [Parameter()] diff --git a/src/Public/Threading.ps1 b/src/Public/Threading.ps1 index b3461bc74..c192c063f 100644 --- a/src/Public/Threading.ps1 +++ b/src/Public/Threading.ps1 @@ -376,6 +376,7 @@ Remove all Lockables. Clear-PodeLockables #> function Clear-PodeLockables { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() @@ -667,6 +668,7 @@ Removes all Mutexes. Clear-PodeMutexes #> function Clear-PodeMutexes { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() @@ -980,6 +982,7 @@ Removes all Semaphores. Clear-PodeSemaphores #> function Clear-PodeSemaphores { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() diff --git a/src/Public/Timers.ps1 b/src/Public/Timers.ps1 index 846ee02b7..78a9ecc73 100644 --- a/src/Public/Timers.ps1 +++ b/src/Public/Timers.ps1 @@ -211,6 +211,7 @@ Removes all Timers. Clear-PodeTimers #> function Clear-PodeTimers { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() @@ -370,6 +371,7 @@ Use-PodeTimers Use-PodeTimers -Path './my-timers' #> function Use-PodeTimers { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param( [Parameter()] diff --git a/src/Public/Utilities.ps1 b/src/Public/Utilities.ps1 index c12d878fe..893ffd464 100644 --- a/src/Public/Utilities.ps1 +++ b/src/Public/Utilities.ps1 @@ -612,6 +612,9 @@ $Arguments = @(Merge-PodeScriptblockArguments -ArgumentList $Arguments -UsingVar $Arguments = @(Merge-PodeScriptblockArguments -UsingVariables $UsingVariables) #> function Merge-PodeScriptblockArguments { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] + [CmdletBinding()] + [OutputType([object[]])] param( [Parameter()] [object[]] diff --git a/src/Public/Verbs.ps1 b/src/Public/Verbs.ps1 index 93c91ff59..3adf26557 100644 --- a/src/Public/Verbs.ps1 +++ b/src/Public/Verbs.ps1 @@ -176,6 +176,7 @@ Removes all added Verbs. Clear-PodeVerbs #> function Clear-PodeVerbs { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param() @@ -261,6 +262,7 @@ Use-PodeVerbs Use-PodeVerbs -Path './my-verbs' #> function Use-PodeVerbs { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] param( [Parameter()] From 7cfef47dbe1fcbf4dab46b1a26d5da9955228129 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Sun, 29 Sep 2024 12:34:03 +0100 Subject: [PATCH 177/177] prepping for 2.11.0 --- docs/release-notes.md | 64 ++++++++++++++++++++++++++++++++++++++++++- pode.build.ps1 | 8 ++++-- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/docs/release-notes.md b/docs/release-notes.md index c96072d0d..969c65a6d 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,8 +1,70 @@ # Release Notes +## v2.11.0 + +Date: 29th September 2024 + +```plain +### Features +* #1320: Enhanced Internationalization Support (i18n) (thanks @mdaneri!) + +### Enhancements +* #1338: Automate Endpoint Assignment for OAViewer in Pode (thanks @mdaneri!) +* #1339: Add 'Rename-PodeOADefinitionTag' Function (thanks @mdaneri!) +* #1340: Add configuration parameter 'Web.OpenApi.UsePodeYamlInternal' (thanks @mdaneri!) +* #1352: Update MIME types to comply with RFC9512 and RFC5323 (thanks @mdaneri!) +* #1356: Dutch language support (thanks @mdaneri!) +* #1373: Dynamically load the Pode DLL relevant to the version of PowerShell (thanks @mdaneri!) +* #1384: Customizing and Managing Runspace Names (thanks @mdaneri!) +* #1388: Support passing Arrays to Functions Using Piping (thanks @mdaneri!) +* #1393: Adds functions for retrieving Schedule and Task Processes +* #1393: Improves Error Handling in Schedules, Timers, Tasks, and Logging +* #1393: Removes Global scope from TimerEvent +* #1399: Replaces occurrences of New-Object with new() + +### Bugs +* #1319: Fixes the Write-Pode(*)Response functions so the Value parameter appropriately handles when an array is passed using piping (thanks @mdaneri!) +* #1321: Fixes a misspelled variable in Add-PodeOAExternalRoute (thanks @mdaneri!) +* #1347: '-AdditionalProperties' doesn't appear on the OpenAPI document despite using the '-NoAdditionalProperties' parameter. (thanks @mdaneri!) +* #1358: Fixes [ordered] comparisons in PowerShell 5.1 (thanks @mdaneri!) +* #1358: Fixes for various OpenAPI issues (thanks @mdaneri!) +* #1358: Fixes OpenAPI version validation check in PowerShell 5.1 (thanks @mdaneri!) +* #1359: Fixes the login redirect URL logic for OAuth2 flows when using -SuccessUseOrigin +* #1360: Fixes a bug when exporting more than 1 module +* #1369: Accurate Output with -NoDefaultResponses (thanks @mdaneri!) +* #1369: Correct Schema with -NoProperties (thanks @mdaneri!) +* #1369: Fixes for OpenAPI Generation: Exception with oneOf/anyOf/allOf (thanks @mdaneri!) +* #1369: Include Min/Max Properties (thanks @mdaneri!) +* #1369: Prevent Request Body on GET Operations (thanks @mdaneri!) +* #1379: Fixes SSL timeouts when running Pode in PS7.4+ +* #1390: Changes "-ContentMediaType" and "-MediaType" parameters to "-ContentType" on most OpenAPI functions (thanks @mdaneri!) +* #1390: Ensures the generated OpenAPI document now maintains element ordering (thanks @mdaneri!) +* #1390: Fixes OpenAPI DefinitionTag being null in some functions (thanks @mdaneri!) +* #1390: Fixes OpenAPI PowerShell 5.1 compatibility issue while testing schemas (thanks @mdaneri!) +* #1397: Fixes retrieving DNS domain name on macOS +* #1400: Fixes session scoped variable when remapping while setting values +* #1400: Fixes User being needlessly splatted when passed to scriptblock for some Authentication methods + +### Documentation +* #1332: Adds documentation for CORS (thanks @mdaneri!) +* #1332: Adds missing features to the Feature List (thanks @mdaneri!) +* #1332: Splits OpenAPI documentation into multiple pages (thanks @mdaneri!) +* #1332: Updates Known Issues for PowerShell classes with PS7.4's SafeThread support (thanks @mdaneri!) +* #1333: Cleans up the Examples in the repository, and adds them to the Documentation (thanks @mdaneri!) + +### Packaging +* #1322: Applies a fix for a PS7.5 bug with Remove-Item throwing divide by zero error +* #1323: Fix build error when dotnet tries to restore from offline NuGet cache +* #1328: Make preview builds optional for PR merges +* #1342: Add GitHub Codespace Configuration and Getting Started Guide for Pode (thanks @mdaneri!) + +### Dependencies +* #1341: Bump actions/add-to-project from 1.0.1 to 1.0.2 +``` + ## v2.10.1 -Data: 27th May 2024 +Date: 27th May 2024 ```plain ### Bugs diff --git a/pode.build.ps1 b/pode.build.ps1 index 7e972d452..2d2be077d 100644 --- a/pode.build.ps1 +++ b/pode.build.ps1 @@ -890,6 +890,10 @@ task ReleaseNotes { $dependabot = @{} foreach ($pr in $prs) { + if ($pr.labels.name -icontains 'superseded') { + continue + } + $label = ($pr.labels[0].name -split ' ')[0] if ($label -iin @('new-release', 'internal-code')) { continue @@ -936,7 +940,7 @@ task ReleaseNotes { } } - $titles = @($pr.title) + $titles = @($pr.title).Trim() if ($pr.title.Contains(';')) { $titles = ($pr.title -split ';').Trim() } @@ -947,7 +951,7 @@ task ReleaseNotes { } foreach ($title in $titles) { - $str = "* #$($pr.number): $($title)" + $str = "* #$($pr.number): $($title -replace '`', "'")" if (![string]::IsNullOrWhiteSpace($author)) { $str += " (thanks @$($author)!)" }