├── .devcontainer └── devcontainer.json ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── documentation-request.md │ ├── enhancement-request.md │ ├── feature-request.md │ ├── packaging-request.md │ └── question.md ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── PSScriptAnalyzer.yml │ ├── VirusTotal-Releases.yml │ ├── VirusTotal.yml │ ├── ci-coverage.yml │ ├── ci-docs.yml │ ├── ci-no-build-needed.yml │ ├── ci-powershell.yml │ ├── ci-pwsh7_5.yml │ ├── ci-pwsh_lts.yml │ ├── ci-pwsh_preview.yml │ ├── label-issue-project.yml │ └── open-issue-project.yml ├── .gitignore ├── .vscode └── settings.json ├── Dockerfile ├── LICENSE.txt ├── PSScriptAnalyzerSettings.psd1 ├── Pode.sln ├── README.md ├── alpine.dockerfile ├── analyzers └── AvoidNewObjectRule.psm1 ├── arm32.dockerfile ├── docs ├── Getting-Started │ ├── CLI.md │ ├── Console.md │ ├── Debug.md │ ├── FirstApp.md │ ├── Frontend.md │ ├── GitHubCodespace.md │ ├── Installation.md │ ├── KnownIssues.md │ ├── Licenses.md │ ├── LocalModules.md │ ├── Migrating │ │ ├── 0X-to-1X.md │ │ └── 1X-to-2X.md │ ├── build.md │ └── pwshsupportpolicy.md ├── Hosting │ ├── AwsLambda.md │ ├── AzureFunctions.md │ ├── Docker.md │ ├── Heroku.md │ ├── IIS.md │ └── RunAsService.md ├── Listeners │ ├── Kestrel.md │ └── Pode.md ├── Servers │ ├── SMTP.md │ └── TCP.md ├── Tutorials │ ├── Authentication │ │ ├── Inbuilt │ │ │ ├── AzureAD.md │ │ │ ├── Session.md │ │ │ ├── Twitter.md │ │ │ ├── UserFile.md │ │ │ ├── WindowsAD.md │ │ │ └── WindowsLocal.md │ │ ├── Methods │ │ │ ├── ApiKey.md │ │ │ ├── Basic.md │ │ │ ├── Bearer.md │ │ │ ├── ClientCertificate.md │ │ │ ├── Custom.md │ │ │ ├── Digest.md │ │ │ ├── Form.md │ │ │ ├── JWT.md │ │ │ ├── Negotiate.md │ │ │ └── OAuth2.md │ │ └── Overview.md │ ├── Authorisation │ │ └── Overview.md │ ├── Basics.md │ ├── CORS.md │ ├── Caching.md │ ├── Certificates.md │ ├── Compression │ │ ├── Requests.md │ │ └── Responses.md │ ├── Configuration.md │ ├── Cookies.md │ ├── Endpoints │ │ ├── Basics.md │ │ ├── External.md │ │ └── Favicon.md │ ├── Endware.md │ ├── Events.md │ ├── FileWatchers.md │ ├── Headers.md │ ├── ImportingModules.md │ ├── Logging │ │ ├── Methods │ │ │ ├── Custom.md │ │ │ ├── EventViewer.md │ │ │ ├── File.md │ │ │ └── Terminal.md │ │ ├── Overview.md │ │ └── Types │ │ │ ├── Custom.md │ │ │ ├── Errors.md │ │ │ └── Requests.md │ ├── Metrics │ │ ├── Requests.md │ │ └── Uptime.md │ ├── Middleware │ │ ├── Overview.md │ │ └── Types │ │ │ ├── BodyParsing.md │ │ │ ├── CSRF.md │ │ │ ├── Limiters │ │ │ ├── AccessRules.md │ │ │ ├── Components.md │ │ │ └── RateRules.md │ │ │ ├── Security.md │ │ │ └── Sessions.md │ ├── Misc │ │ ├── CronExpressions.md │ │ ├── DesktopApp.md │ │ ├── Outputs.md │ │ ├── ServerRoot.md │ │ └── UploadFiles.md │ ├── OpenAPI │ │ ├── 1Overview.md │ │ ├── 2Properties.md │ │ ├── 3Components.md │ │ ├── 4DocumentationTools.md │ │ ├── 5ParameterValidation.md │ │ ├── 6MultipleDefinitions.md │ │ └── Specification │ │ │ └── v3.0.3.md │ ├── RequestLimits.md │ ├── Routes │ │ ├── Examples │ │ │ ├── AnonymousAccess.md │ │ │ ├── LoginPage.md │ │ │ ├── RestApiSessions.md │ │ │ └── WebPages.md │ │ ├── Overview.md │ │ └── Utilities │ │ │ ├── AutomaticFunctionsAndModules.md │ │ │ ├── ContentTypes.md │ │ │ ├── ErrorPages.md │ │ │ ├── FlashMessages.md │ │ │ ├── Redirecting.md │ │ │ ├── ResponseTypes.md │ │ │ ├── RouteGrouping.md │ │ │ ├── SSE.md │ │ │ ├── SimplePages.md │ │ │ └── StaticContent.md │ ├── Schedules.md │ ├── ScopedVariables.md │ ├── Scoping.md │ ├── Secrets │ │ ├── Examples │ │ │ └── SecretStore.md │ │ ├── Overview.md │ │ └── Types │ │ │ ├── Custom.md │ │ │ └── SecretManagement.md │ ├── Server Operations │ │ ├── Disabling │ │ │ └── Overview.md │ │ ├── Overview.md │ │ ├── Restarting │ │ │ ├── Overview.md │ │ │ └── Type │ │ │ │ ├── AutoRestarting.md │ │ │ │ └── FileMonitoring.md │ │ └── Suspending │ │ │ └── Overview.md │ ├── SharedState.md │ ├── Tasks.md │ ├── Threading │ │ ├── Lockables.md │ │ ├── Mutexes.md │ │ ├── Semaphores.md │ │ └── ServerThreads.md │ ├── Timers.md │ ├── Views │ │ ├── Pode.md │ │ └── ThirdParty.md │ ├── WebEvent.md │ └── WebSockets │ │ ├── Endpoints.md │ │ └── External.md ├── images │ ├── GXAjs98JsZ.png │ ├── companies │ │ └── coop-logo.png │ ├── event-flow.png │ ├── favicon.ico │ ├── icon-transparent.png │ └── icon.png ├── index.md ├── release-notes.md ├── requirements.txt └── roadmap.md ├── examples ├── Caching.ps1 ├── Create-Routes.ps1 ├── Dockerfile ├── Dot-SourceScript.ps1 ├── External-Funcs.ps1 ├── File-Monitoring.ps1 ├── File-Watchers.ps1 ├── FileBrowser │ ├── FileBrowser.ps1 │ └── public │ │ └── ruler.png ├── HelloWorld │ └── HelloWorld.ps1 ├── IIS-Example.ps1 ├── Logging.ps1 ├── Looping-Service.ps1 ├── Mail-Server.ps1 ├── Middleware.ps1 ├── OneOff-Script.ps1 ├── OpenApi-SimplePotato.ps1 ├── OpenApi-TuttiFrutti.ps1 ├── PetStore │ ├── Order.psm1 │ ├── PetData.psm1 │ ├── Petstore-OpenApi.ps1 │ ├── Petstore-OpenApiMultiTag.ps1 │ ├── UserData.psm1 │ ├── data │ │ └── PetData.json │ └── server.psd1 ├── Schedules-CronHelper.ps1 ├── Schedules-LongRunning.ps1 ├── Schedules-Routes.ps1 ├── Schedules.ps1 ├── ServerFrom-File.ps1 ├── Shared-State.ps1 ├── Suspend-Resume.ps1 ├── SwaggerEditor │ ├── Swagger-Editor.ps1 │ └── www │ │ └── index.html ├── Tasks.ps1 ├── Tcp-Server.ps1 ├── Tcp-ServerAuth.ps1 ├── Tcp-ServerHttp.ps1 ├── Tcp-ServerMultiEndpoint.ps1 ├── Threading.ps1 ├── Timers-Route.ps1 ├── Timers.ps1 ├── Web-AuthApiKey.ps1 ├── Web-AuthBasic.ps1 ├── Web-AuthBasicAccess.ps1 ├── Web-AuthBasicAdhoc.ps1 ├── Web-AuthBasicAnon.ps1 ├── Web-AuthBasicBearer.ps1 ├── Web-AuthBasicClientcert.ps1 ├── Web-AuthBasicHeader.ps1 ├── Web-AuthDigest.ps1 ├── Web-AuthForm.ps1 ├── Web-AuthFormAccess.ps1 ├── Web-AuthFormAd.ps1 ├── Web-AuthFormAnon.ps1 ├── Web-AuthFormCreds.ps1 ├── Web-AuthFormFile.ps1 ├── Web-AuthFormLocal.ps1 ├── Web-AuthFormMerged.ps1 ├── Web-AuthFormSessionAuth.ps1 ├── Web-AuthMerged.ps1 ├── Web-AuthNegotiate.ps1 ├── Web-AuthOauth2.ps1 ├── Web-AuthOauth2Form.ps1 ├── Web-AuthOauth2Oidc.ps1 ├── Web-Cookies.ps1 ├── Web-Csrf.ps1 ├── Web-FuncsToRoutes.ps1 ├── Web-Gui.ps1 ├── Web-GzipRequest.ps1 ├── Web-Hostname.ps1 ├── Web-HostnameKestrel.ps1 ├── Web-Imports.ps1 ├── Web-Metrics.ps1 ├── Web-Pages.ps1 ├── Web-PagesDocker.ps1 ├── Web-PagesHttps.ps1 ├── Web-PagesKestrel.ps1 ├── Web-PagesMD.ps1 ├── Web-PagesSimple.ps1 ├── Web-PagesUsing.ps1 ├── Web-RestApi.ps1 ├── Web-RestOpenApi.ps1 ├── Web-RestOpenApiShared.ps1 ├── Web-RestOpenApiSimple.ps1 ├── Web-RouteEndpoints.ps1 ├── Web-RouteGroup.ps1 ├── Web-RouteListenNames.ps1 ├── Web-RouteProtocols.ps1 ├── Web-Secrets.ps1 ├── Web-SecretsLocal.ps1 ├── Web-SelfSigned.ps1 ├── Web-Sessions.ps1 ├── Web-Signal.ps1 ├── Web-SignalConnection.ps1 ├── Web-SimplePages.ps1 ├── Web-Sockets.ps1 ├── Web-Sse.ps1 ├── Web-Static.ps1 ├── Web-StaticAuth.ps1 ├── Web-TpEPS.ps1 ├── Web-TpPSHTML.ps1 ├── Web-Upload.ps1 ├── Web-UploadKestrel.ps1 ├── Web-UsePodeAuth.ps1 ├── WebAuth-ApikeyJWT.ps1 ├── WebHook.ps1 ├── WebNunit-RestApi.ps1 ├── Write-Response.ps1 ├── assets │ ├── [metadata].json │ ├── file.txt │ ├── images │ │ └── Fry.png │ └── index.html ├── auth │ └── SampleAuth.ps1 ├── certs │ ├── cert.pem │ ├── cert_nodes.pem │ ├── key.pem │ ├── key_nodes.pem │ ├── pode-cert.cer │ └── pode-cert.pfx ├── docker-compose.yml ├── modules │ ├── External-Funcs.psm1 │ ├── Imported-Funcs.ps1 │ ├── Imported-SubFuncs.ps1 │ ├── RouteScript.ps1 │ └── Script1.ps1 ├── open-gui.bat ├── package.json ├── public │ ├── Anger.jpg │ ├── Ruler.png │ ├── [brackets].txt │ ├── dummy.txt │ ├── scripts │ │ ├── simple.js │ │ ├── simple.js.eps │ │ ├── simple.js.pode │ │ ├── simple.js.ps1 │ │ ├── sse.js │ │ └── websockets.js │ └── styles │ │ ├── simple.css │ │ ├── simple.css.eps │ │ ├── simple.css.pode │ │ ├── simple.css.ps1 │ │ └── websockets.css ├── relative │ └── dot-source-server.ps1 ├── routes │ └── route.ps1 ├── scripts │ ├── routeScript.ps1 │ ├── schedule.ps1 │ ├── server.ps1 │ └── timer.ps1 ├── server.psd1 ├── static │ ├── Ruler.png │ ├── index.html │ └── public │ │ ├── Anger.jpg │ │ ├── scripts │ │ └── simple.js │ │ └── styles │ │ └── simple.css ├── timers │ └── timer.ps1 ├── users │ └── users.json ├── views │ ├── auth-about.pode │ ├── auth-home-anon.pode │ ├── auth-home.pode │ ├── auth-login.pode │ ├── auth-register.pode │ ├── gui.pode │ ├── index-csrf.pode │ ├── index.eps │ ├── index.md │ ├── index.ps1 │ ├── simple.html │ ├── simple.pode │ ├── sse-home.html │ ├── web-static.pode │ ├── web-upload-multi.html │ ├── web-upload.html │ └── websockets.html ├── web-RestOpenApiFuncs.ps1 └── web.config ├── images ├── example_code.png ├── example_code_2.png ├── example_code_readme.svg ├── icon-new.png ├── icon-new.svg ├── icon-transparent.png ├── icon.png ├── icon_name_bottom.png └── icon_name_left.png ├── licenses ├── LICENSE.Kerberos.NET.txt ├── LICENSE.PSYaml.txt ├── LICENSE.RapiDoc.txt ├── LICENSE.RapiPdf.txt ├── LICENSE.SecretManagement.txt ├── LICENSE.bootstrap.txt ├── LICENSE.highlightjs.txt ├── LICENSE.openapi-explorer.txt ├── LICENSE.powershell-yaml.txt ├── LICENSE.redoc.txt ├── LICENSE.stoplight.txt ├── LICENSE.swagger-editor.txt └── LICENSE.swagger-ui.txt ├── mkdocs-overrides └── main.html ├── mkdocs.yml ├── package.json ├── packers ├── choco │ ├── VERIFICATION.txt │ ├── pode_template.nuspec │ └── tools │ │ ├── ChocolateyInstall_template.ps1 │ │ └── ChocolateyUninstall.ps1 └── docker │ └── arm32 │ └── Dockerfile ├── pode.build.ps1 ├── src ├── Listener │ ├── FileSystemWatcher │ │ ├── BufferingFileSystemWatcher.cs │ │ ├── EventQueueOverflowException.cs │ │ ├── FileWatcherErrorEventArgs.cs │ │ └── RecoveringFileSystemWatcher.cs │ ├── NuGet.config │ ├── Pode.csproj │ ├── PodeClientSignal.cs │ ├── PodeCompressionType.cs │ ├── PodeConnector.cs │ ├── PodeContext.cs │ ├── PodeContextState.cs │ ├── PodeEndpoint.cs │ ├── PodeFileEvent.cs │ ├── PodeFileWatcher.cs │ ├── PodeFileWatcherChangeType.cs │ ├── PodeForm.cs │ ├── PodeFormData.cs │ ├── PodeFormFile.cs │ ├── PodeHelpers.cs │ ├── PodeHttpRequest.cs │ ├── PodeItemQueue.cs │ ├── PodeKerberosAuth.cs │ ├── PodeListener.cs │ ├── PodeLoggingLevel.cs │ ├── PodeNative.cs │ ├── PodeProtocol.cs │ ├── PodeProtocolType.cs │ ├── PodeReceiver.cs │ ├── PodeRequest.cs │ ├── PodeRequestException.cs │ ├── PodeResponse.cs │ ├── PodeResponseHeaders.cs │ ├── PodeServerEvent.cs │ ├── PodeServerEventType.cs │ ├── PodeServerSignal.cs │ ├── PodeServerState.cs │ ├── PodeSignal.cs │ ├── PodeSignalFrame.cs │ ├── PodeSignalRequest.cs │ ├── PodeSmtpAttachment.cs │ ├── PodeSmtpCommand.cs │ ├── PodeSmtpRequest.cs │ ├── PodeSmtpStartType.cs │ ├── PodeSocket.cs │ ├── PodeSseScope.cs │ ├── PodeStreamState.cs │ ├── PodeTcpRequest.cs │ ├── PodeTlsMode.cs │ ├── PodeWatcher.cs │ ├── PodeWebSocket.cs │ ├── PodeWebSocketCloseFrom.cs │ ├── PodeWebSocketRequest.cs │ └── PodeWsOpCode.cs ├── Locales │ ├── ar │ │ └── Pode.psd1 │ ├── de │ │ └── Pode.psd1 │ ├── en-us │ │ └── Pode.psd1 │ ├── en │ │ └── Pode.psd1 │ ├── es │ │ └── Pode.psd1 │ ├── fr │ │ └── Pode.psd1 │ ├── it │ │ └── Pode.psd1 │ ├── ja │ │ └── Pode.psd1 │ ├── ko │ │ └── Pode.psd1 │ ├── nl │ │ └── Pode.psd1 │ ├── pl │ │ └── Pode.psd1 │ ├── pt │ │ └── Pode.psd1 │ └── zh │ │ └── Pode.psd1 ├── Misc │ ├── default-doc-bookmarks.html.pode │ ├── default-error-page.html.pode │ ├── default-error-page.json.pode │ ├── default-error-page.xml.pode │ ├── default-explorer.html.pode │ ├── default-file-browsing.html.pode │ ├── default-rapidoc.html.pode │ ├── default-rapipdf.html.pode │ ├── default-redoc.html.pode │ ├── default-stoplight.html.pode │ ├── default-swagger-editor.html.pode │ ├── default-swagger.html.pode │ └── favicon.ico ├── Pode.Internal.psd1 ├── Pode.Internal.psm1 ├── Pode.psd1 ├── Pode.psm1 ├── Private │ ├── Access.ps1 │ ├── Authentication.ps1 │ ├── AutoImport.ps1 │ ├── Caching.ps1 │ ├── CancellationToken.ps1 │ ├── Console.ps1 │ ├── Context.ps1 │ ├── Cookies.ps1 │ ├── CronParser.ps1 │ ├── Cryptography.ps1 │ ├── Endpoints.ps1 │ ├── Endware.ps1 │ ├── Events.ps1 │ ├── FileMonitor.ps1 │ ├── FileWatchers.ps1 │ ├── Gui.ps1 │ ├── Helpers.ps1 │ ├── Limit.ps1 │ ├── Logging.ps1 │ ├── Mappers.ps1 │ ├── Metrics.ps1 │ ├── Middleware.ps1 │ ├── NameGenerator.ps1 │ ├── OpenApi.ps1 │ ├── PodeServer.ps1 │ ├── Responses.ps1 │ ├── Routes.ps1 │ ├── Runspaces.ps1 │ ├── Schedules.ps1 │ ├── ScopedVariables.ps1 │ ├── Secrets.ps1 │ ├── Security.ps1 │ ├── Server.ps1 │ ├── Serverless.ps1 │ ├── ServiceServer.ps1 │ ├── Sessions.ps1 │ ├── Setup.ps1 │ ├── SmtpServer.ps1 │ ├── Tasks.ps1 │ ├── TcpServer.ps1 │ ├── Timers.ps1 │ ├── Verbs.ps1 │ └── WebSockets.ps1 └── Public │ ├── Access.ps1 │ ├── Authentication.ps1 │ ├── AutoImport.ps1 │ ├── Caching.ps1 │ ├── Cookies.ps1 │ ├── Core.ps1 │ ├── Endpoint.ps1 │ ├── Events.ps1 │ ├── FavIcon.ps1 │ ├── FileWatchers.ps1 │ ├── Flash.ps1 │ ├── Handlers.ps1 │ ├── Headers.ps1 │ ├── Limit.ps1 │ ├── Logging.ps1 │ ├── Metrics.ps1 │ ├── Middleware.ps1 │ ├── OAComponents.ps1 │ ├── OAProperties.ps1 │ ├── OpenApi.ps1 │ ├── Responses.ps1 │ ├── Routes.ps1 │ ├── Runspaces.ps1 │ ├── SSE.ps1 │ ├── Schedules.ps1 │ ├── ScopedVariables.ps1 │ ├── Secrets.ps1 │ ├── Security.ps1 │ ├── Sessions.ps1 │ ├── State.ps1 │ ├── Tasks.ps1 │ ├── Threading.ps1 │ ├── Timers.ps1 │ ├── Utilities.ps1 │ ├── Verbs.ps1 │ └── WebSockets.ps1 └── tests ├── integration ├── Authentication.Tests.ps1 ├── Endpoints.Tests.ps1 ├── OpenApi.Tests.ps1 ├── RestApi.Https.Tests.ps1 ├── RestApi.Tests.ps1 ├── Schedules.Tests.ps1 ├── Sessions.Tests.ps1 ├── Timers.Tests.ps1 ├── WebPages.Tests.ps1 ├── WebSocket.Tests.ps1 ├── images │ └── custom_ruler.png ├── public │ └── ruler.png ├── specs │ ├── OpenApi-TuttiFrutti_3.0.3.json │ └── OpenApi-TuttiFrutti_3.1.0.json └── views │ ├── dynamic.pode │ └── static.html ├── perf ├── README.md ├── basic │ ├── css_style.js │ ├── full_flow.js │ ├── image.js │ └── root.js └── utils │ └── common.js ├── shared └── TestHelper.ps1 └── unit ├── Authentication.Tests.ps1 ├── Context.Tests.ps1 ├── Cookies.Tests.ps1 ├── CronParser.Tests.ps1 ├── Cryptography.Tests.ps1 ├── Endware.Tests.ps1 ├── Favicon.Tests.ps1 ├── Flash.Tests.ps1 ├── Handlers.Tests.ps1 ├── Headers.Tests.ps1 ├── Helpers.Tests.ps1 ├── Localization.Tests.ps1 ├── Logging.Tests.ps1 ├── Mappers.Tests.ps1 ├── Metrics.Tests.ps1 ├── Middleware.Tests.ps1 ├── NameGenerator.Tests.ps1 ├── OpenApi.Tests.ps1 ├── PrivateOpenApi.Tests.ps1 ├── Responses.Tests.ps1 ├── Routes.Tests.ps1 ├── Schedules.Tests.ps1 ├── Security.Tests.ps1 ├── Server.Tests.ps1 ├── Serverless.Tests.ps1 ├── Sessions.Tests.ps1 ├── State.Tests.ps1 ├── Timers.Tests.ps1 └── _.Tests.ps1 /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Codespace with PowerShell, Pester, Invoke-Build, and .NET 8", 3 | "image": "mcr.microsoft.com/vscode/devcontainers/base:ubuntu", 4 | "features": { 5 | "ghcr.io/devcontainers/features/powershell:1": {}, 6 | "ghcr.io/devcontainers/features/dotnet:1": { 7 | "version": "8.0" 8 | } 9 | }, 10 | "customizations": { 11 | "vscode": { 12 | "extensions": [ 13 | "ms-vscode.powershell", 14 | "pspester.pester-test" 15 | ] 16 | } 17 | }, 18 | "postCreateCommand": "pwsh -Command 'Install-Module -Name InvokeBuild,Pester -Force -SkipPublisherCheck; sleep 5; Invoke-Build Build '" 19 | } 20 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [Badgerati] 4 | ko_fi: badgerati 5 | custom: ["https://www.paypal.me/badgerati"] -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Create a bug report to help us improve 4 | title: '' 5 | labels: 'bug :bug:' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Describe the Bug 11 | A clear and concise description of what the bug is. 12 | 13 | ### Steps To Reproduce 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | ### Expected Behavior 21 | A clear and concise description of what you expected to happen. 22 | 23 | ### Screenshots 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | ### Platform 27 | - OS: [e.g. iOS, Windows] 28 | - Browser: [e.g. Chrome, Safari] 29 | - Versions: 30 | - Pode: [e.g. Pode v1.7.3] 31 | - PowerShell: [e.g. PS6.2.1] 32 | 33 | ### Additional Context 34 | Add any other context about the problem here. 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation Request 3 | about: Suggest an edit to Pode's documentation 4 | title: '' 5 | labels: 'documentation :book:' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Describe the Change 11 | A clear and concise description of the edit. 12 | 13 | ### Additional Context 14 | Add any other context or screenshots about the enhancement request here. 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/enhancement-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Enhancement Request 3 | about: Suggest an enhancement for an existing feature. 4 | title: '' 5 | labels: 'enhancement :arrow_up:' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Describe the Change 11 | A clear and concise description of what you want to happen. 12 | 13 | ### Related Issues 14 | A clear and concise description of what the problem is, or a link/reference to the issue. 15 | 16 | ### Additional Context 17 | Add any other context or screenshots about the enhancement request here. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest a new feature for Pode 4 | title: '' 5 | labels: 'feature :sunny:' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Describe the Feature 11 | A clear and concise description of what you want to happen. 12 | 13 | ### Related Issues 14 | A clear and concise description of what the problem is, or a link/reference to the issue. 15 | 16 | ### Additional Context 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/packaging-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Packaging Request 3 | about: Suggest an improvement for the packaging of Pode, such as a new version of software. 4 | title: '' 5 | labels: 'packaging :package:' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Describe the Change 11 | A clear and concise description of what you want to happen. 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask a question about Pode's features, examples, or documentation 4 | title: '' 5 | labels: 'question :grey_question:' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Question 11 | A clear and concise description of your question. 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | labels: 8 | - "packaging :package:" 9 | 10 | - package-ecosystem: "npm" 11 | directory: "/" 12 | schedule: 13 | interval: "daily" 14 | labels: 15 | - "packaging :package:" -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### Description of the Change 2 | A clear and concise description of what has been changed. 3 | 4 | ### Related Issue 5 | A link/reference to the GitHub issue. 6 | 7 | ### Examples 8 | If relevant, include any examples of using what you have changed. 9 | 10 | ### Additional Context 11 | Add any other context or screenshots about the pull request request here. 12 | -------------------------------------------------------------------------------- /.github/workflows/PSScriptAnalyzer.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | # 6 | # https://github.com/microsoft/psscriptanalyzer-action 7 | # For more information on PSScriptAnalyzer in general, see 8 | # https://github.com/PowerShell/PSScriptAnalyzer 9 | 10 | name: PSScriptAnalyzer 11 | 12 | on: 13 | push: 14 | branches: 15 | - 'develop' 16 | paths: 17 | - 'src/**.ps1' 18 | - 'src/*.psm1' 19 | - 'src/*.psd1' 20 | - 'PSScriptAnalyzerSettings.psd1' 21 | - '.github/workflows/PSScriptAnalyzer.yml' 22 | pull_request: 23 | branches: 24 | - 'develop' 25 | paths: 26 | - 'src/**.ps1' 27 | - 'src/*.psm1' 28 | - 'src/*.psd1' 29 | - 'PSScriptAnalyzerSettings.psd1' 30 | - '.github/workflows/PSScriptAnalyzer.yml' 31 | schedule: 32 | - cron: '20 16 * * 6' 33 | 34 | permissions: 35 | contents: read 36 | 37 | jobs: 38 | build: 39 | permissions: 40 | contents: read # for actions/checkout to fetch code 41 | security-events: write # for github/codeql-action/upload-sarif to upload SARIF results 42 | actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status 43 | name: PSScriptAnalyzer 44 | runs-on: ubuntu-latest 45 | steps: 46 | - uses: actions/checkout@v4 47 | 48 | - name: Run PSScriptAnalyzer 49 | uses: microsoft/psscriptanalyzer-action@6b2948b1944407914a58661c49941824d149734f 50 | with: 51 | path: .\src 52 | recurse: true 53 | settings: .\PSScriptAnalyzerSettings.psd1 54 | output: results.sarif 55 | 56 | - name: Upload SARIF results file 57 | uses: github/codeql-action/upload-sarif@v3 58 | with: 59 | sarif_file: results.sarif 60 | -------------------------------------------------------------------------------- /.github/workflows/VirusTotal-Releases.yml: -------------------------------------------------------------------------------- 1 | name: VirusTotal Scan - Releases 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Check VIRUSTOTAL_API_KEY 13 | env: 14 | VIRUSTOTAL_API_KEY: ${{ secrets.VIRUSTOTAL_API_KEY }} 15 | run: | 16 | if [ -z "$VIRUSTOTAL_API_KEY" ]; then 17 | echo "VIRUSTOTAL_API_KEY is not set. Exiting workflow." 18 | exit 1 19 | fi 20 | echo "VIRUSTOTAL_API_KEY is set. Proceeding with the workflow." 21 | 22 | - name: Run VirusTotal Scan 23 | uses: crazy-max/ghaction-virustotal@v4 24 | with: 25 | vt_api_key: ${{ secrets.VIRUSTOTAL_API_KEY }} 26 | github_token: ${{ secrets.GITHUB_TOKEN }} 27 | update_release_body: true 28 | request_rate: 4 29 | files: | 30 | .zip$ 31 | -------------------------------------------------------------------------------- /.github/workflows/VirusTotal.yml: -------------------------------------------------------------------------------- 1 | name: VirusTotal Scan 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'develop' 7 | paths: 8 | - 'src/**' 9 | - 'pode.build.ps1' 10 | - '.github/workflows/VirusTotal.yml' 11 | pull_request: 12 | branches: 13 | - 'master' 14 | paths: 15 | - 'src/**' 16 | - 'pode.build.ps1' 17 | - '.github/workflows/VirusTotal.yml' 18 | schedule: 19 | - cron: '0 12 * * *' 20 | 21 | env: 22 | INVOKE_BUILD_VERSION: '5.12.2' 23 | POWERSHELL_VERSION: 'lts' 24 | 25 | jobs: 26 | build: 27 | runs-on: ubuntu-latest 28 | steps: 29 | 30 | - name: Check VIRUSTOTAL_API_KEY 31 | env: 32 | VIRUSTOTAL_API_KEY: ${{ secrets.VIRUSTOTAL_API_KEY }} 33 | run: | 34 | if [ -z "$VIRUSTOTAL_API_KEY" ]; then 35 | echo "VIRUSTOTAL_API_KEY is not set. Exiting workflow." 36 | exit 1 37 | fi 38 | echo "VIRUSTOTAL_API_KEY is set. Proceeding with the workflow." 39 | 40 | - uses: actions/checkout@v4 41 | 42 | - name: Setup .NET 43 | uses: actions/setup-dotnet@v4 44 | with: 45 | dotnet-version: 9.x 46 | 47 | - name: Setup Powershell 48 | shell: pwsh 49 | run: | 50 | Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force 51 | Invoke-Build SetupPowerShell -PowerShellVersion $env:POWERSHELL_VERSION 52 | 53 | - name: Install Invoke-Build 54 | shell: pwsh 55 | run: | 56 | Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force 57 | 58 | - name: Build Zip Package 59 | shell: pwsh 60 | run: | 61 | Invoke-Build Compress 62 | 63 | - name: Run VirusTotal Scan 64 | uses: crazy-max/ghaction-virustotal@v4 65 | with: 66 | vt_api_key: ${{ secrets.VIRUSTOTAL_API_KEY }} 67 | request_rate: 4 68 | files: | 69 | ./deliverable/*.zip 70 | -------------------------------------------------------------------------------- /.github/workflows/ci-coverage.yml: -------------------------------------------------------------------------------- 1 | name: Pode CI Coverage 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | - 'develop' 8 | paths: 9 | - 'src/**' 10 | - 'tests/**' 11 | - 'pode.build.ps1' 12 | - '.github/workflows/ci-coverage.yml' 13 | pull_request: 14 | branches: 15 | - '*' 16 | paths: 17 | - 'src/**' 18 | - 'tests/**' 19 | - 'pode.build.ps1' 20 | - '.github/workflows/ci-coverage.yml' 21 | 22 | env: 23 | INVOKE_BUILD_VERSION: '5.12.2' 24 | 25 | jobs: 26 | build: 27 | runs-on: ubuntu-latest 28 | 29 | steps: 30 | - uses: actions/checkout@v4 31 | 32 | - name: Check PowerShell version 33 | shell: pwsh 34 | run: | 35 | $PSVersionTable.PSVersion 36 | 37 | - name: Setup .NET 38 | uses: actions/setup-dotnet@v4 39 | with: 40 | dotnet-version: 9.x 41 | 42 | - name: Install Invoke-Build 43 | shell: pwsh 44 | run: | 45 | Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force 46 | 47 | - name: Run Pester Tests 48 | shell: pwsh 49 | env: 50 | PODE_COVERALLS_TOKEN: ${{ secrets.PODE_COVERALLS_TOKEN }} 51 | PODE_RUN_CODE_COVERAGE: false 52 | run: | 53 | Invoke-Build Test -------------------------------------------------------------------------------- /.github/workflows/ci-docs.yml: -------------------------------------------------------------------------------- 1 | name: Pode CI - Docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | - '!gh-pages' 8 | paths: 9 | - 'mkdocs.yml' 10 | - 'mkdocs-overrides/**' 11 | - 'docs/**' 12 | - '.github/workflows/ci-docs.yml' 13 | - 'pode.build.ps1' 14 | - 'src/Pode.psd1' 15 | pull_request: 16 | branches: 17 | - '*' 18 | paths: 19 | - 'mkdocs.yml' 20 | - 'mkdocs-overrides/**' 21 | - 'docs/**' 22 | - '.github/workflows/ci-docs.yml' 23 | - 'pode.build.ps1' 24 | - 'src/Pode.psd1' 25 | 26 | env: 27 | INVOKE_BUILD_VERSION: '5.12.2' 28 | 29 | jobs: 30 | build: 31 | runs-on: windows-latest 32 | 33 | strategy: 34 | fail-fast: false 35 | 36 | steps: 37 | - uses: actions/checkout@v4 38 | 39 | - name: Setup .NET 40 | uses: actions/setup-dotnet@v4 41 | with: 42 | dotnet-version: 9.x 43 | 44 | - name: Install Invoke-Build 45 | shell: pwsh 46 | run: | 47 | Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force 48 | 49 | - name: Build Documentation 50 | shell: pwsh 51 | run: | 52 | Invoke-Build DocsBuild -------------------------------------------------------------------------------- /.github/workflows/ci-no-build-needed.yml: -------------------------------------------------------------------------------- 1 | name: Pode CI - No Build Needed 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | - '!gh-pages' 8 | paths-ignore: 9 | - 'mkdocs.yml' 10 | - 'mkdocs-overrides/**' 11 | - 'docs/**' 12 | - 'src/**' 13 | - 'tests/**' 14 | - '.github/workflows/ci-docs.yml' 15 | - '.github/workflows/ci-pwsh_lts.yml' 16 | - '.github/workflows/ci-pwsh7_2.yml' 17 | - '.github/workflows/ci-powershell.yml' 18 | - '.github/workflows/ci-coverage.yml' 19 | - '.github/workflows/PSScriptAnalyzer.yml' 20 | - 'pode.build.ps1' 21 | - 'Dockerfile' 22 | - '*.dockerfile' 23 | - 'PSScriptAnalyzerSettings.psd1' 24 | pull_request: 25 | branches: 26 | - '*' 27 | paths-ignore: 28 | - 'mkdocs.yml' 29 | - 'mkdocs-overrides/**' 30 | - 'docs/**' 31 | - 'src/**' 32 | - 'tests/**' 33 | - '.github/workflows/ci-docs.yml' 34 | - '.github/workflows/ci-pwsh_lts.yml' 35 | - '.github/workflows/ci-pwsh7_2.yml' 36 | - '.github/workflows/ci-powershell.yml' 37 | - '.github/workflows/ci-coverage.yml' 38 | - '.github/workflows/PSScriptAnalyzer.yml' 39 | - 'pode.build.ps1' 40 | - 'Dockerfile' 41 | - '*.dockerfile' 42 | - 'PSScriptAnalyzerSettings.psd1' 43 | 44 | jobs: 45 | build: 46 | runs-on: ubuntu-latest 47 | 48 | strategy: 49 | fail-fast: false 50 | 51 | steps: 52 | - name: Install Invoke-Build 53 | shell: pwsh 54 | run: | 55 | Write-Host "No build needed for this commit" -------------------------------------------------------------------------------- /.github/workflows/ci-powershell.yml: -------------------------------------------------------------------------------- 1 | name: Pode CI - Powershell Desktop 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | - '!gh-pages' 8 | paths: 9 | - 'src/**' 10 | - 'tests/**' 11 | - 'pode.build.ps1' 12 | - '.github/workflows/ci-powershell.yml' 13 | pull_request: 14 | branches: 15 | - '*' 16 | paths: 17 | - 'src/**' 18 | - 'tests/**' 19 | - 'pode.build.ps1' 20 | - '.github/workflows/ci-powershell.yml' 21 | 22 | env: 23 | INVOKE_BUILD_VERSION: '5.12.2' 24 | 25 | jobs: 26 | build: 27 | runs-on: windows-latest 28 | 29 | strategy: 30 | fail-fast: false 31 | 32 | steps: 33 | - uses: actions/checkout@v4 34 | 35 | - name: Check PowerShell version 36 | shell: powershell 37 | run: | 38 | $PSVersionTable.PSVersion 39 | 40 | - name: Setup .NET 41 | uses: actions/setup-dotnet@v4 42 | with: 43 | dotnet-version: 9.x 44 | 45 | - name: Install Invoke-Build 46 | shell: powershell 47 | run: | 48 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 49 | Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force 50 | 51 | - name: Run Pester Tests 52 | shell: powershell 53 | run: | 54 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 55 | Invoke-Build Test 56 | 57 | - name: Build Packages 58 | shell: powershell 59 | run: | 60 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 61 | Invoke-Build Pack -------------------------------------------------------------------------------- /.github/workflows/ci-pwsh7_5.yml: -------------------------------------------------------------------------------- 1 | name: Pode CI - pwsh 7.5 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | - '!gh-pages' 8 | paths: 9 | - 'src/**' 10 | - 'tests/**' 11 | - 'pode.build.ps1' 12 | - '.github/workflows/ci-pwsh7_5.yml' 13 | - 'Dockerfile' 14 | - '*.dockerfile' 15 | pull_request: 16 | branches: 17 | - '*' 18 | paths: 19 | - 'src/**' 20 | - 'tests/**' 21 | - 'pode.build.ps1' 22 | - '.github/workflows/ci-pwsh7_5.yml' 23 | - 'Dockerfile' 24 | - '*.dockerfile' 25 | 26 | env: 27 | INVOKE_BUILD_VERSION: '5.12.2' 28 | POWERSHELL_VERSION: '7.5.1' 29 | 30 | jobs: 31 | build: 32 | runs-on: ${{ matrix.os }} 33 | 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | os: [ubuntu-latest, windows-latest, macOS-latest] 38 | 39 | steps: 40 | - uses: actions/checkout@v4 41 | 42 | - name: Setup .NET 43 | uses: actions/setup-dotnet@v4 44 | with: 45 | dotnet-version: 9.x 46 | 47 | - name: Setup Powershell - Unix 48 | shell: pwsh 49 | if: runner.os == 'Linux' || runner.os == 'macOS' 50 | run: | 51 | Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force 52 | Invoke-Build SetupPowerShell -PowerShellVersion $env:POWERSHELL_VERSION 53 | 54 | - name: Setup Powershell - Windows 55 | shell: PowerShell 56 | if: runner.os == 'Windows' 57 | run: | 58 | Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force 59 | Invoke-Build SetupPowerShell -PowerShellVersion $env:POWERSHELL_VERSION 60 | 61 | - name: Output PowerShell version 62 | shell: pwsh 63 | run: | 64 | $PSVersionTable.PSVersion 65 | 66 | - name: Install Invoke-Build 67 | shell: pwsh 68 | run: | 69 | Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force 70 | 71 | - name: Run Pester Tests 72 | shell: pwsh 73 | run: | 74 | Invoke-Build Test 75 | 76 | - name: Build Packages 77 | shell: pwsh 78 | run: | 79 | Invoke-Build Pack -------------------------------------------------------------------------------- /.github/workflows/ci-pwsh_lts.yml: -------------------------------------------------------------------------------- 1 | name: Pode CI - pwsh lts 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | - '!gh-pages' 8 | paths: 9 | - 'src/**' 10 | - 'tests/**' 11 | - 'pode.build.ps1' 12 | - '.github/workflows/ci-pwsh_lts.yml' 13 | - 'Dockerfile' 14 | - '*.dockerfile' 15 | pull_request: 16 | branches: 17 | - '*' 18 | paths: 19 | - 'src/**' 20 | - 'tests/**' 21 | - 'pode.build.ps1' 22 | - '.github/workflows/ci-pwsh_lts.yml' 23 | - 'Dockerfile' 24 | - '*.dockerfile' 25 | 26 | env: 27 | INVOKE_BUILD_VERSION: '5.12.2' 28 | POWERSHELL_VERSION: 'lts' 29 | 30 | jobs: 31 | build: 32 | runs-on: ${{ matrix.os }} 33 | 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | os: [ubuntu-latest, windows-latest, macOS-latest] 38 | 39 | steps: 40 | - uses: actions/checkout@v4 41 | 42 | - name: Setup .NET 43 | uses: actions/setup-dotnet@v4 44 | with: 45 | dotnet-version: 9.x 46 | 47 | - name: Setup Powershell - Unix 48 | shell: pwsh 49 | if: runner.os == 'Linux' || runner.os == 'macOS' 50 | run: | 51 | Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force 52 | Invoke-Build SetupPowerShell -PowerShellVersion $env:POWERSHELL_VERSION 53 | 54 | - name: Setup Powershell - Windows 55 | shell: PowerShell 56 | if: runner.os == 'Windows' 57 | run: | 58 | Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force 59 | Invoke-Build SetupPowerShell -PowerShellVersion $env:POWERSHELL_VERSION 60 | 61 | - name: Output PowerShell version 62 | shell: pwsh 63 | run: | 64 | $PSVersionTable.PSVersion 65 | 66 | - name: Install Invoke-Build 67 | shell: pwsh 68 | run: | 69 | Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force 70 | 71 | - name: Run Pester Tests 72 | shell: pwsh 73 | run: | 74 | Invoke-Build Test 75 | 76 | - name: Build Packages 77 | shell: pwsh 78 | run: | 79 | Invoke-Build Pack -------------------------------------------------------------------------------- /.github/workflows/ci-pwsh_preview.yml: -------------------------------------------------------------------------------- 1 | name: Pode CI - pwsh preview 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | - '!gh-pages' 8 | paths: 9 | - 'src/**' 10 | - 'tests/**' 11 | - 'pode.build.ps1' 12 | - '.github/workflows/ci-pwsh_preview.yml' 13 | - 'Dockerfile' 14 | - '*.dockerfile' 15 | pull_request: 16 | branches: 17 | - '*' 18 | paths: 19 | - 'src/**' 20 | - 'tests/**' 21 | - 'pode.build.ps1' 22 | - '.github/workflows/ci-pwsh_preview.yml' 23 | - 'Dockerfile' 24 | - '*.dockerfile' 25 | 26 | env: 27 | INVOKE_BUILD_VERSION: '5.12.2' 28 | POWERSHELL_VERSION: 'Preview' 29 | 30 | jobs: 31 | build-preview: 32 | runs-on: ${{ matrix.os }} 33 | 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | os: [ubuntu-latest, windows-latest, macOS-latest] 38 | 39 | steps: 40 | - uses: actions/checkout@v4 41 | 42 | - name: Setup .NET 43 | uses: actions/setup-dotnet@v4 44 | with: 45 | dotnet-version: 9.x 46 | 47 | - name: Setup Powershell - Unix 48 | shell: pwsh 49 | if: runner.os == 'Linux' || runner.os == 'macOS' 50 | run: | 51 | Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force 52 | Invoke-Build SetupPowerShell -PowerShellVersion $env:POWERSHELL_VERSION 53 | 54 | - name: Setup Powershell - Windows 55 | shell: PowerShell 56 | if: runner.os == 'Windows' 57 | run: | 58 | Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force 59 | Invoke-Build SetupPowerShell -PowerShellVersion $env:POWERSHELL_VERSION 60 | 61 | - name: Output PowerShell version 62 | shell: pwsh 63 | run: | 64 | $PSVersionTable.PSVersion 65 | 66 | - name: Install Invoke-Build 67 | shell: pwsh 68 | run: | 69 | Install-Module -Name InvokeBuild -RequiredVersion $env:INVOKE_BUILD_VERSION -Force 70 | 71 | - name: Run Pester Tests 72 | shell: pwsh 73 | run: | 74 | Invoke-Build Test 75 | 76 | - name: Build Packages 77 | shell: pwsh 78 | run: | 79 | Invoke-Build Pack -------------------------------------------------------------------------------- /.github/workflows/label-issue-project.yml: -------------------------------------------------------------------------------- 1 | name: Add labeled issues to project 2 | 3 | on: 4 | issues: 5 | types: 6 | - labeled 7 | 8 | jobs: 9 | add-to-project: 10 | name: Add issue to project 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/add-to-project@v1.0.2 14 | with: 15 | project-url: https://github.com/users/Badgerati/projects/2 16 | github-token: ${{ secrets.PROJECT_TOKEN }} 17 | labeled: 'planned :calendar:, roadmap :rocket:, backlog :scroll:, draft :pencil2:, idea :bulb:' 18 | label-operator: OR -------------------------------------------------------------------------------- /.github/workflows/open-issue-project.yml: -------------------------------------------------------------------------------- 1 | name: Add opened issues to project 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | 8 | jobs: 9 | add-to-project: 10 | name: Add issue to project 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/add-to-project@v1.0.2 14 | with: 15 | project-url: https://github.com/users/Badgerati/projects/2 16 | github-token: ${{ secrets.PROJECT_TOKEN }} 17 | labeled: 'bug :bug:, documentation :book:, packaging :package:, enhancement :arrow_up:, feature :sunny:' 18 | label-operator: OR -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/powershell:7.5-ubuntu-24.04 2 | LABEL maintainer="Matthew Kelly (Badgerati)" 3 | RUN mkdir -p /usr/local/share/powershell/Modules/Pode 4 | COPY ./pkg/ /usr/local/share/powershell/Modules/Pode -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) [2017-2025] [Matthew Kelly (Badgerati)] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /PSScriptAnalyzerSettings.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | Severity = @('Error', 'Warning', 'Information') 3 | IncludeDefaultRules = $true 4 | 5 | CustomRulePath = @( 6 | './analyzers/AvoidNewObjectRule.psm1' 7 | ) 8 | 9 | Rules = @{ 10 | PSReviewUnusedParameter = @{ 11 | CommandsToTraverse = @( 12 | 'Where-Object', 13 | 'Remove-PodeRoute' 14 | ) 15 | } 16 | AvoidNewObjectRule = @{ 17 | Severity = 'Warning' 18 | } 19 | } 20 | 21 | ExcludeRules = @( 22 | 'PSAvoidUsingPlainTextForPassword', 23 | 'PSUseShouldProcessForStateChangingFunctions', 24 | 'PSAvoidUsingUsernameAndPasswordParams', 25 | 'PSUseProcessBlockForPipelineCommand', 26 | 'PSAvoidUsingConvertToSecureStringWithPlainText', 27 | 'PSReviewUnusedParameter', 28 | 'PSAvoidAssignmentToAutomaticVariable', 29 | 'PSUseBOMForUnicodeEncodedFile', 30 | 'PSAvoidTrailingWhitespace' 31 | ) 32 | 33 | } -------------------------------------------------------------------------------- /Pode.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{41F81369-8680-4BC5-BA16-C7891D245717}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pode", "src\Listener\Pode.csproj", "{772D5C9F-1B25-46A7-8977-412A5F7F77D1}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {772D5C9F-1B25-46A7-8977-412A5F7F77D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {772D5C9F-1B25-46A7-8977-412A5F7F77D1}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {772D5C9F-1B25-46A7-8977-412A5F7F77D1}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {772D5C9F-1B25-46A7-8977-412A5F7F77D1}.Release|Any CPU.Build.0 = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | GlobalSection(NestedProjects) = preSolution 25 | {772D5C9F-1B25-46A7-8977-412A5F7F77D1} = {41F81369-8680-4BC5-BA16-C7891D245717} 26 | EndGlobalSection 27 | GlobalSection(ExtensibilityGlobals) = postSolution 28 | SolutionGuid = {F24001DC-2986-4305-B1B5-8E73BCDF1A77} 29 | EndGlobalSection 30 | EndGlobal 31 | -------------------------------------------------------------------------------- /alpine.dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/powershell:7.5-alpine-3.20 2 | LABEL maintainer="Matthew Kelly (Badgerati)" 3 | RUN mkdir -p /usr/local/share/powershell/Modules/Pode 4 | COPY ./pkg/ /usr/local/share/powershell/Modules/Pode -------------------------------------------------------------------------------- /analyzers/AvoidNewObjectRule.psm1: -------------------------------------------------------------------------------- 1 | function Measure-AvoidNewObjectRule { 2 | [CmdletBinding()] 3 | [OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]])] 4 | param( 5 | [Parameter(Mandatory = $true)] 6 | [ValidateNotNullOrEmpty()] 7 | [System.Management.Automation.Language.ScriptBlockAst] 8 | $ScriptBlockAst 9 | ) 10 | 11 | # Initialize an empty array to collect diagnostic records 12 | $diagnostics = @() 13 | 14 | try { 15 | # Traverse the AST to find all instances of New-Object cmdlet 16 | $ScriptBlockAst.FindAll({ 17 | param($Ast) 18 | $Ast -is [System.Management.Automation.Language.CommandAst] -and 19 | $Ast.CommandElements[0].Extent.Text -eq 'New-Object' 20 | }, $true) | ForEach-Object { 21 | $diagnostics += [PSCustomObject]@{ 22 | Message = "Avoid using 'New-Object' and use '::new()' instead." 23 | Extent = $_.Extent 24 | RuleName = 'AvoidNewObjectRule' 25 | Severity = 'Warning' 26 | ScriptName = $FileName 27 | } 28 | } 29 | 30 | # Return the diagnostic records 31 | return $diagnostics 32 | } 33 | catch { 34 | $PSCmdlet.ThrowTerminatingError($PSItem) 35 | } 36 | } 37 | 38 | Export-ModuleMember -Function Measure-AvoidNewObjectRule -------------------------------------------------------------------------------- /arm32.dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/powershell:7.5-ubuntu-22.04-arm32 2 | LABEL maintainer="Matthew Kelly (Badgerati)" 3 | RUN mkdir -p /usr/local/share/powershell/Modules/Pode 4 | COPY ./pkg/ /usr/local/share/powershell/Modules/Pode -------------------------------------------------------------------------------- /docs/Getting-Started/Licenses.md: -------------------------------------------------------------------------------- 1 | # Licenses 2 | 3 | Pode's core license is MIT, which can be [found here](https://github.com/Badgerati/Pode/blob/develop/LICENSE.txt). 4 | 5 | Pode also has several dependencies, some of which are optional and some of which are mandatory - depending on the feature you're using within Pode. For example, if you're using OpenAPI and render the documentation via Swagger or ReDoc then these are mandatory dependencies. However, if you're returning YAML data from a Route then you can either use Pode's inbuilt YAML converter, or you can optionally use [PSYAML](https://github.com/Phil-Factor/PSYaml) or [powershell-yaml](https://github.com/cloudbase/powershell-yaml) and Pode will detect these are installed. 6 | 7 | The licenses for Pode dependencies, whether they're optional or mandatory, can be [found here](https://github.com/Badgerati/Pode/tree/develop/licenses), and they are also released alongside Pode's module within a `/licenses` folder. -------------------------------------------------------------------------------- /docs/Listeners/Kestrel.md: -------------------------------------------------------------------------------- 1 | # Kestrel 2 | 3 | Starting from Pode 2.0, there is now support for Kestrel as a custom listener for Pode. This Kestrel listener can be found in the [Pode.Kestrel](https://github.com/Badgerati/Pode.Kestrel) module. The Kestrel listener, at present, only supports HTTP/HTTPS. 4 | 5 | !!! important 6 | The Kestrel listener only works in PowerShell 6.0+ 7 | 8 | ## Usage 9 | 10 | To begin using the Kestrel listener, you'll first need to install the module: 11 | 12 | ```powershell 13 | Install-Module -Name Pode.Kestrel 14 | ``` 15 | 16 | then, in your main server script, you'll need to import the module and set the `-ListenerType`: 17 | 18 | ```powershell 19 | Import-Module -Name Pode.Kestrel 20 | 21 | Start-PodeServer -ListenerType Kestrel { 22 | # endpoints, routes, etc 23 | } 24 | ``` 25 | 26 | and that's it! 27 | -------------------------------------------------------------------------------- /docs/Listeners/Pode.md: -------------------------------------------------------------------------------- 1 | # Pode 2 | 3 | Pode has an inbuilt .NET cross-platform socket listener that is used by default. You don't need to do anything special outside of using Pode normally. Pode's default listener supports HTTP/HTTPS, WS/WSS, SMTP and TCP. 4 | -------------------------------------------------------------------------------- /docs/Tutorials/Compression/Responses.md: -------------------------------------------------------------------------------- 1 | # Responses 2 | 3 | Pode has support for sending back compressed Responses, if enabled, and if a client sends an appropriate `Accept-Encoding` header. 4 | 5 | The followings compression methods are supported: 6 | 7 | * gzip 8 | * deflate 9 | 10 | When enabled, Pode will compress the response's bytes prior to sending the response; the `Content-Encoding` header will also be sent appropriately on the response. 11 | 12 | ## Enable 13 | 14 | By default response compression is disabled in Pode. To enable compression you can set the following value in your server's `server.psd1` [configuration](../../Configuration) file: 15 | 16 | ```powershell 17 | @{ 18 | Web = @{ 19 | Compression = @{ 20 | Enable = $true 21 | } 22 | } 23 | } 24 | ``` 25 | 26 | Once enabled, compression will be used if a valid `Accept-Encoding` header is sent in the request. 27 | 28 | ## Headers 29 | 30 | For your Pode server to compress the response, the client must send an `Accept-Encoding` header for with `gzip` or `deflate`: 31 | 32 | ```text 33 | Accept-Encoding: gzip 34 | Accept-Encoding: deflate 35 | Accept-Encoding: identity 36 | Accept-Encoding: * 37 | ``` 38 | 39 | Or any valid combination: 40 | 41 | ```text 42 | Accept-Encoding: gzip,deflate 43 | ``` 44 | 45 | If multiple encodings are sent, then Pode will use the first supported value. There is also support for quality values as well, so you can weight encodings or fully disable non-compression (if no q-value is on an encoding it is assumed to be 1) 46 | 47 | ```text 48 | Accept-Encoding: gzip,deflate,identity;q=0 49 | ``` 50 | 51 | In a scenario where no encodings are supported, and identity (no-compression) is disabled, then Pode will respond with a 406. 52 | 53 | If an encoding is used to compress the response, then Pode will set the `Content-Encoding` on the response. 54 | -------------------------------------------------------------------------------- /docs/Tutorials/Endware.md: -------------------------------------------------------------------------------- 1 | # Endware 2 | 3 | Endware in Pode is like [Middleware](../Middleware/Overview), but it runs after a Route. Endware will also run regardless the state of any prior Middleware or Route logic; if a either throws an error (ie: HTTP 500 or 404), then the Endware will still run. Also, if you have multiple Endwares configured, then each will be invoked inturn, but independently of each other - should one of the Endwares fail, the others will still be invoked. 4 | 5 | Pode has some inbuilt Endware, namely: 6 | 7 | * Any configured [Logging](../Logging/Overview) is invoked as Endware. 8 | * If [Sessions](../Middleware/Types/Sessions) are enabled, then session data is persisted as Endware. 9 | 10 | ## Creating Endware 11 | 12 | To add a new Endware script you can use [`Add-PodeEndware`](../../Functions/Utilities/Add-PodeEndware), and supply a `-ScriptBlock`: 13 | 14 | ```powershell 15 | Add-PodeEndware -ScriptBlock { 16 | # logic 17 | } 18 | ``` 19 | 20 | The scriptblock for Endware also has access to the [WebEvent](../WebEvent) variable. 21 | -------------------------------------------------------------------------------- /docs/Tutorials/Headers.md: -------------------------------------------------------------------------------- 1 | # Headers 2 | 3 | In Pode you can add/retrieve headers for the Request/Response of the current web event. Using the header functions has to be done within the context of a web event, such as in Routes/Middleware/Authentication/Logging/Endware. 4 | 5 | ## Setting Headers 6 | 7 | There are 2 ways of setting headers on a response: [`Add-PodeHeader`](../../Functions/Headers/Add-PodeHeader) and [`Set-PodeHeader`](../../Functions/Headers/Set-PodeHeader). 8 | 9 | [`Add-PodeHeader`](../../Functions/Headers/Add-PodeHeader) will append multiple values for one header on the response - such as the `Set-Cookie` header of which there can be multiple of on a response. The following will add 2 of the same header on the response: 10 | 11 | ```powershell 12 | Add-PodeMiddleware -Name Example -ScriptBlock { 13 | Add-PodeHeader -Name Name1 -Value Value1 14 | Add-PodeHeader -Name Name1 -Value Value2 15 | } 16 | ``` 17 | 18 | [`Set-PodeHeader`](../../Functions/Headers/Set-PodeHeader) will clear all current values for a header on the response, and reset it to one value. The following will add 2 of the same header to the response, but then override that to 1 header: 19 | 20 | ```powershell 21 | Add-PodeMiddleware -Name Example -ScriptBlock { 22 | Add-PodeHeader -Name Name1 -Value Value1 23 | Add-PodeHeader -Name Name1 -Value Value2 24 | 25 | Set-PodeHeader -Name Name1 -Value Value3 26 | } 27 | ``` 28 | 29 | ## Getting Headers 30 | 31 | To retrieve the value of a header on the request, you can use [`Get-PodeHeader`](../../Functions/Headers/Get-PodeHeader): 32 | 33 | ```powershell 34 | Add-PodeRoute -Method Get -Path '/' -ScriptBlock { 35 | Get-PodeHeader -Name 'X-Header-Name' 36 | } 37 | ``` 38 | 39 | ## Signing Headers 40 | 41 | You can sign a header by supplying a `-Secret` to any of the header functions; supplying it to [`Get-PodeHeader`](../../Functions/Headers/Get-PodeHeader) will attempt to unsign the header for the raw value. 42 | -------------------------------------------------------------------------------- /docs/Tutorials/Logging/Methods/Custom.md: -------------------------------------------------------------------------------- 1 | # Custom 2 | 3 | Sometimes you don't want to log to a file, or the terminal; instead you want to log to something better, like LogStash, Splunk, Athena, or any other central logging platform. Although Pode doesn't have these inbuilt (yet!) it is possible to create a custom logging method, where you define a ScriptBlock with logic to send logs to these platforms. 4 | 5 | These custom method can be used for any log type - Requests, Error, or Custom. 6 | 7 | The ScriptBlock you create will be supplied two arguments: 8 | 9 | 1. The item to be logged. This could be a string (from Requests/Errors), or any custom type. 10 | 2. The options you supplied on [`New-PodeLoggingMethod`](../../../../Functions/Logging/New-PodeLoggingMethod). 11 | 12 | ## Examples 13 | 14 | ### Send to S3 Bucket 15 | 16 | This example will take whatever item is supplied to it, convert it to a string, and then send it off to some S3 bucket in AWS. In this case, it will be logging Requests: 17 | 18 | ```powershell 19 | $s3_options = @{ 20 | AccessKey = $AccessKey 21 | SecretKey = $SecretKey 22 | } 23 | 24 | $s3_logging = New-PodeLoggingType -Custom -ArgumentList $s3_options -ScriptBlock { 25 | param($item, $s3_opts) 26 | 27 | Write-S3Object ` 28 | -BucketName '' ` 29 | -Content $item.ToString() ` 30 | -AccessKey $s3_opts.AccessKey ` 31 | -SecretKey $s3_opts.SecretKey 32 | } 33 | 34 | $s3_logging | Enable-PodeRequestLogging 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/Tutorials/Logging/Methods/EventViewer.md: -------------------------------------------------------------------------------- 1 | # Event Viewer 2 | 3 | You can log items to the Windows Event Viewer, using Pode's unbuilt Event Viewer logging logic. You can log anything, but it's best to use this in conjunction with [`Enable-PodeErrorLogging`](../../../../Functions/Logging/Enable-PodeErrorLogging) and [`Write-PodeErrorLog`](../../../../Functions/Logging/Write-PodeErrorLog). 4 | 5 | Errors will be logged using an appropriate error level, but other log items will be logged as Informational by default. 6 | 7 | By default, Pode will log to the Application log with a source of Pode, and an Event ID of 0. 8 | 9 | ## Usage 10 | 11 | When using this log method, Pode will first check if the source exists, and will then attempt to create it. To do this, you will need to be running Pode as an administrator. 12 | 13 | If however you're running Pode locally, or in a situation where you can't run Pode as a full admin - like in IIS - then you will first have to create the source yourself manually. Assuming a source of `Pode` and in the `Application` log, you can use the following: 14 | 15 | ```powershell 16 | [System.Diagnostics.EventLog]::CreateEventSource('Pode', 'Application') 17 | ``` 18 | 19 | Once the source is created, Pode can log to the Event Viewer without being an admin! 20 | 21 | To enable and log errors to the Event Viewer, the following will work: 22 | 23 | ```powershell 24 | New-PodeLoggingMethod -EventViewer | Enable-PodeErrorLogging 25 | ``` 26 | 27 | This will log to the `Application` log using `Pode` as the source. 28 | 29 | ## Event Log 30 | 31 | To log to a different event log, other than Application, you can specify the log via `-EventLogName`: 32 | 33 | ```powershell 34 | New-PodeLoggingMethod -EventViewer -EventLogName SomeLogName | Enable-PodeErrorLogging 35 | ``` 36 | 37 | ## Event Source 38 | 39 | To log using a different source, other than Pode, you can specify the source via `-Source`: 40 | 41 | ```powershell 42 | New-PodeLoggingMethod -EventViewer -Source WebsiteName | Enable-PodeErrorLogging 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/Tutorials/Logging/Methods/File.md: -------------------------------------------------------------------------------- 1 | # File 2 | 3 | You can log items to a file using Pode's inbuilt file logging logic. The inbuilt logic allows you to define a maximum number of days to keep files, as well as a maximum file size. The logic will convert any item to a string, and then write it to file. 4 | 5 | By default, Pode will create all log files in a `./logs` directory at the root of your server. Each log file will be stored by day, eg: `_2019-08-02_001.log`. The last `001` number specifies the log number for that day - if files are be limited by size. 6 | 7 | ## Examples 8 | 9 | ### Basic 10 | 11 | The following example will setup the file logging method for logging Requests: 12 | 13 | ```powershell 14 | New-PodeLoggingMethod -File -Name 'requests' | Enable-PodeRequestLogging 15 | ``` 16 | 17 | ### Maximum Days 18 | 19 | The following example will configure file logging to only keep a maximum number of days of logs. Ie, if you set `-MaxDays` to 4, then Pode will only store the last 4 days worth of logs. 20 | 21 | ```powershell 22 | New-PodeLoggingMethod -File -Name 'requests' -MaxDays 4 | Enable-PodeRequestLogging 23 | ``` 24 | 25 | ### Maximum Size 26 | 27 | The following example will configure file logging to keep logging to a file until it reaches a maximum size. Once the size is reach, Pode will start logging to a new file; in this case, you'll see the last 3 digits increment: `001 > 002`. 28 | 29 | In this example, the maximum size it limited to 10MB: 30 | 31 | ```powershell 32 | New-PodeLoggingMethod -File -Name 'requests' -MaxSize 10MB | Enable-PodeRequestLogging 33 | ``` 34 | 35 | ### Custom Path 36 | 37 | By default Pode puts all logs in the `./logs` directory. You can use a custom path by using `-Path`: 38 | 39 | ```powershell 40 | New-PodeLoggingMethod -File -Name 'requests' -Path 'E:/logs' | Enable-PodeRequestLogging 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/Tutorials/Logging/Methods/Terminal.md: -------------------------------------------------------------------------------- 1 | # Terminal 2 | 3 | You can log items to the terminal using Pode's inbuilt terminal logic. The inbuilt logic will convert any item to a string, and output it to the terminal. 4 | 5 | ## Examples 6 | 7 | ### Basic 8 | 9 | The following example will setup the terminal logging method for logging Requests: 10 | 11 | ```powershell 12 | New-PodeLoggingMethod -Terminal | Enable-PodeRequestLogging 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/Tutorials/Logging/Types/Custom.md: -------------------------------------------------------------------------------- 1 | # Custom 2 | 3 | You can define Custom logging types in Pode by using the [`Add-PodeLogger`](../../../../Functions/Logging/Add-PodeLogger) function. Much like Requests and Errors, this function too accepts any logging method from [`New-PodeLoggingMethod`](../../../../Functions/Logging/New-PodeLoggingMethod). 4 | 5 | When adding a Custom logger, you supply a `-ScriptBlock` plus an array of optional arguments in `-ArgumentList`. The function also requires a unique `-Name`, so that it can be referenced from the [`Write-PodeLog`](../../../../Functions/Logging/Write-PodeLog) function. 6 | 7 | The ScriptBlock will be supplied with the following arguments: 8 | 9 | 1. The item to log that was supplied via [`Write-PodeLog`](../../../../Functions/Logging/Write-PodeLog). 10 | 2. The arguments that were supplied from [`Add-PodeLogger`](../../../../Functions/Logging/Add-PodeLogger)'s `-ArgumentList` parameter. 11 | 12 | ## Examples 13 | 14 | ### Write to File 15 | 16 | This example will create a Custom logging method that will take some custom hashtable, transform it into a string, and then return the string. That string will then be passed to the inbuilt File logging method: 17 | 18 | ```powershell 19 | New-PodeLoggingMethod -File -Name 'Custom' | Add-PodeLogger -Name 'Main' -ScriptBlock { 20 | param($item, $arg1, $arg2) 21 | return "$($item.Key1), $($item.Key2), $($item.Key3)" 22 | } -ArgumentList $arg1, $arg2 23 | 24 | Write-PodeLog -Name 'Main' -InputObject @{ 25 | Key1 = 'Value1' 26 | Key2 = 'Value2' 27 | Key3 = 'Value3' 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/Tutorials/Metrics/Uptime.md: -------------------------------------------------------------------------------- 1 | # Uptime and Restarts 2 | 3 | Pode internally keeps track of the uptime of the server, as well as the number of times the server has been restarted. 4 | 5 | ## Uptime 6 | 7 | There are two uptime stats in Pode, and both will be returned to you in milliseconds: 8 | 9 | 1. The uptime for the server since the last restart 10 | 2. The total uptime of the server regardless of restarts 11 | 12 | To get either, you can use the [`Get-PodeServerUptime`](../../../Functions/Metrics/Get-PodeServerUptime) function. For the total uptime, just supply the `-Total` switch: 13 | 14 | ```powershell 15 | $current = Get-PodeServerUptime 16 | $total = Get-PodeServerUptime -Total 17 | ``` 18 | 19 | ## Restart Count 20 | 21 | Pode keeps track of how many time your server restarts, you can get this count by using the [`Get-PodeServerRestartCount`](../../../Functions/Metrics/Get-PodeServerRestartCount) function: 22 | 23 | ```powershell 24 | $count = Get-PodeServerRestartCount 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/Tutorials/Middleware/Types/BodyParsing.md: -------------------------------------------------------------------------------- 1 | # Body Parsing 2 | 3 | Pode has inbuilt body/payload parsing on Requests, which by default can parse the following content types: 4 | 5 | * `*/json` 6 | * `*/xml` 7 | * `*/csv` 8 | * `*/x-www-form-urlencoded` 9 | * `multipart/form-data` 10 | 11 | This is useful however, there can be times when you might want to use a different JSON parsing library - or parse a completely different content type altogether! This is possible using the [`Add-PodeBodyParser`](../../../../Functions/Middleware/Add-PodeBodyParser) function. 12 | 13 | ## Adding a Parser 14 | 15 | You can use the [`Add-PodeBodyParser`](../../../../Functions/Middleware/Add-PodeBodyParser) function to define a scriptblock that can parse the Request body for a specific content type. Any set parsers have a higher priority than the inbuilt ones, meaning if you define a parser for `application/json` then this will be used instead of the inbuilt one. 16 | 17 | The scriptblock you supply will be supplied a single argument, which will be the Body of the Request. 18 | 19 | For example, to set your own JSON parser that will simply return the body unmodified you could do the following: 20 | 21 | ```powershell 22 | Add-PodeBodyParser -ContentType 'application/json' -ScriptBlock { 23 | param($body) 24 | return $body 25 | } 26 | ``` 27 | 28 | This can then be accessed the normal way within a Route from the `.Data` property on the accessible `$WebEvent`: 29 | 30 | ```powershell 31 | Add-PodeRoute -Method Post -Path '/' -ScriptBlock { 32 | # if using the above parser, .Data here will just be a plain string 33 | Write-PodeTextResponse -Value $WebEvent.Data 34 | } 35 | ``` 36 | 37 | This is great if you want to be able to parse other content types like YAML, HCL, or many others! 38 | 39 | ## Removing a Parser 40 | 41 | To remove a defined parser you can use the [`Remove-PodeBodyParser`](../../../../Functions/Middleware/Remove-PodeBodyParser) function: 42 | 43 | ```powershell 44 | Remove-PodeBodyParser -ContentType 'application/json' 45 | ``` 46 | 47 | !!! note 48 | This will only remove defined custom parsers, and will not affect the inbuilt parsers. 49 | -------------------------------------------------------------------------------- /docs/Tutorials/Misc/Outputs.md: -------------------------------------------------------------------------------- 1 | # Outputs 2 | 3 | ## Variables 4 | 5 | You can tell Pode to create variables with values when the server stops by using [`Out-PodeVariable`](../../../Functions/Utilities/Out-PodeVariable), for example: 6 | 7 | ```powershell 8 | Out-PodeVariable -Name VariableName -Value 'Some_Variable_Value' 9 | ``` 10 | 11 | The `-Value` of the variable can be any object type, and when the server is stopped these variables will be created and available in the command line. 12 | 13 | If you were to run the able example, this means that when the server is stopped, you will have access to a `$VariableName` variable on the CLI. 14 | -------------------------------------------------------------------------------- /docs/Tutorials/Misc/ServerRoot.md: -------------------------------------------------------------------------------- 1 | # Server Root 2 | 3 | The root path for your server, by default, is always defined by `$MyInvocation.PSScriptRoot`. 4 | 5 | Normally this is enough, and you'll likely never need to change it however, if you should want to change your server's root path, you can alter it in the following ways. 6 | 7 | !!! note 8 | The path you supply in both cases can be literal, or relative to `$MyInvocation.PSScriptRoot`. If you supply a literal path it will be used instead of the invocation path. 9 | 10 | ## Code 11 | 12 | The main way to alter the root path of you server is to use the `-RootPath` parameter on the `server` function: 13 | 14 | ```powershell 15 | Start-PodeServer -RootPath '../server' { 16 | # logic 17 | } 18 | ``` 19 | 20 | With this, everything from your `server.psd1`, `/views`, `/public`, etc will need to be within the `../server` directory. 21 | 22 | ## Configuration 23 | 24 | The other way to alter the root path is via the `server.psd1` file: 25 | 26 | ```powershell 27 | @{ 28 | Server = @{ 29 | Root = "../server" 30 | } 31 | } 32 | ``` 33 | 34 | In this case, the `server.psd1` file will need to be located at `$MyInvocation.PSScriptRoot`. Everything else will need to be located in `../server`. 35 | -------------------------------------------------------------------------------- /docs/Tutorials/OpenAPI/4DocumentationTools.md: -------------------------------------------------------------------------------- 1 | 2 | # Documentation Tools 3 | 4 | If you're not using a custom OpenAPI viewer, then you can use one or more of the inbuilt which Pode supports: ones with Pode: 5 | 6 | * Swagger 7 | * ReDoc 8 | * RapiDoc 9 | * StopLight 10 | * Explorer 11 | * RapiPdf 12 | 13 | For each you can customise the Route path to access the page on, but by default Swagger is at `/swagger`, ReDoc is at `/redoc`, etc. If you've written your own custom OpenAPI definition then you can also set a custom Route path to fetch the definition on. 14 | 15 | To enable a viewer you can use the [`Enable-PodeOAViewer`](../../../Functions/OpenApi/Enable-PodeOAViewer) function: 16 | 17 | ```powershell 18 | # for swagger at "/docs/swagger" 19 | Enable-PodeOAViewer -Type Swagger -Path '/docs/swagger' -DarkMode 20 | 21 | # and ReDoc at the default "/redoc" 22 | Enable-PodeOAViewer -Type ReDoc -Path '/docs/redoc' 23 | 24 | # and RapiDoc at "/docs/rapidoc" 25 | Enable-PodeOAViewer -Type RapiDoc -Path '/docs/rapidoc' 26 | 27 | # and StopLight at "/docs/stoplight" 28 | Enable-PodeOAViewer -Type StopLight -Path '/docs/stoplight' 29 | 30 | # and Explorer at "/docs/explorer" 31 | Enable-PodeOAViewer -Type Explorer -Path '/docs/explorer' 32 | 33 | # and RapiPdf at "/docs/rapipdf" 34 | Enable-PodeOAViewer -Type RapiPdf -Path '/docs/rapipdf' 35 | 36 | # plus a bookmark page with the link to all documentation 37 | Enable-PodeOAViewer -Bookmarks -Path '/docs' 38 | 39 | # there is also an OpenAPI editor (only for v3.0.x) 40 | Enable-PodeOAViewer -Editor -Path '/docs/swagger-editor' 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/Tutorials/RequestLimits.md: -------------------------------------------------------------------------------- 1 | # Request Limits 2 | 3 | When making requests to the server, there are some limits that will cause the request to fail. These limits mostly cover web requests, and can be altered in the [`server.psd1`](../Configuration) configuration file. 4 | 5 | ## Timeout 6 | 7 | There is a default request timeout of 30 seconds, exceeding this will force the connection to close. In the case of a web request, a 408 HTTP status code will be returned. 8 | 9 | You can edit the timeout in the `server.psd1` file: 10 | 11 | ```powershell 12 | @{ 13 | Server = @{ 14 | Request = @{ 15 | Timeout = 30 16 | } 17 | } 18 | } 19 | ``` 20 | 21 | The value supplied should be in seconds. 22 | 23 | ## Body Size 24 | 25 | On web requests there is a default max request body size of 100MB, exceeding this will cause a 413 HTTP status code to be returned. 26 | 27 | You can edit the max body size in the `server.psd1` file: 28 | 29 | ```powershell 30 | @{ 31 | Server = @{ 32 | Request = @{ 33 | BodySize = 100MB 34 | } 35 | } 36 | } 37 | ``` 38 | 39 | The value supplied should be in bytes, or using the PowerShell notation `100MB`. 40 | -------------------------------------------------------------------------------- /docs/Tutorials/Routes/Utilities/Redirecting.md: -------------------------------------------------------------------------------- 1 | # Redirecting 2 | 3 | Sometimes you just want a Route to redirect the user else where, be it to another URL or to the same Route just a different port/protocol. 4 | 5 | ## Usage 6 | 7 | When in a Route, to inform the client to redirect to a different endpoint you can use the [`Move-PodeResponseUrl`](../../../../Functions/Responses/Move-PodeResponseUrl) function. 8 | 9 | Supplying `-Url` will redirect the user to that URL, or you can supply a relative path o the server for the user to be redirected to. The `-Port` and `-Protocol` can be used separately or together, but not with `-Url`. Using `-Port`/`-Protocol` will use the URI of the current web request to generate the redirect URL. 10 | 11 | By default the redirecting will return a `302` response, but supplying `-Moved` will return a `301` response instead. 12 | 13 | The following example will redirect the user to Google: 14 | 15 | ```powershell 16 | Start-PodeServer { 17 | Add-PodeEndpoint -Address * -Port 8080 -Protocol Http 18 | 19 | Add-PodeRoute -Method Get -Path '/redirect' -ScriptBlock { 20 | Move-PodeResponseUrl -Url 'https://google.com' 21 | } 22 | } 23 | ``` 24 | 25 | The below example will redirect the user to the same host/server, but with a different protocol and port: 26 | 27 | ```powershell 28 | Start-PodeServer { 29 | Add-PodeEndpoint -Address * -Port 8080 -Protocol Http 30 | Add-PodeEndpoint -Address * -Port 8086 -Protocol HTTPS 31 | 32 | Add-PodeRoute -Method Get -Path '/redirect' -ScriptBlock { 33 | Move-PodeResponseUrl -Port 8086 -Protocol Https 34 | } 35 | } 36 | ``` 37 | 38 | This final example will redirect every HTTP request, on every action and route, to HTTPS: 39 | 40 | ```powershell 41 | Start-PodeServer { 42 | Add-PodeEndpoint -Address * -Port 8080 -Protocol Http -Name EndpointHttp 43 | Add-PodeEndpoint -Address * -Port 8443 -Protocol Https -Name EndpointHttps 44 | 45 | Add-PodeRoute -Method * -Path * -EndpointName EndpointHttp -ScriptBlock { 46 | Move-PodeResponseUrl -Port 8443 -Protocol Https 47 | } 48 | } 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/Tutorials/Server Operations/Restarting/Overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | There are 4 ways to restart a running Pode server: 4 | 5 | 1. **Ctrl+R**: If you press `Ctrl+R` on a running server, it will trigger a restart to take place. 6 | 1a. On Unix you can use `Shift+R`. 7 | 2. [**File Monitoring**](../Types/FileMonitoring): This will watch for file changes, and if enabled will trigger the server to restart. 8 | 3. [**Auto-Restarting**](../Types/AutoRestarting): Defined within the `server.psd1` configuration file, you can set schedules for the server to automatically restart. 9 | 4. [`Restart-PodeServer`](../../../Functions/Core/Restart-PodeServer): This function lets you manually restart Pode from within the server. 10 | 11 | When the server restarts, it will re-invoke the `-ScriptBlock` supplied to the [`Start-PodeServer`](../../../Functions/Core/Start-PodeServer) function. This means the best approach to reload new modules/scripts it to dot-source/[`Use-PodeScript`](../../../Functions/Utilities/Use-PodeScript) your scripts into your server, as any changes to the main `scriptblock` will **not** take place. 12 | -------------------------------------------------------------------------------- /docs/Tutorials/Threading/ServerThreads.md: -------------------------------------------------------------------------------- 1 | # Server Threads 2 | 3 | By default Pode deals with incoming requests synchronously in a single thread (or runspace). You can increase the number of threads/runspaces that Pode uses to handle requests by using the `-Threads` parameter on [`Start-PodeServer`](../../../Functions/Core/Start-PodeServer): 4 | 5 | ```powershell 6 | Start-PodeServer -Threads 2 { 7 | # logic 8 | } 9 | ``` 10 | 11 | The number of threads supplied only applies to Web, SMTP, and TCP servers. If `-Threads` is not supplied, or is <=0 then the number of threads is forced to the default of 1. 12 | -------------------------------------------------------------------------------- /docs/images/GXAjs98JsZ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/docs/images/GXAjs98JsZ.png -------------------------------------------------------------------------------- /docs/images/companies/coop-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/docs/images/companies/coop-logo.png -------------------------------------------------------------------------------- /docs/images/event-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/docs/images/event-flow.png -------------------------------------------------------------------------------- /docs/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/docs/images/favicon.ico -------------------------------------------------------------------------------- /docs/images/icon-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/docs/images/icon-transparent.png -------------------------------------------------------------------------------- /docs/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/docs/images/icon.png -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | mkdocs-material -------------------------------------------------------------------------------- /examples/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM badgerati/pode:test 2 | COPY . /usr/src/app/ 3 | EXPOSE 8081 4 | CMD [ "pwsh", "-c", "cd /usr/src/app; ./Web-PagesDocker.ps1" ] 5 | -------------------------------------------------------------------------------- /examples/Dot-SourceScript.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a Pode server and run a script from an external file. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server, enables terminal logging for errors, and uses an external 7 | script for additional logic. It imports the Pode module from the source path if available, 8 | otherwise from the installed modules. 9 | 10 | .EXAMPLE 11 | To run the sample: ./Dot-SourceScript.ps1 12 | 13 | .LINK 14 | https://github.com/Badgerati/Pode/blob/develop/examples/Dot-SourceScript.ps1 15 | 16 | .NOTES 17 | Author: Pode Team 18 | License: MIT License 19 | #> 20 | 21 | try { 22 | # Determine the script path and Pode module path 23 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 24 | $podePath = Split-Path -Parent -Path $ScriptPath 25 | 26 | # Import the Pode module from the source path if it exists, otherwise from installed modules 27 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 28 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 29 | } 30 | else { 31 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 32 | } 33 | } 34 | catch { throw } 35 | 36 | # or just: 37 | # Import-Module Pode 38 | 39 | # runs the logic once, then exits 40 | Start-PodeServer { 41 | 42 | New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging 43 | Use-PodeScript -Path './modules/Script1.ps1' 44 | 45 | } 46 | -------------------------------------------------------------------------------- /examples/External-Funcs.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a Pode server and use an external module function. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server listening on port 8081, imports an external module containing functions, 7 | and includes a route that uses a function from the external module to generate a response. 8 | 9 | .EXAMPLE 10 | To run the sample: ./External-Funcs.ps1 11 | 12 | Invoke-RestMethod -Uri http://localhost:8081 -Method Get 13 | 14 | .LINK 15 | https://github.com/Badgerati/Pode/blob/develop/examples/External-Funcs.ps1 16 | 17 | .NOTES 18 | Author: Pode Team 19 | License: MIT License 20 | #> 21 | 22 | try { 23 | # Determine the script path and Pode module path 24 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 25 | $podePath = Split-Path -Parent -Path $ScriptPath 26 | 27 | # Import the Pode module from the source path if it exists, otherwise from installed modules 28 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 29 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 30 | } else { 31 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 32 | } 33 | } catch { throw } 34 | 35 | # or just: 36 | # Import-Module Pode 37 | 38 | # include the external function module 39 | Import-PodeModule -Path './modules/External-Funcs.psm1' 40 | 41 | # create a server, and start listening on port 8081 42 | Start-PodeServer { 43 | 44 | # listen on localhost:8085 45 | Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http 46 | 47 | # GET request for "localhost:8085/" 48 | Add-PodeRoute -Method Get -Path '/' -ScriptBlock { 49 | Write-PodeJsonResponse -Value @{ 'result' = (Get-Greeting) } 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /examples/File-Monitoring.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a Pode server with a view engine and file monitoring. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server listening on port 8081, uses Pode's view engine for rendering 7 | web pages, and configures the server to monitor file changes and restart automatically. 8 | 9 | .EXAMPLE 10 | To run the sample: ./File-Monitoring.ps1 11 | 12 | Invoke-RestMethod -Uri http://localhost:8081 -Method Get 13 | 14 | .LINK 15 | https://github.com/Badgerati/Pode/blob/develop/examples/File-Monitoring.ps1 16 | 17 | .NOTES 18 | Author: Pode Team 19 | License: MIT License 20 | #> 21 | 22 | try { 23 | # Determine the script path and Pode module path 24 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 25 | $podePath = Split-Path -Parent -Path $ScriptPath 26 | 27 | # Import the Pode module from the source path if it exists, otherwise from installed modules 28 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 29 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 30 | } 31 | else { 32 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 33 | } 34 | } 35 | catch { throw } 36 | 37 | # or just: 38 | # Import-Module Pode 39 | 40 | # create a server listening on port 8081, set to monitor file changes and restart the server 41 | Start-PodeServer { 42 | 43 | Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http 44 | Set-PodeViewEngine -Type Pode 45 | 46 | # GET request for web page on "localhost:8081/" 47 | Add-PodeRoute -Method Get -Path '/' -ScriptBlock { 48 | Write-PodeViewResponse -Path 'simple' -Data @{ 'numbers' = @(1, 2, 3); } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /examples/File-Watchers.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a Pode server with file watcher and logging. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server, enables terminal logging for errors, and adds a file watcher 7 | to monitor changes in PowerShell script files (*.ps1) within the script directory. The server 8 | logs file change events and outputs them to the terminal. 9 | 10 | .EXAMPLE 11 | To run the sample: ./File-Watchers.ps1 12 | 13 | .LINK 14 | https://github.com/Badgerati/Pode/blob/develop/examples/File-Watchers.ps1 15 | 16 | .NOTES 17 | Author: Pode Team 18 | License: MIT License 19 | #> 20 | 21 | try { 22 | # Determine the script path and Pode module path 23 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 24 | $podePath = Split-Path -Parent -Path $ScriptPath 25 | 26 | # Import the Pode module from the source path if it exists, otherwise from installed modules 27 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 28 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 29 | } 30 | else { 31 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 32 | } 33 | } 34 | catch { throw } 35 | 36 | # or just: 37 | # Import-Module Pode 38 | 39 | Start-PodeServer -Verbose { 40 | 41 | # enable logging 42 | New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging 43 | 44 | Add-PodeFileWatcher -Path $ScriptPath -Include '*.ps1' -ScriptBlock { 45 | "[$($FileEvent.Type)][$($FileEvent.Parameters['project'])]: $($FileEvent.FullPath)" | Out-Default 46 | } 47 | } -------------------------------------------------------------------------------- /examples/FileBrowser/public/ruler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/examples/FileBrowser/public/ruler.png -------------------------------------------------------------------------------- /examples/HelloWorld/HelloWorld.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | PowerShell script to set up a Pode server with a simple GET endpoint. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server that listens on port 8080. It includes a single route for GET requests 7 | to the root path ('/') that returns a simple text response. 8 | 9 | .EXAMPLE 10 | To run the sample: ./HelloWorld/HelloWorld.ps1 11 | 12 | # HTML responses 'Hello, world! 13 | Invoke-RestMethod -Uri http://localhost:8081/ -Method Get 14 | 15 | .LINK 16 | https://github.com/Badgerati/Pode/blob/develop/examples/HelloWorld/HelloWorld.ps1 17 | 18 | .NOTES 19 | Author: Pode Team 20 | License: MIT License 21 | #> 22 | try { 23 | # Get the path of the script being executed 24 | $ScriptPath = (Split-Path -Parent -Path (Split-Path -Parent -Path $MyInvocation.MyCommand.Path)) 25 | # Get the parent directory of the script's path 26 | $podePath = Split-Path -Parent -Path $ScriptPath 27 | 28 | # Check if the Pode module file exists in the specified path 29 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 30 | # If the Pode module file exists, import it 31 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 32 | } 33 | else { 34 | # If the Pode module file does not exist, import the Pode module from the system 35 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 36 | } 37 | } 38 | catch { 39 | # If there is any error during the module import, throw the error 40 | throw 41 | } 42 | 43 | # Alternatively, you can directly import the Pode module from the system 44 | # Import-Module Pode 45 | 46 | # Start the Pode server 47 | Start-PodeServer -ConfigFile '..\Server.psd1' { 48 | # Add an HTTP endpoint listening on localhost at port 8080 49 | Add-PodeEndpoint -Address localhost -Port 8080 -Protocol Http 50 | 51 | # Add a route for GET requests to the root path '/' 52 | Add-PodeRoute -Method Get -Path '/' -ScriptBlock { 53 | # Send a text response with 'Hello, world!' 54 | Write-PodeTextResponse -Value 'Hello, world!' 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /examples/Looping-Service.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a Pode server with interval-based service handlers. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server that runs with a specified interval, adding service handlers 7 | that execute at each interval. The handlers include logging messages to the terminal and using 8 | lock mechanisms. 9 | 10 | .EXAMPLE 11 | To run the sample: ./Looping-Service.ps1 12 | 13 | .LINK 14 | https://github.com/Badgerati/Pode/blob/develop/examples/Looping-Service.ps1 15 | 16 | .NOTES 17 | Author: Pode Team 18 | License: MIT License 19 | #> 20 | 21 | try { 22 | # Determine the script path and Pode module path 23 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 24 | $podePath = Split-Path -Parent -Path $ScriptPath 25 | 26 | # Import the Pode module from the source path if it exists, otherwise from installed modules 27 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 28 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 29 | } 30 | else { 31 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 32 | } 33 | } 34 | catch { throw } 35 | 36 | # or just: 37 | # Import-Module Pode 38 | 39 | # create a server, and start looping 40 | Start-PodeServer -Interval 3 { 41 | 42 | Add-PodeHandler -Type Service -Name 'Hello' -ScriptBlock { 43 | Write-PodeHost 'hello, world!' 44 | Lock-PodeObject -ScriptBlock { 45 | "Look I'm locked!" | Out-PodeHost 46 | } 47 | } 48 | 49 | Add-PodeHandler -Type Service -Name 'Bye' -ScriptBlock { 50 | Write-PodeHost 'goodbye!' 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /examples/OneOff-Script.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A simple PowerShell script to set up a Pode server and log a message. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server, enables terminal logging for errors, and writes a "hello, world!" message to the terminal. 7 | The server runs the logic once and then exits. 8 | 9 | .EXAMPLE 10 | To run the sample: ./OneOff-Script.ps1 11 | 12 | .LINK 13 | https://github.com/Badgerati/Pode/blob/develop/examples/OneOff-Script.ps1 14 | 15 | .NOTES 16 | Author: Pode Team 17 | License: MIT License 18 | #> 19 | 20 | try { 21 | # Determine the script path and Pode module path 22 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 23 | $podePath = Split-Path -Parent -Path $ScriptPath 24 | 25 | # Import the Pode module from the source path if it exists, otherwise from installed modules 26 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 27 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 28 | } 29 | else { 30 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 31 | } 32 | } 33 | catch { throw } 34 | 35 | # or just: 36 | # Import-Module Pode 37 | 38 | # runs the logic once, then exits 39 | Start-PodeServer { 40 | 41 | New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging 42 | Write-PodeHost 'hello, world!' 43 | 44 | } 45 | -------------------------------------------------------------------------------- /examples/PetStore/server.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | RestFulPort = 8081 3 | Protocol = 'Http' 4 | Address = 'localhost' 5 | Certificate = 'Certificate.pem' 6 | CertificateKey = 'CertificateKey.key' 7 | CertificatePassword = 'password@01' 8 | SessionsTtlMinutes = 360 9 | SelfSignedCertificate = $false 10 | Server = @{ 11 | Timeout = 60 12 | BodySize = 100MB 13 | } 14 | Web = @{ 15 | OpenApi = @{ 16 | DefaultDefinitionTag = 'v3.0.3' 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /examples/Schedules-CronHelper.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a Pode server with HTTP endpoints and a scheduled task. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server listening on port 8081 with a scheduled task that runs every 2 minutes. 7 | It includes an endpoint for GET requests. 8 | 9 | .EXAMPLE 10 | To run the sample: ./Schedules-CronHelper.ps1 11 | 12 | Invoke-RestMethod -Uri http://localhost:8081 -Method Get 13 | 14 | .LINK 15 | https://github.com/Badgerati/Pode/blob/develop/examples/Schedules-CronHelper.ps1 16 | 17 | .NOTES 18 | Author: Pode Team 19 | License: MIT License 20 | #> 21 | 22 | try { 23 | # Determine the script path and Pode module path 24 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 25 | $podePath = Split-Path -Parent -Path $ScriptPath 26 | 27 | # Import the Pode module from the source path if it exists, otherwise from installed modules 28 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 29 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 30 | } 31 | else { 32 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 33 | } 34 | } 35 | catch { throw } 36 | 37 | # or just: 38 | # Import-Module Pode 39 | 40 | Start-PodeServer { 41 | 42 | Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http 43 | 44 | $cron = New-PodeCron -Every Minute -Interval 2 45 | Add-PodeSchedule -Name 'example' -Cron $cron -ScriptBlock { 46 | 'Hi there!' | Out-Default 47 | } 48 | 49 | Add-PodeRoute -Method Get -Path '/' -ScriptBlock { 50 | Write-PodeJsonResponse -Value @{ Result = 1 } 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /examples/Schedules-LongRunning.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a Pode server with multiple scheduled tasks. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server listening on port 8081 with multiple scheduled tasks. Each task runs every minute 7 | and sleeps for a random duration between 5 and 40 seconds. The maximum concurrency for schedules is set to 30. 8 | 9 | .EXAMPLE 10 | To run the sample: ./Schedules-LongRunning.ps1 11 | 12 | .LINK 13 | https://github.com/Badgerati/Pode/blob/develop/examples/Schedules-LongRunning.ps1 14 | 15 | .NOTES 16 | Author: Pode Team 17 | License: MIT License 18 | #> 19 | 20 | try { 21 | # Determine the script path and Pode module path 22 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 23 | $podePath = Split-Path -Parent -Path $ScriptPath 24 | 25 | # Import the Pode module from the source path if it exists, otherwise from installed modules 26 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 27 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 28 | } 29 | else { 30 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 31 | } 32 | } 33 | catch { throw } 34 | 35 | # or just: 36 | # Import-Module Pode 37 | 38 | # create a server, and start listening on port 8081 39 | Start-PodeServer { 40 | 41 | # listen on localhost:8081 42 | Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http 43 | 44 | # add lots of schedules that each sleep for a while 45 | 1..30 | ForEach-Object { 46 | Add-PodeSchedule -Name "Schedule_$($_)" -Cron '@minutely' -ArgumentList @{ ID = $_ } -ScriptBlock { 47 | param($ID) 48 | 49 | $seconds = (Get-Random -Minimum 5 -Maximum 40) 50 | Start-Sleep -Seconds $seconds 51 | "ID: $($ID) [$($seconds)]" | Out-PodeHost 52 | } 53 | } 54 | 55 | Set-PodeScheduleConcurrency -Maximum 30 56 | 57 | } -------------------------------------------------------------------------------- /examples/Schedules-Routes.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a Pode server with dynamic schedule creation. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server listening on port 8081 with the ability to create new schedules dynamically via an API route. 7 | The server is configured with schedule pooling enabled, and includes an endpoint to create a new schedule that runs every minute. 8 | 9 | .EXAMPLE 10 | To run the sample: ./Schedules-Routes.ps1 11 | 12 | Invoke-RestMethod -Uri http://localhost:8081/api/schedule -Method Get 13 | 14 | .LINK 15 | https://github.com/Badgerati/Pode/blob/develop/examples/Schedules-Routes.ps1 16 | 17 | .NOTES 18 | Author: Pode Team 19 | License: MIT License 20 | #> 21 | 22 | try { 23 | # Determine the script path and Pode module path 24 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 25 | $podePath = Split-Path -Parent -Path $ScriptPath 26 | 27 | # Import the Pode module from the source path if it exists, otherwise from installed modules 28 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 29 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 30 | } 31 | else { 32 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 33 | } 34 | } 35 | catch { throw } 36 | 37 | # or just: 38 | # Import-Module Pode 39 | 40 | # create a server, and start listening on port 8081 41 | Start-PodeServer -EnablePool Schedules { 42 | 43 | # listen on localhost:8081 44 | Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http 45 | 46 | # create a new schdule via a route 47 | Add-PodeRoute -Method Get -Path '/api/schedule' -ScriptBlock { 48 | Add-PodeSchedule -Name 'example' -Cron '@minutely' -ScriptBlock { 49 | 'hello there' | out-default 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /examples/ServerFrom-File.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a basic Pode server. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server using a server definition from an external script file. The server listens on port 8081, logs errors to the terminal, uses the Pode view engine, and includes a timer and a route for HTTP GET requests. 7 | 8 | .EXAMPLE 9 | To run the sample: ./ServerFrom-File.ps1 10 | 11 | .LINK 12 | https://github.com/Badgerati/Pode/blob/develop/examples/ServerFrom-File.ps1 13 | 14 | .NOTES 15 | Author: Pode Team 16 | License: MIT License 17 | #> 18 | 19 | try { 20 | # Determine the script path and Pode module path 21 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 22 | $podePath = Split-Path -Parent -Path $ScriptPath 23 | 24 | # Import the Pode module from the source path if it exists, otherwise from installed modules 25 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 26 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 27 | } 28 | else { 29 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 30 | } 31 | } 32 | catch { throw } 33 | 34 | # or just: 35 | # Import-Module Pode 36 | 37 | # create a basic server 38 | Start-PodeServer -FilePath "$ScriptPath/scripts/server.ps1" -CurrentPath -------------------------------------------------------------------------------- /examples/SwaggerEditor/Swagger-Editor.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Sets up a Pode server to serve the Swagger editor and static files. 4 | 5 | .DESCRIPTION 6 | This script configures a Pode server to listen on a specified port (default is 8081) and serve the Swagger editor 7 | and other static files. It enables request and error logging and sets up a view engine for rendering HTML. 8 | 9 | .PARAMETER Port 10 | The port number on which the Pode server will listen. Default is 8081. 11 | 12 | .EXAMPLE 13 | To run the sample: ./SwaggerEditor/Swagger-Editor.ps1 14 | 15 | Use a browser to access http://127.0.0.1:8081/ 16 | 17 | 18 | .LINK 19 | https://github.com/Badgerati/Pode/blob/develop/examples/SwaggerEditor/Swagger-Editor.ps1 20 | 21 | .NOTES 22 | Author: Pode Team 23 | License: MIT License 24 | #> 25 | param( 26 | [int] 27 | $Port = 8081 28 | ) 29 | 30 | try { 31 | $ScriptPath = (Split-Path -Parent -Path (Split-Path -Parent -Path $MyInvocation.MyCommand.Path)) 32 | $podePath = Split-Path -Parent -Path $ScriptPath 33 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 34 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 35 | } 36 | else { 37 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 38 | } 39 | } 40 | catch { throw } 41 | # or just: 42 | # Import-Module Pode 43 | 44 | # create a server, and start listening on port 8081 45 | Start-PodeServer -ConfigFile '..\Server.psd1' -Threads 2 { 46 | 47 | # listen on localhost:8081 48 | Add-PodeEndpoint -Address localhost -Port $port -Protocol Http 49 | New-PodeLoggingMethod -Terminal | Enable-PodeRequestLogging 50 | New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging 51 | 52 | # set view engine to pode renderer 53 | Set-PodeViewEngine -Type HTML 54 | 55 | # STATIC asset folder route 56 | Add-PodeStaticRoute -Path '/editor' -Source './www' -Defaults @('index.html') -FileBrowser 57 | Add-PodeRoute -Method Get -Path '/' -ScriptBlock { 58 | Move-PodeResponseUrl -Url '/editor/index.html' 59 | } 60 | } -------------------------------------------------------------------------------- /examples/Timers-Route.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A PowerShell script to set up a basic Pode server with timer functionality. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server that listens on a specified port and allows the creation of timers via HTTP routes. 7 | It includes a route to create a new timer that runs a specified script block at defined intervals. 8 | 9 | .EXAMPLE 10 | To run the sample: ./Timers-Route.ps1 11 | 12 | Invoke-RestMethod -Uri http://localhost:8081/api/timer -Method Get 13 | 14 | .LINK 15 | https://github.com/Badgerati/Pode/blob/develop/examples/Timers-Route.ps1 16 | 17 | .PARAMETER Port 18 | The port number on which the Pode server will listen. Default is 8081. 19 | 20 | .NOTES 21 | Author: Pode Team 22 | License: MIT License 23 | #> 24 | try { 25 | # Determine the script path and Pode module path 26 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 27 | $podePath = Split-Path -Parent -Path $ScriptPath 28 | 29 | # Import the Pode module from the source path if it exists, otherwise from installed modules 30 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 31 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 32 | } 33 | else { 34 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 35 | } 36 | } 37 | catch { throw } 38 | 39 | # or just: 40 | # Import-Module Pode 41 | 42 | # create a basic server 43 | Start-PodeServer -EnablePool Timers { 44 | 45 | Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http 46 | 47 | # create a new timer via a route 48 | Add-PodeRoute -Method Get -Path '/api/timer' -ScriptBlock { 49 | Add-PodeTimer -Name 'example' -Interval 5 -ScriptBlock { 50 | 'hello there' | out-default 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /examples/Web-AuthNegotiate.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Example of using Negotiate authentication with Pode. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server that listens on port 8080, logs errors to the terminal, 7 | and demonstrates the use of Negotiate authentication. The server provides a single route 8 | that requires Negotiate authentication to access. 9 | 10 | .EXAMPLE 11 | To run the sample: ./Web-AuthNegotiate.ps1 12 | 13 | Invoke-RestMethod -Uri 'http://pode.example.com:8080' -UseDefaultCredentials 14 | 15 | .LINK 16 | https://github.com/Badgerati/Pode/blob/develop/examples/Web-AuthNegotiate.ps1 17 | 18 | .NOTES 19 | Author: Pode Team 20 | License: MIT License 21 | #> 22 | 23 | try { 24 | # Determine the script path and Pode module path 25 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 26 | $podePath = Split-Path -Parent -Path $ScriptPath 27 | 28 | # Import the Pode module from the source path if it exists, otherwise from installed modules 29 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 30 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 31 | } 32 | else { 33 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 34 | } 35 | } 36 | catch { throw } 37 | 38 | # or just: 39 | # Import-Module Pode 40 | 41 | Start-PodeServer -Threads 2 { 42 | # listen on localhost:8080 43 | Add-PodeEndpoint -Address localhost -Port 8080 -Host 'pode.example.com' -Protocol Http 44 | 45 | # enable error logging 46 | New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging 47 | 48 | # setup negotiate auth 49 | New-PodeAuthScheme -Negotiate -KeytabPath '.\pode-user.keytab' | Add-PodeAuth -Name 'Login' -Sessionless -ScriptBlock { 50 | param($claim) 51 | $claim | Out-Default 52 | $claim.Identity.Name | Out-Default 53 | return @{ User = $claim } 54 | } 55 | 56 | # example JSON route, requiring negotiate auth 57 | Add-PodeRoute -Method Get -Path '/' -Authentication Login -ScriptBlock { 58 | Write-PodeJsonResponse -Value @{ result = 'hello' } 59 | } 60 | } -------------------------------------------------------------------------------- /examples/Web-Gui.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a Pode server with desktop GUI capabilities. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server listening on ports 8081 and 8091. It includes a route to handle GET requests 7 | and sets up the server to run as a desktop GUI application using the Pode view engine. 8 | 9 | .EXAMPLE 10 | To run the sample: ./Web-Gui.ps1 11 | 12 | .LINK 13 | https://github.com/Badgerati/Pode/blob/develop/examples/Web-Gui.ps1 14 | 15 | .NOTES 16 | Author: Pode Team 17 | License: MIT License 18 | #> 19 | try { 20 | # Determine the script path and Pode module path 21 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 22 | $podePath = Split-Path -Parent -Path $ScriptPath 23 | 24 | # Import the Pode module from the source path if it exists, otherwise from installed modules 25 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 26 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 27 | } 28 | else { 29 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 30 | } 31 | } 32 | catch { throw } 33 | 34 | # or just: 35 | # Import-Module Pode 36 | 37 | # create a server, and start listening on port 8081 38 | Start-PodeServer { 39 | 40 | # listen on localhost:8081 41 | Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http -Name 'local1' 42 | Add-PodeEndpoint -Address localhost -Port 8091 -Protocol Http -Name 'local2' 43 | 44 | # tell this server to run as a desktop gui 45 | Show-PodeGui -Title 'Pode Desktop Application' -Icon '../images/icon.png' -EndpointName 'local2' -ResizeMode 'NoResize' 46 | 47 | # set view engine to pode renderer 48 | Set-PodeViewEngine -Type Pode 49 | 50 | # GET request for web page on "localhost:8081/" 51 | Add-PodeRoute -Method Get -Path '/' -ScriptBlock { 52 | Write-PodeViewResponse -Path 'gui' -Data @{ 'numbers' = @(1, 2, 3); } 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /examples/Web-GzipRequest.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a Pode server with error logging and a route to handle gzip'd JSON. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server listening on port 8081. It includes error logging and a route to handle POST requests that receive gzip'd JSON data. 7 | 8 | .EXAMPLE 9 | To run the sample: ./Web-GzipRequest.ps1 10 | 11 | Invoke-RestMethod -Uri http://localhost:8081/users -Method Post 12 | 13 | .LINK 14 | https://github.com/Badgerati/Pode/blob/develop/examples/Web-GzipRequest.ps1 15 | 16 | .NOTES 17 | Author: Pode Team 18 | License: MIT License 19 | #> 20 | try { 21 | # Determine the script path and Pode module path 22 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 23 | $podePath = Split-Path -Parent -Path $ScriptPath 24 | 25 | # Import the Pode module from the source path if it exists, otherwise from installed modules 26 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 27 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 28 | } 29 | else { 30 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 31 | } 32 | } 33 | catch { throw } 34 | 35 | # or just: 36 | # Import-Module Pode 37 | 38 | # create a server, and start listening on port 8081 39 | Start-PodeServer -Threads 2 { 40 | 41 | # listen on localhost:8081 42 | Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http 43 | 44 | New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging 45 | 46 | # GET request that receives gzip'd json 47 | Add-PodeRoute -Method Post -Path '/users' -ScriptBlock { 48 | Write-PodeJsonResponse -Value $WebEvent.Data 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /examples/Web-Imports.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a Pode server with various routes, access rules, logging, and request handling. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server listening on multiple endpoints with request redirection. 7 | It demonstrates how to handle GET, POST, and other HTTP requests, set up access and limit rules, 8 | implement custom logging, and serve web pages using Pode's view engine. 9 | 10 | .PARAMETER Port 11 | The port number on which the server will listen. Default is 8081. 12 | 13 | .EXAMPLE 14 | To run the sample: ./Web-Imports.ps1 15 | 16 | Invoke-RestMethod -Uri http://localhost:8081/ -Method Get 17 | 18 | .LINK 19 | https://github.com/Badgerati/Pode/blob/develop/examples/Web-Imports.ps1 20 | 21 | .NOTES 22 | Author: Pode Team 23 | License: MIT License 24 | #> 25 | param( 26 | [int] 27 | $Port = 8081 28 | ) 29 | 30 | try { 31 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 32 | $podePath = Split-Path -Parent -Path $ScriptPath 33 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 34 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 35 | } 36 | else { 37 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 38 | } 39 | 40 | # import modules 41 | Import-Module -Name EPS -ErrorAction Stop 42 | } 43 | catch { throw } 44 | 45 | # or just: 46 | # Import-Module Pode 47 | 48 | 49 | 50 | # create a server, and start listening on port 8081 51 | Start-PodeServer -Threads 2 { 52 | 53 | # listen on localhost:8081 54 | Add-PodeEndpoint -Address localhost -Port $Port -Protocol Http 55 | 56 | # set view engine to pode renderer 57 | Set-PodeViewEngine -Type Pode 58 | 59 | # GET request for web page on "localhost:8081/" 60 | Add-PodeRoute -Method Get -Path '/' -ScriptBlock { 61 | Get-Module | Out-Default 62 | Write-PodeViewResponse -Path 'simple' -Data @{ 'numbers' = @(1, 2, 3); } 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /examples/Web-Metrics.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a Pode server with a route to check server uptime and restart count. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server listening on port 8081. It includes a route to check the server's uptime 7 | and the number of times the server has restarted. 8 | 9 | .EXAMPLE 10 | To run the sample: ./Web-Metrics.ps1 11 | 12 | Invoke-RestMethod -Uri http://localhost:8081/uptime -Method Get 13 | 14 | .LINK 15 | https://github.com/Badgerati/Pode/blob/develop/examples/Web-Metrics.ps1 16 | 17 | .NOTES 18 | Author: Pode Team 19 | License: MIT License 20 | #> 21 | try { 22 | # Determine the script path and Pode module path 23 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 24 | $podePath = Split-Path -Parent -Path $ScriptPath 25 | 26 | # Import the Pode module from the source path if it exists, otherwise from installed modules 27 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 28 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 29 | } 30 | else { 31 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 32 | } 33 | } 34 | catch { throw } 35 | 36 | Start-PodeServer -Threads 2 { 37 | 38 | Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http 39 | 40 | Add-PodeRoute -Method Get -Path '/uptime' -ScriptBlock { 41 | Write-PodeJsonResponse -Value @{ 42 | Restarts = (Get-PodeServerRestartCount) 43 | Uptime = @{ 44 | Session = (Get-PodeServerUptime) 45 | Total = (Get-PodeServerUptime -Total) 46 | } 47 | } 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /examples/Web-SelfSigned.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a HTTPS Pode server with a self-sign certificate 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server listening on port 8081 in HTTPS 7 | 8 | .EXAMPLE 9 | To run the sample: ./Web-SelfSigned.ps1 10 | 11 | .LINK 12 | https://github.com/Badgerati/Pode/blob/develop/examples/Web-SelfSigned.ps1 13 | 14 | .NOTES 15 | Author: Pode Team 16 | License: MIT License 17 | #> 18 | try { 19 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 20 | $podePath = Split-Path -Parent -Path $ScriptPath 21 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 22 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 23 | } 24 | else { 25 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 26 | } 27 | } 28 | catch { throw } 29 | 30 | Start-PodeServer -Threads 6 { 31 | Add-PodeEndpoint -Address localhost -Port '8081' -Protocol 'Https' -SelfSigned 32 | 33 | New-PodeLoggingMethod -File -Name 'requests' | Enable-PodeRequestLogging 34 | New-PodeLoggingMethod -File -Name 'errors' | Enable-PodeErrorLogging 35 | 36 | Add-PodeRoute -Method Get -Path / -ScriptBlock { 37 | Write-PodeTextResponse -Value 'Test' 38 | } 39 | } -------------------------------------------------------------------------------- /examples/Web-Sessions.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | A sample PowerShell script to set up a Pode server with session persistent authentication. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server listening on port 8085 with session persistent authentication. 7 | It demonstrates a simple server setup with a view counter. Each visit to the root URL ('http://localhost:8085') 8 | increments the view counter stored in the session. 9 | 10 | .EXAMPLE 11 | To run the sample: ./Web-Sessions.ps1 12 | 13 | Invoke-RestMethod -Uri http://localhost:8081/ -Method Get 14 | 15 | .LINK 16 | https://github.com/Badgerati/Pode/blob/develop/examples/Web-Sessions.ps1 17 | 18 | .NOTES 19 | Author: Pode Team 20 | License: MIT License 21 | #> 22 | try { 23 | # Determine the script path and Pode module path 24 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 25 | $podePath = Split-Path -Parent -Path $ScriptPath 26 | 27 | # Import the Pode module from the source path if it exists, otherwise from installed modules 28 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 29 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 30 | } 31 | else { 32 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 33 | } 34 | } 35 | catch { throw } 36 | 37 | # or just: 38 | # Import-Module Pode 39 | 40 | # create a server, and start listening on port 8085 41 | Start-PodeServer { 42 | 43 | # listen on localhost:8085 44 | Add-PodeEndpoint -Address localhost -Port 8085 -Protocol Http 45 | 46 | # set view engine to pode renderer 47 | Set-PodeViewEngine -Type Pode 48 | 49 | # setup session details 50 | Enable-PodeSessionMiddleware -Duration 120 -Extend -Generator { 51 | return [System.IO.Path]::GetRandomFileName() 52 | } 53 | 54 | # GET request for web page on "localhost:8085/" 55 | Add-PodeRoute -Method Get -Path '/' -ScriptBlock { 56 | $WebEvent.Session.Data.Views++ 57 | Write-PodeViewResponse -Path 'simple' -Data @{ 'numbers' = @($WebEvent.Session.Data.Views); } 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /examples/Web-SimplePages.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | PowerShell script to set up a Pode server with various pages and error logging. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server that listens on a specified port and provides several routes 7 | to display process and service information, as well as static views. 8 | 9 | .PARAMETER Port 10 | The port number on which the server will listen. Default is 8081. 11 | 12 | .EXAMPLE 13 | To run the sample: ./Web-SimplePages.ps1 14 | 15 | Invoke-RestMethod -Uri http://localhost:8081/Processes/ -Method Get 16 | Invoke-RestMethod -Uri http://localhost:8081/Services/ -Method Get 17 | Invoke-RestMethod -Uri http://localhost:8081/Index/ -Method Get 18 | Invoke-RestMethod -Uri http://localhost:8081/File/ -Method Get 19 | 20 | .LINK 21 | https://github.com/Badgerati/Pode/blob/develop/examples/Web-SimplePages.ps1 22 | 23 | .NOTES 24 | Author: Pode Team 25 | License: MIT License 26 | #> 27 | try { 28 | # Determine the script path and Pode module path 29 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 30 | $podePath = Split-Path -Parent -Path $ScriptPath 31 | 32 | # Import the Pode module from the source path if it exists, otherwise from installed modules 33 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 34 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 35 | } 36 | else { 37 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 38 | } 39 | } 40 | catch { throw } 41 | 42 | # create a server, and start listening on port 8081 43 | Start-PodeServer -Threads 2 { 44 | 45 | # listen on localhost:8081 46 | Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http 47 | New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging 48 | 49 | Add-PodePage -Name Processes -ScriptBlock { Get-Process } 50 | Add-PodePage -Name Services -ScriptBlock { Get-Service } 51 | Add-PodePage -Name Index -View 'simple' 52 | Add-PodePage -Name File -FilePath '.\views\simple.pode' -Data @{ 'numbers' = @(1, 2, 3); } 53 | 54 | } -------------------------------------------------------------------------------- /examples/Web-Sockets.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | PowerShell script to set up a Pode server with HTTPS and logging. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server that listens on a specified port with HTTPS protocol using a certificate. 7 | It includes request logging and provides a sample route to return a JSON response. 8 | 9 | .PARAMETER Port 10 | The port number on which the server will listen. Default is 8081. 11 | 12 | .EXAMPLE 13 | To run the sample: ./Web-Sockets.ps1 14 | 15 | Invoke-RestMethod -Uri https://localhost:8081/ -Method Get 16 | 17 | .LINK 18 | https://github.com/Badgerati/Pode/blob/develop/examples/Web-Sockets.ps1 19 | 20 | .NOTES 21 | Author: Pode Team 22 | License: MIT License 23 | #> 24 | try { 25 | # Determine the script path and Pode module path 26 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 27 | $podePath = Split-Path -Parent -Path $ScriptPath 28 | 29 | # Import the Pode module from the source path if it exists, otherwise from installed modules 30 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 31 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 32 | } 33 | else { 34 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 35 | } 36 | } 37 | catch { throw } 38 | 39 | # or just: 40 | # Import-Module Pode 41 | 42 | # create a server, and start listening 43 | Start-PodeServer -Threads 5 { 44 | 45 | # listen 46 | Add-PodeEndpoint -Address localhost -Port 8081 -Certificate './certs/pode-cert.pfx' -CertificatePassword '1234' -Protocol Https 47 | # Add-PodeEndpoint -Address localhost -Port 8081 -SelfSigned -Protocol Https 48 | 49 | # log requests to the terminal 50 | New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging 51 | 52 | # GET request for web page on "localhost:8085/" 53 | Add-PodeRoute -Method Get -Path '/' -ScriptBlock { 54 | Write-PodeJsonResponse -Value @{ 55 | Kenobi = 'Hello, there' 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /examples/Web-TpEPS.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | PowerShell script to set up a Pode server with EPS view engine. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server that listens on a specified port, logs requests to the terminal, 7 | and uses the EPS renderer for serving web pages. 8 | 9 | .EXAMPLE 10 | To run the sample: ./Web-TpEPS.ps1 11 | 12 | .LINK 13 | https://github.com/Badgerati/Pode/blob/develop/examples/Web-TpEPS.ps1 14 | 15 | .NOTES 16 | Author: Pode Team 17 | License: MIT License 18 | #> 19 | try { 20 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 21 | $podePath = Split-Path -Parent -Path $ScriptPath 22 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 23 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 24 | } 25 | else { 26 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 27 | } 28 | 29 | Import-Module -Name 'EPS' -ErrorAction Stop 30 | } 31 | catch { throw } 32 | 33 | # or just: 34 | # Import-Module Pode 35 | 36 | # create a server, and start listening on port 8081 37 | Start-PodeServer -Threads 2 { 38 | 39 | # listen on localhost:8081 40 | Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http 41 | 42 | # log requests to the terminal 43 | New-PodeLoggingMethod -Terminal | Enable-PodeRequestLogging 44 | 45 | # set view engine to EPS renderer 46 | Set-PodeViewEngine -Type EPS -ScriptBlock { 47 | param($path, $data) 48 | $template = Get-Content -Path $path -Raw -Force 49 | 50 | if ($null -eq $data) { 51 | return (Invoke-EpsTemplate -Template $template) 52 | } 53 | else { 54 | return (Invoke-EpsTemplate -Template $template -Binding $data) 55 | } 56 | } 57 | 58 | # GET request for web page on "localhost:8081/" 59 | Add-PodeRoute -Method Get -Path '/' -ScriptBlock { 60 | Write-PodeViewResponse -Path 'index' -Data @{ 'numbers' = @(1, 2, 3); 'date' = [DateTime]::UtcNow; } 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /examples/Web-TpPSHTML.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | PowerShell script to set up a Pode server with PSHTML view engine. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server that listens on a specified port, logs requests to the terminal, 7 | and uses the PSHTML renderer for serving web pages. 8 | 9 | .EXAMPLE 10 | To run the sample: ./Web-TpPSHTML.ps1 11 | 12 | .LINK 13 | https://github.com/Badgerati/Pode/blob/develop/examples/Web-TpPSHTML.ps1 14 | 15 | .NOTES 16 | Author: Pode Team 17 | License: MIT License 18 | #> 19 | try { 20 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 21 | $podePath = Split-Path -Parent -Path $ScriptPath 22 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 23 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 24 | } 25 | else { 26 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 27 | } 28 | Import-Module -Name PSHTML -ErrorAction Stop 29 | } 30 | catch { throw } 31 | 32 | # or just: 33 | # Import-Module Pode 34 | 35 | 36 | # create a server, and start listening on port 8081 37 | Start-PodeServer -Threads 2 { 38 | 39 | # listen on localhost:8081 40 | Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http 41 | 42 | # log requests to the terminal 43 | New-PodeLoggingMethod -Terminal | Enable-PodeRequestLogging 44 | 45 | # set view engine to PSHTML renderer 46 | Set-PodeViewEngine -Type PSHTML -Extension PS1 -ScriptBlock { 47 | param($path, $data) 48 | return [string](. $path $data) 49 | } 50 | 51 | # GET request for web page on "localhost:8081/" 52 | Add-PodeRoute -Method Get -Path '/' -ScriptBlock { 53 | Write-PodeViewResponse -Path 'index' -Data @{ 'numbers' = @(1, 2, 3); } 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /examples/Web-UploadKestrel.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | PowerShell script to set up a Pode server with Kestrel listener and file upload functionality. 4 | 5 | .DESCRIPTION 6 | This script sets up a Pode server that listens on a specified port using the Kestrel listener type. 7 | It serves a web page for file upload and processes file uploads, saving them to the server. 8 | 9 | .PARAMETER Port 10 | The port number on which the server will listen. Default is 8081. 11 | 12 | .EXAMPLE 13 | To run the sample: ./Web-UploadKestrel.ps1 14 | 15 | Invoke-RestMethod -Uri http://localhost:8081/upload -Method Post 16 | Invoke-RestMethod -Uri http://localhost:8081/ -Method Get 17 | 18 | .LINK 19 | https://github.com/Badgerati/Pode/blob/develop/examples/Web-UploadKestrel.ps1 20 | 21 | .NOTES 22 | Author: Pode Team 23 | License: MIT License 24 | #> 25 | param( 26 | [int] 27 | $Port = 8081 28 | ) 29 | 30 | try { 31 | $ScriptPath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) 32 | $podePath = Split-Path -Parent -Path $ScriptPath 33 | if (Test-Path -Path "$($podePath)/src/Pode.psm1" -PathType Leaf) { 34 | Import-Module "$($podePath)/src/Pode.psm1" -Force -ErrorAction Stop 35 | } 36 | else { 37 | Import-Module -Name 'Pode' -MaximumVersion 2.99 -ErrorAction Stop 38 | } 39 | Import-Module -Name Pode.Kestrel -ErrorAction Stop 40 | } 41 | catch { throw } 42 | 43 | 44 | # or just: 45 | # Import-Module Pode 46 | 47 | # create a server, and start listening on port 8081 48 | Start-PodeServer -Threads 2 -ListenerType Kestrel { 49 | 50 | # listen on localhost:8081 51 | Add-PodeEndpoint -Address localhost -Port $port -Protocol Http 52 | 53 | Set-PodeViewEngine -Type HTML 54 | 55 | # GET request for web page on "localhost:8081/" 56 | Add-PodeRoute -Method Get -Path '/' -ScriptBlock { 57 | Write-PodeViewResponse -Path 'web-upload' 58 | } 59 | 60 | # POST request to upload a file 61 | Add-PodeRoute -Method Post -Path '/upload' -ScriptBlock { 62 | Save-PodeRequestFile -Key 'avatar' 63 | Move-PodeResponseUrl -Url '/' 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /examples/assets/[metadata].json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example" 3 | } -------------------------------------------------------------------------------- /examples/assets/file.txt: -------------------------------------------------------------------------------- 1 | Hello there. -------------------------------------------------------------------------------- /examples/assets/images/Fry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/examples/assets/images/Fry.png -------------------------------------------------------------------------------- /examples/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Static Page 4 | 5 | 6 | 7 | Hello, world! This is a static index page! 8 | 9 | -------------------------------------------------------------------------------- /examples/auth/SampleAuth.ps1: -------------------------------------------------------------------------------- 1 | # setup bearer auth 2 | New-PodeAuthScheme -ApiKey -Location $Location | Add-PodeAuth -Name 'Validate' -Sessionless -ScriptBlock { 3 | param($key) 4 | 5 | # here you'd check a real user storage, this is just for example 6 | if ($key -ieq 'test-api-key') { 7 | return @{ 8 | User = @{ 9 | ID = 'M0R7Y302' 10 | Name = 'Morty' 11 | Type = 'Human' 12 | } 13 | } 14 | } 15 | 16 | return $null 17 | } -------------------------------------------------------------------------------- /examples/certs/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDYDCCAkigAwIBAgIJAKe/1qpK2+6+MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV 3 | BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX 4 | aWRnaXRzIFB0eSBMdGQwHhcNMjEwODA1MTUzODE1WhcNMjIwODA1MTUzODE1WjBF 5 | MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 6 | ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB 7 | CgKCAQEA4JoZM7i3KJHC8EOzBRO8bmSAVoRIjvLD2O1B0Axv9+2wQlHByZZZP2Pp 8 | bY3wahczUvDqihGV0iQDeKDUvETnh4MrrJaeXqyt/t9/5wVeuH10p5tfaYe4Mqwd 9 | tVxyAsjLB41445fTGkwvmJi0Ka19GFx232DAT28p5kc8VLb/XXAjuEzeccBOvw53 10 | ZOSbANg3g2G7m/GYeehtK9vh8FQTDtnMXer6WZ0QNBSF9898KpC1WQsF89t24Ox7 11 | SJs3uWjFqBwKMbEl6fUMg7I26DY7pYIgKu5QAfUgdF8LZcPv5Fu8c0Np/XdcpuVI 12 | 1S4jVmo4xf7/Tr3fFPNJ/r5im19UhwIDAQABo1MwUTAdBgNVHQ4EFgQUbHM52jhC 13 | bekyuSuu+R6hwpCrB10wHwYDVR0jBBgwFoAUbHM52jhCbekyuSuu+R6hwpCrB10w 14 | DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAy9mnBTkRWHVwK/t8 15 | E2nYkoDqwwa+dO852JGrl39vzJR02iQUMKF7OFGPf33VmsgJFyznNzZWnOnqg7l4 16 | 6RH5vSymdC7MShKp/jKzScdN1iGS0OFn6ZzJLLVilxj3WMfX3ivv0VdOq46OmRhl 17 | 3ymVdqWNXN9Mkz8pPeS2IcluMsy4YAjd76vTLeVpcruKjHT/zYv+mvLilzmCUNO7 18 | ZEgv8Z/rCGahaGstBnXecLv/fYhAtciEsjVZuwQO74YWSckNnFCxltMFEp4isskU 19 | KA452y1/mdHc/GADPry9Fitjus2cjBIKuw0vwOZlx9nzk/oE4K41SNk41rxEVhYt 20 | azEiUw== 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /examples/certs/cert_nodes.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDYDCCAkigAwIBAgIJAJc72KSCiuAkMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV 3 | BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX 4 | aWRnaXRzIFB0eSBMdGQwHhcNMjEwODA1MTUzODAwWhcNMjIwODA1MTUzODAwWjBF 5 | MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 6 | ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB 7 | CgKCAQEArvYj+XMKYRfU3cKXfeDeX0Tv8zPnZ9hc/lTBc3UNifBjzcReLKbTDz76 8 | IxI6rmNFcRXJbVDOTE03pIBsqs4+haaGYtwd4tyvTex4iUfURd887WaOwjCtsMsM 9 | w3Pgll8SpZaXvuWboZUWNTtgWNWQ5BhYFQhxcI+iuJecy2WqHkbG9UPjsF7slyAT 10 | eGnuB9O2xAV9qapVMWz10CwqW0HWeaHcLqqM1XGyNxTtU+RkUV16+Qb1rW901Ck+ 11 | mDXoUs4O4UW9jVHKw03DKlv/9v1lnOszveKXvtriOBS3nhFeCpej0TYFvExoE2G1 12 | dOEvDxBvDkRT0TXVH/VuZ5qBp2qp1wIDAQABo1MwUTAdBgNVHQ4EFgQUpUllOx5o 13 | M+22/y06FYvhKf/ZGyAwHwYDVR0jBBgwFoAUpUllOx5oM+22/y06FYvhKf/ZGyAw 14 | DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAfi/dniGTslG4MF7d 15 | p2KxF2/VsXYVnjp4EfpIUBfQwF/6yn3jUJSunWc/iisLp0GXvmyAk56eDBQEWdx+ 16 | cogIKbKAhrMk0JbmRNRJN+6DrKlstgqcP3bVMDYKRD82VrzfcdtMeI70PwH55wPU 17 | V3UHmlni4Gs2js48TjRwypCvTTozNrkDiC89FrlQ7+PhQCcG26GZZpSMXP54allO 18 | U2aQrQv0zCYi1gZwyQ0px/2vPkOD4HEmbEk7hGFkaM88+XutyDxfYG21glz4JzsQ 19 | TPicqsfAItoaOPZ3wQ2wEMhjyum6/V5VoXRJ17lFtG1Vy8GfTt8zTkZyGkGx/zTN 20 | xBJkHQ== 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /examples/certs/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIXZcbs4qNi2kCAggA 3 | MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECIpXQr1lKOXJBIIEyBnrPhHod9qi 4 | aVphPgF0IBTKrRJfWlzkGg/FuUvhxRfJd9xeozt6eCYWYV4TWAJj8mGbDr2pORyd 5 | 4loI6Bo3HtpW1WHZmYP4X7OLkCCjNYo/LoE7AX325bkmhs6AWOggWkK072oygRds 6 | qnHXdyzQV0u74mYu1u4yBXhTxzllfgwvKZ+ChrloMcXAgz5+7cS06Jzw97WDjoJG 7 | lTAHpBlFptP+SEfiG/PP78NA+zspKs9yijtRD5aD/pOHsN943AfbxGimd1vK+Xma 8 | 6HpCqrdljrgg+/On5jKl9ffOdczyhqZFJyaqgEcZgQiVQwUilz8JK5Y1qqv29pm7 9 | zvxebdt/PkMlzGr5E4X/Nu3iKk2BhnwSS6W9B7u/bGaH97uHE04CTi9U3SV9H+g9 10 | JUYTxMfkJ5sdnlxfEo1jjS8YKg/+V2P5bXd5bEp7SgtmoUz/IcDfctiLDUV9Xh/E 11 | JXlEcPq2cx+wpc3fN+bC42ZLoEbbxEVoWRktqJo6ZA4VltEujlbl3WA/qphoFixL 12 | uE+O9s5ekTi+Yk9lIvFd3Tv7tMSCzp3Qkwxu1S2AgiOIReWeC1tp9X6qY/srOrtV 13 | S6hAPclKgGMhyreBdcXk+CrL/vQVo0B8J80xRgz9thC1KY9NNWR1MiBbLxTxXdHJ 14 | kAwsHrm31nvBiV3WDu3ShXQjBRDgCq5b1Di1KRN0z2w7Ht4MMB4hVmgeeWjVG3Ia 15 | jAwxvXrjIXs7D7nzYUpMVxbMyeYkERIQ5czxR7R7rNp9jCCGuy2GGoZjOdZ8Kd4N 16 | NQj/ZLYKIBQGIOkvtQ8UL/Kxe91VM8QpwszvwJXIQgmidDsOcZw7NiGqLJX3mRzD 17 | qRKYl1TXAJnYuBYUNaPbzeNbRE/RvTqz55LNZ0juL39WYnE0gwwP5V3G122d7Msm 18 | KRpE8X1Mv7E8EqtBzdoK3O6YgoTm/njsecUCZfU/c7FKg180Q/z18uVMxQ3nSxEv 19 | wR0rpc5CW9c4MlnomVrlimob5uG0MnkANLKJNtm6+KDyt110g5xUdgF1Jqb5AkeU 20 | HzNWXQlmOw9AhYshTKDwtZVlChxvSC9IwbcxDORkjiiC7TWIiXa8lwyUHoCzS4jb 21 | ACnvbWN+J2a08AXExUJSDmsP6+3mplwFAz2rn38xp0HYQOoRm+Rw5AMtSwN6KYn1 22 | P9CKxDB8lK8/GF2iELzudiraiDc61l8ELkmFACyt2Fo70tfj4sVQIu7KJhp1jBAU 23 | /CXQAKaY7otZ5fcmwby2rp4eMuNv8aInGZfEderZoz6UivErhr2Rydep+VA9Sbgq 24 | 316/z/hGrzwWWa2I1qbuX19bN1jILhsa7YTa2CL/6KB1ghh9lqkWfY6Po8rVN/YP 25 | Kw0R+7+MK2KHXES+NDP5dF5d0KiDJDvGkS//8ZUUGwbJNi+ymrUvhKhTmJoPG3xf 26 | sV0ELNQlkFQt28YrfFSHyB+hVCNnTcy1sMWGUt2X1Thsr6GL717Q+YhnOQZEDd2M 27 | Jhs/4LJaCvrdXIJHQXgtsS2UBAqd4+frJh1pp+SWRT+Xn+uAqfxCjhrJ73bLPcx/ 28 | lOfBtkpjZGaqOIr6kFYDsf+eVXimtkF2fYyCeU7WoS+vML52Cz7+hWjouq53kS3m 29 | 2XbYMLV6Z1Bcjbvb8i6uEA== 30 | -----END ENCRYPTED PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /examples/certs/key_nodes.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCu9iP5cwphF9Td 3 | wpd94N5fRO/zM+dn2Fz+VMFzdQ2J8GPNxF4sptMPPvojEjquY0VxFcltUM5MTTek 4 | gGyqzj6FpoZi3B3i3K9N7HiJR9RF3zztZo7CMK2wywzDc+CWXxKllpe+5ZuhlRY1 5 | O2BY1ZDkGFgVCHFwj6K4l5zLZaoeRsb1Q+OwXuyXIBN4ae4H07bEBX2pqlUxbPXQ 6 | LCpbQdZ5odwuqozVcbI3FO1T5GRRXXr5BvWtb3TUKT6YNehSzg7hRb2NUcrDTcMq 7 | W//2/WWc6zO94pe+2uI4FLeeEV4Kl6PRNgW8TGgTYbV04S8PEG8ORFPRNdUf9W5n 8 | moGnaqnXAgMBAAECggEAFTy1YysOoHh3Ey/ymYn5FBFXGus69ITzzL9W9//GU+8E 9 | /k4OrFbXmasoS6eDzfUo0bA2UfmUAPkCfwpDpnwAZNKwz0Eus4HcGZZRj0BTyONv 10 | DtX7ECE+hA4xj2v6X+ZMaiMcakSOno9tMaryZ/YMb1NxJaRvuJ0GwGdO1fWSL7hu 11 | NXB2jRkrHAEzb4zudsMwJhOVmPGfN6PZ2ktONfnP06Nz8YcyTipF+QHbxrJ91nM7 12 | +udY534LTBXjIHJ8Fm8yGbFTJRUmAH+OpTzpmB54HI1b25liN8cZyr6NZHjr0+zT 13 | Uk9V4Cnq8rDIyXnDkfVg3nZSDw3wVPQPsPTmv6U1eQKBgQDb7A9Zs7xW/KFldmgO 14 | gS2cfXqfprvTpl8IebsHYGQX6sYarVHE5awhe1wV2V6v6LUWzta3BFpLer/l4ASk 15 | LpNlTa5+QIFbe5zuWu55bgPKZRPRbdWLzhHN12y+3KWAYEvioxHHizXMDIqubZ1v 16 | JaiF9UGmNWdX7NeYEPIr9R0ghQKBgQDLqeVHCELvizsmVzX5R9e6h0ybgisZAsP9 17 | z0bNZszzxV0zji65zCkxgCkQW1SMDkJMmpYSWjVp5nR5b9RwXGA7jZ+m2HAttNzq 18 | JyKlTJG39IDmg4Ap/hDjqRWj5La9z5rY/WX7l9lVTjGiQuDbHRccC533jGyU/COD 19 | NuA14lF9qwKBgHLTO+iQCaQ5X2OEgSwhklkEwwOcoLEPSss4E8j0MQ6zzB+dovX1 20 | HPyWViwqRGAAVpzD/iOsqCCExLEXWBUJJHheKN9OervzPKrO23iXUm9YexJ8EGVg 21 | gLdC5Up6FgeDP9vjXKMdMkeJvNb58JtZxDW9KjvH4l9sD90b6/W7kyupAoGBAIwj 22 | SF97IMvBax7zrXDs7VUtGhp7E/quu3uer6JQVUB7kqkR8bbo84NbI2Zc4a1JdndN 23 | e2v/ZHeNGqIgv/Xcql7wEWX10iKxK7121lEVgcMpW7TB0WOTrb1pMDnI+7FZ87vR 24 | iOX405PuLRrwl9ZNiwRCPh0DJAfUAv+bt+V76ATnAoGBAKJ0jKIqf4eVFyqxIZNp 25 | +tdLQ5aQQQuCNGoY0flD5kAq8lCSLxt+76VMlCxG3gqAYIEz697fjDMsGaLDkmt3 26 | QZql5UcJrYoppSa9otqRNftdRzfyDZ+7aEYQ5qimrPRFGtHPf9CVj81AI7vkbpBe 27 | 4QhebC89xSeGKpd9rAdJXDYz 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /examples/certs/pode-cert.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/examples/certs/pode-cert.cer -------------------------------------------------------------------------------- /examples/certs/pode-cert.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/examples/certs/pode-cert.pfx -------------------------------------------------------------------------------- /examples/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | web: 5 | build: . 6 | ports: 7 | - "8081:8081" 8 | container_name: pode-example 9 | restart: always 10 | -------------------------------------------------------------------------------- /examples/modules/External-Funcs.psm1: -------------------------------------------------------------------------------- 1 | function Get-Greeting { 2 | return "Hello, world! [$(Get-Random -Maximum 100)]" 3 | } -------------------------------------------------------------------------------- /examples/modules/Imported-Funcs.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Custom function for Web-PageUsing 4 | 5 | .DESCRIPTION 6 | Custom function for Web-PageUsing 7 | 8 | .NOTES 9 | Author: Pode Team 10 | License: MIT License 11 | #> 12 | function Write-MyGreeting { 13 | Write-PodeJsonResponse -Value @{ Message = "Hello, world! [$(Get-Random -Maximum 100)]" } 14 | } 15 | 16 | Export-PodeFunction -Name 'Write-MyGreeting' 17 | Use-PodeScript -Path (Join-Path $PSScriptRoot .\Imported-SubFuncs.ps1) -------------------------------------------------------------------------------- /examples/modules/Imported-SubFuncs.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Custom function for Imported-Funcs.ps1 4 | 5 | .DESCRIPTION 6 | Custom function for Imported-Funcs.ps1 7 | 8 | .NOTES 9 | Author: Pode Team 10 | License: MIT License 11 | #> 12 | function Write-MySubGreeting { 13 | Write-PodeJsonResponse -Value @{ Message = "Mudkipz! [$(Get-Random -Maximum 100)]" } 14 | } 15 | 16 | Export-PodeFunction -Name 'Write-MySubGreeting' -------------------------------------------------------------------------------- /examples/modules/RouteScript.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Custom script for Web-Pages.ps1 and Web-PagesKestrel.ps1 4 | 5 | .DESCRIPTION 6 | Custom script for Web-Pages.ps1 and Web-PagesKestrel.ps1 7 | 8 | .NOTES 9 | Author: Pode Team 10 | License: MIT License 11 | #> 12 | return { 13 | $using:hmm | out-default 14 | Write-PodeViewResponse -Path 'simple' -Data @{ 'numbers' = @(4, 5, 6); } 15 | } -------------------------------------------------------------------------------- /examples/modules/Script1.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Custom script for Dot-SourceScript.ps1 4 | 5 | .DESCRIPTION 6 | Custom script for Dot-SourceScript.ps1 7 | 8 | .NOTES 9 | Author: Pode Team 10 | License: MIT License 11 | #> 12 | 13 | Write-Host 'Hello, world!' -------------------------------------------------------------------------------- /examples/open-gui.bat: -------------------------------------------------------------------------------- 1 | rem This is an example script to open a gui via Pode, and hide the terminal 2 | powershell.exe -noprofile -windowstyle hidden -command .\web-gui.ps1 3 | exit -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pode", 3 | "version": "0.0.0", 4 | "main": "./Web-Pages.ps1", 5 | "scripts": { 6 | "start": "./Web-Pages.ps1", 7 | "install": "", 8 | "test": "", 9 | "build": "" 10 | }, 11 | "dependencies": { 12 | }, 13 | "modules": { 14 | "eps": "0.5.0" 15 | }, 16 | "devModules": { 17 | "pester": "latest" 18 | }, 19 | "author": "Matthew Kelly (Badgerati)", 20 | "license": "MIT" 21 | } 22 | -------------------------------------------------------------------------------- /examples/public/Anger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/examples/public/Anger.jpg -------------------------------------------------------------------------------- /examples/public/Ruler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/examples/public/Ruler.png -------------------------------------------------------------------------------- /examples/public/[brackets].txt: -------------------------------------------------------------------------------- 1 | Brackets test file -------------------------------------------------------------------------------- /examples/public/dummy.txt: -------------------------------------------------------------------------------- 1 | This is just a 2 | 3 | test file for 4 | 5 | 6 | 7 | 8 | 9 | uploading -------------------------------------------------------------------------------- /examples/public/scripts/simple.js: -------------------------------------------------------------------------------- 1 | console.log('hello, world!'); -------------------------------------------------------------------------------- /examples/public/scripts/simple.js.eps: -------------------------------------------------------------------------------- 1 | console.log("<% if ($date.Second % 2 -eq 0) { %>hello, world!<% } else { %>goodbye, world!<% } %>"); -------------------------------------------------------------------------------- /examples/public/scripts/simple.js.pode: -------------------------------------------------------------------------------- 1 | console.log("$( 2 | $date = [DateTime]::UtcNow; 3 | 4 | if ($date.Second % 2 -eq 0) { 5 | "hello, world!"; 6 | } else { 7 | "goodbye, world!"; 8 | } 9 | )"); -------------------------------------------------------------------------------- /examples/public/scripts/simple.js.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Custom script for index.ps1 4 | 5 | .DESCRIPTION 6 | Custom script for index.ps1 7 | 8 | .NOTES 9 | Author: Pode Team 10 | License: MIT License 11 | #> 12 | return (. { 13 | $date = [DateTime]::UtcNow; 14 | 15 | "console.log(`"" 16 | if ($date.Second % 2 -eq 0) { 17 | "hello, world!" 18 | } else { 19 | "goodbye, world!" 20 | } 21 | "`")" 22 | }) -------------------------------------------------------------------------------- /examples/public/scripts/sse.js: -------------------------------------------------------------------------------- 1 | $(document).ready(() => { 2 | $('button#local').off('click').on('click', (e) => { 3 | const sse = new EventSource("/data"); 4 | 5 | sse.addEventListener("Action", (e) => { 6 | $('#messages').append(`

Action: ${e.data}

`); 7 | }); 8 | 9 | sse.addEventListener("BoldOne", (e) => { 10 | $('#messages').append(`

BoldOne: ${e.data}

`); 11 | }); 12 | 13 | sse.addEventListener("pode.close", (e) => { 14 | console.log('CLOSE'); 15 | sse.close(); 16 | }); 17 | 18 | sse.addEventListener("pode.open", (e) => { 19 | var data = JSON.parse(e.data); 20 | console.log(`OPEN: ${data.clientId}`); 21 | }); 22 | 23 | sse.onerror = (e) => { 24 | console.log('ERROR!'); 25 | } 26 | }); 27 | 28 | $('button#global').off('click').on('click', (e) => { 29 | const sse2 = new EventSource("/sse"); 30 | 31 | sse2.onmessage = (e) => { 32 | $('#messages').append(`

${e.data}

`); 33 | }; 34 | 35 | sse2.onerror = (e) => { 36 | console.log('ERROR2!'); 37 | sse.close(); 38 | }; 39 | 40 | sse2.addEventListener("pode.close", (e) => { 41 | console.log('CLOSE'); 42 | sse2.close(); 43 | }); 44 | }); 45 | }) -------------------------------------------------------------------------------- /examples/public/scripts/websockets.js: -------------------------------------------------------------------------------- 1 | $(document).ready(() => { 2 | // create the websocket 3 | var ws = new WebSocket("ws://localhost:8091/"); 4 | 5 | // event for inbound messages to append them 6 | ws.onmessage = function(evt) { 7 | var data = JSON.parse(evt.data) 8 | console.log(data); 9 | $('#messages').append(`

${data.message}

`); 10 | } 11 | 12 | // send message on the socket, to all clients 13 | $('#bc-form').submit(function(e) { 14 | e.preventDefault(); 15 | console.log(`send: ${$('#bc-message').val()}`); 16 | ws.send(JSON.stringify({ message: $('#bc-message').val() })); 17 | $('input[name=message]').val(''); 18 | }) 19 | }) -------------------------------------------------------------------------------- /examples/public/styles/simple.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: rebeccapurple; 3 | } 4 | 5 | a { 6 | color: white; 7 | } 8 | 9 | a:visited { 10 | color: yellow; 11 | } -------------------------------------------------------------------------------- /examples/public/styles/simple.css.eps: -------------------------------------------------------------------------------- 1 | body { 2 | <% if ($date.Second % 2 -eq 0) { %> 3 | background-color: rebeccapurple; 4 | <% } else { %> 5 | background-color: red; 6 | <% } %> 7 | } -------------------------------------------------------------------------------- /examples/public/styles/simple.css.pode: -------------------------------------------------------------------------------- 1 | body { 2 | $( 3 | $date = [DateTime]::UtcNow; 4 | 5 | if ($date.Second % 2 -eq 0) { 6 | "background-color: rebeccapurple;"; 7 | } else { 8 | "background-color: red;"; 9 | } 10 | ) 11 | } -------------------------------------------------------------------------------- /examples/public/styles/simple.css.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Custom script for index.ps1 4 | 5 | .DESCRIPTION 6 | Custom script for index.ps1 7 | 8 | .NOTES 9 | Author: Pode Team 10 | License: MIT License 11 | #> 12 | return (. { 13 | $date = [DateTime]::UtcNow; 14 | 15 | "body {" 16 | if ($date.Second % 2 -eq 0) { 17 | "background-color: rebeccapurple;" 18 | } else { 19 | "background-color: red;" 20 | } 21 | "}" 22 | }) -------------------------------------------------------------------------------- /examples/public/styles/websockets.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: cyan; 3 | } -------------------------------------------------------------------------------- /examples/relative/dot-source-server.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Example of dot-sourcing server logic from a relative path 4 | 5 | .DESCRIPTION 6 | 7 | Example of dot-sourcing server logic from a relative path 8 | 9 | .NOTES 10 | Author: Pode Team 11 | License: MIT License 12 | #> 13 | # example of dot-sourcing server logic from a relative path 14 | . ../web-pages.ps1 -------------------------------------------------------------------------------- /examples/routes/route.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Used by Web-Pages.ps1 using Use-PodeRoutes 4 | 5 | .DESCRIPTION 6 | Used by Web-Pages.ps1 using Use-PodeRoutes 7 | 8 | .NOTES 9 | Author: Pode Team 10 | License: MIT License 11 | #> 12 | Add-PodeRoute -Method Get -Path '/route-file' -ScriptBlock { 13 | Write-PodeJsonResponse -Value @{ Message = "I'm from a route file!" } 14 | } -------------------------------------------------------------------------------- /examples/scripts/routeScript.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Used by Create-Routes.ps1 4 | 5 | .DESCRIPTION 6 | Create-Routes.ps1 7 | 8 | .NOTES 9 | Author: Pode Team 10 | License: MIT License 11 | #> 12 | { 13 | $Id = $WebEvent.Parameters['id'] 14 | Write-PodeJsonResponse -StatusCode 200 -Value @{'id' = $Id } 15 | } -------------------------------------------------------------------------------- /examples/scripts/schedule.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Used by Schedules.ps1 4 | 5 | .DESCRIPTION 6 | Used by Schedules.ps1 7 | 8 | .NOTES 9 | Author: Pode Team 10 | License: MIT License 11 | #> 12 | { 13 | 'Hello, there!' | Out-PodeHost 14 | } -------------------------------------------------------------------------------- /examples/scripts/server.ps1: -------------------------------------------------------------------------------- 1 | { 2 | Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http 3 | New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging 4 | Set-PodeViewEngine -Type Pode 5 | 6 | Add-PodeTimer -Name 'Hi' -Interval 4 -ScriptBlock { 7 | 'Hello from a file!' | Out-PodeHost 8 | } 9 | 10 | Add-PodeRoute -Method Get -Path '/' -ScriptBlock { 11 | Write-PodeViewResponse -Path 'simple' -Data @{ 'numbers' = @(1, 2, 3); } 12 | } 13 | } -------------------------------------------------------------------------------- /examples/scripts/timer.ps1: -------------------------------------------------------------------------------- 1 | { 2 | 'Hello, there!' | Out-PodeHost 3 | } -------------------------------------------------------------------------------- /examples/static/Ruler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/examples/static/Ruler.png -------------------------------------------------------------------------------- /examples/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Static Home Page 4 | 5 | 6 | 7 | 8 | Hello, world! This is static home page! 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/static/public/Anger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/examples/static/public/Anger.jpg -------------------------------------------------------------------------------- /examples/static/public/scripts/simple.js: -------------------------------------------------------------------------------- 1 | console.log('hello, world!'); -------------------------------------------------------------------------------- /examples/static/public/styles/simple.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: rebeccapurple; 3 | } -------------------------------------------------------------------------------- /examples/timers/timer.ps1: -------------------------------------------------------------------------------- 1 | Add-PodeTimer -Name 'imported-timer' -Interval 10 -ScriptBlock { 2 | 'i am imported!' | Out-Default 3 | } -------------------------------------------------------------------------------- /examples/users/users.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Name": "Rick Sanchez", 4 | "Username": "r.sanchez", 5 | "Email": "r.sanchez@sanctum.com", 6 | "Password": "bQik5jDkqg1c2HPmWuoKI99C3mEHPstJ7xcVj+ap3Oo=", 7 | "Groups": [ 8 | "Admin", 9 | "Developer" 10 | ] 11 | } 12 | ] -------------------------------------------------------------------------------- /examples/views/auth-about.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | Auth About 4 | 5 | 6 | 7 | 8 | Hello, this is an about page! 9 |
10 | 11 |

12 | Home 13 | Register 14 |

15 | 16 |
17 |
18 | 19 |
20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/views/auth-home-anon.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | Auth Home 4 | 5 | 6 | 7 | 8 | Hello, there! Welcome to the home page, please login below. 9 | 10 |
11 |
12 | 13 |
14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/views/auth-home.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | Auth Home 4 | 5 | 6 | 7 | 8 | Hello, $($data.Username)! You have view this page $($data.Views) times! 9 |

10 | Your session will expire on $($data.Expiry) 11 |
12 | 13 |

14 | About 15 | Register 16 |

17 | 18 |
19 |
20 | 21 |
22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/views/auth-login.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | Auth Login 4 | 5 | 6 | 7 | 8 | Please Login: 9 | 10 |
11 |
12 | 13 | 14 |
15 |
16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 | 24 | $(if ($Data.flash['auth-error']) { 25 | "

$($Data.flash['auth-error'])

" 26 | }) 27 | 28 | 29 | -------------------------------------------------------------------------------- /examples/views/auth-register.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | Auth Register 4 | 5 | 6 | 7 | 8 | Hello, this is a register page! 9 |
10 | 11 |

12 | Home 13 | About 14 |

15 | 16 |
17 |
18 | 19 |
20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/views/gui.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pode Page 4 | 5 | 6 | 7 | 8 | Hello, world! This is Pode page in a desktop gui! 9 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/views/index-csrf.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | CSRF Example Page 4 | 5 | 6 | 7 |

Example form using a CSRF token

8 |

Clicking submit will just reload the page

9 |
10 | 11 | 12 | 13 |
14 | 15 | 16 |

Example form not using a CSRF token

17 |

Clicking submit will throw a 403 http error

18 |
19 | 20 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/views/index.eps: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pode Page 4 | 5 | 6 | 7 | 8 | Hello, world! This is Pode page! 9 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/views/index.md: -------------------------------------------------------------------------------- 1 | # Home Page 2 | 3 | This is an example page written in markdown. 4 | 5 | ## Look a Header 6 | 7 | * And this is a bullet-point, 8 | * And another, 9 | * And another! 10 | 11 | ## With another Header, Shock 12 | 13 | Even tables work! 14 | 15 | | Names | Universe | 16 | | ----- | -------- | 17 | | Rick | C-157 | 18 | | Morty | C-157 | -------------------------------------------------------------------------------- /examples/views/index.ps1: -------------------------------------------------------------------------------- 1 | param($data) 2 | 3 | return html { 4 | head { 5 | title 'Pode Page' 6 | link -href 'styles/simple.css.ps1' -rel 'stylesheet' -type 'text/css' 7 | script 'scripts/simple.js.ps1' 8 | } 9 | 10 | body { 11 | p { 12 | 'Hello, world! This is Pode page!' 13 | } 14 | 15 | foreach ($i in $data.numbers) { 16 | "
  • value: $i
  • " 17 | } 18 | 19 | img 'Anger.jpg' 20 | } 21 | } -------------------------------------------------------------------------------- /examples/views/simple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | HTML Page 4 | 5 | 6 | 7 | Hello, world! This is an HTML page! 8 | 9 | -------------------------------------------------------------------------------- /examples/views/simple.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pode Page 4 | 5 | 6 | 7 | 8 | Hello, world! This is Pode page! 9 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/views/sse-home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SSE Home 5 | 6 | 7 | 8 | 9 | 10 | 11 |

    Example of using SSE

    12 |

    Messages streamed from a local SSE connection

    13 | 14 | 15 |
    16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/views/web-static.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pode Page 4 | 5 | 6 | 7 | 8 | Hello, world! This is Pode page! 9 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/views/web-upload-multi.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Upload Multiple Files 4 | 5 | 6 | 7 | 8 |
    9 |
    10 | 11 | 12 |
    13 |
    14 | 15 | 16 |
    17 |
    18 | 19 |
    20 |
    21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/views/web-upload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Sign Up 4 | 5 | 6 | 7 | 8 |
    9 |
    10 | 11 | 12 |
    13 |
    14 | 15 | 16 |
    17 |
    18 | 19 |
    20 |
    21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/views/websockets.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | WebSockets 4 | 5 | 6 | 7 | 8 | 9 |

    Example of using a WebSockets

    10 |

    Clicking submit will broadcast the message to all connected clients - try opening this page on multiple, and different, browsers!

    11 |
    12 | 13 | 14 |
    15 | 16 |
    17 | 18 | -------------------------------------------------------------------------------- /examples/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /images/example_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/images/example_code.png -------------------------------------------------------------------------------- /images/example_code_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/images/example_code_2.png -------------------------------------------------------------------------------- /images/icon-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/images/icon-new.png -------------------------------------------------------------------------------- /images/icon-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/images/icon-transparent.png -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/images/icon.png -------------------------------------------------------------------------------- /images/icon_name_bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/images/icon_name_bottom.png -------------------------------------------------------------------------------- /images/icon_name_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/images/icon_name_left.png -------------------------------------------------------------------------------- /licenses/LICENSE.Kerberos.NET.txt: -------------------------------------------------------------------------------- 1 | Project URL: https://github.com/dotnet/Kerberos.NET 2 | 3 | MIT License 4 | 5 | Copyright (c) .NET Foundation and Contributors 6 | All Rights Reserved 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. -------------------------------------------------------------------------------- /licenses/LICENSE.PSYaml.txt: -------------------------------------------------------------------------------- 1 | Project URL: https://github.com/Phil-Factor/PSYaml 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2016 Jakku Labs 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. -------------------------------------------------------------------------------- /licenses/LICENSE.RapiDoc.txt: -------------------------------------------------------------------------------- 1 | Project URL: https://github.com/rapi-doc/RapiDoc 2 | 3 | MIT License 4 | 5 | Copyright (c) 2022 Mrinmoy Majumdar 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the 9 | "Software"), to deal in the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /licenses/LICENSE.RapiPdf.txt: -------------------------------------------------------------------------------- 1 | Project URL: https://github.com/mrin9/RapiPdf 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /licenses/LICENSE.SecretManagement.txt: -------------------------------------------------------------------------------- 1 | Project URL: https://github.com/PowerShell/SecretManagement 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. -------------------------------------------------------------------------------- /licenses/LICENSE.bootstrap.txt: -------------------------------------------------------------------------------- 1 | Project URL: https://github.com/twbs/bootstrap 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2011-2025 The Bootstrap Authors 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. -------------------------------------------------------------------------------- /licenses/LICENSE.highlightjs.txt: -------------------------------------------------------------------------------- 1 | Project URL: https://github.com/highlightjs/highlight.js 2 | 3 | BSD 3-Clause License 4 | 5 | Copyright (c) 2006, Ivan Sagalaev. 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, this 12 | list of conditions and the following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above copyright notice, 15 | this list of conditions and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | * Neither the name of the copyright holder nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /licenses/LICENSE.redoc.txt: -------------------------------------------------------------------------------- 1 | Project URL: https://github.com/Redocly/redoc 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015-present, Rebilly, Inc. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. -------------------------------------------------------------------------------- /mkdocs-overrides/main.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block announce %} 4 | Pode's official documentation is hosted on GitHub. If you're seeing this elsewhere, like readthedocs, please use the docs on GitHub 😊 5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Pode 2 | 3 | theme: 4 | name: material 5 | logo: images/icon-transparent.png 6 | favicon: images/favicon.ico 7 | custom_dir: mkdocs-overrides 8 | features: 9 | - navigation.tabs 10 | - navigation.tabs.sticky 11 | - navigation.tracking 12 | - navigation.top 13 | - content.code.copy 14 | - content.action.edit 15 | - content.action.view 16 | font: 17 | text: Fira Sans 18 | code: Fira Code 19 | palette: 20 | - scheme: default 21 | primary: cyan 22 | accent: cyan 23 | toggle: 24 | icon: material/weather-sunny 25 | name: Light Mode 26 | - scheme: slate 27 | primary: cyan 28 | accent: cyan 29 | toggle: 30 | icon: material/weather-night 31 | name: Dark Mode 32 | 33 | markdown_extensions: 34 | - pymdownx.highlight 35 | - pymdownx.superfences 36 | - pymdownx.tasklist: 37 | custom_checkbox: true 38 | - pymdownx.details 39 | - admonition 40 | - meta 41 | 42 | repo_name: badgerati/pode 43 | repo_url: https://github.com/Badgerati/Pode 44 | edit_uri: edit/master/docs 45 | 46 | extra: 47 | social: 48 | - icon: fontawesome/brands/discord 49 | link: https://discord.gg/fRqeGcbF6h 50 | - icon: fontawesome/brands/github 51 | link: https://github.com/badgerati/pode 52 | - icon: fontawesome/brands/x-twitter 53 | link: https://twitter.com/badgerati 54 | - icon: fontawesome/brands/bluesky 55 | link: https://bsky.app/profile/badgerati.bsky.social 56 | - icon: fontawesome/brands/docker 57 | link: https://hub.docker.com/r/badgerati/pode -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pode", 3 | "description": "Web Component for use with the Pode PowerShell web server", 4 | "repository": "https://github.com/Badgerati/Pode.git", 5 | "author": "Matthew Kelly ", 6 | "license": "MIT", 7 | "dependencies": { 8 | "@highlightjs/cdn-assets": "11.11.1", 9 | "@stoplight/elements": "9.0.1", 10 | "bootstrap": "5.3.5", 11 | "openapi-explorer": "2.2.734", 12 | "rapidoc": "9.3.8", 13 | "rapipdf": "2.2.1", 14 | "redoc": "2.5.0", 15 | "swagger-editor-dist": "4.14.5", 16 | "swagger-ui-dist": "5.21.0" 17 | } 18 | } -------------------------------------------------------------------------------- /packers/choco/VERIFICATION.txt: -------------------------------------------------------------------------------- 1 | VERIFICATION 2 | Verification is intended to assist the Chocolatey moderators and community 3 | in verifying that this package's contents are trustworthy. 4 | 5 | This embedded PowerShell module is packaged and distributed by the author. 6 | 7 | The contents of which can be found on the releases pages at . 8 | 9 | To verify contents, either: 10 | 1. Compare the Checksum on the release notes against the Module's source. 11 | 2. Download the zip from the release, run 'checksum -t sha256' on it, and compare. -------------------------------------------------------------------------------- /packers/choco/tools/ChocolateyUninstall.ps1: -------------------------------------------------------------------------------- 1 | function Remove-PodeModule($path) 2 | { 3 | $path = Join-Path $path 'Pode' 4 | if (Test-Path $path) 5 | { 6 | Write-Host "Deleting module directory: $($path)" 7 | Remove-Item -Path $path -Recurse -Force | Out-Null 8 | if (!$?) { 9 | throw "Failed to delete: $path" 10 | } 11 | } 12 | } 13 | 14 | 15 | 16 | # Determine which Program Files path to use 17 | $progFiles = [string]$env:ProgramFiles 18 | 19 | # Remove PS Module 20 | # Set the module path 21 | $modulePath = Join-Path $progFiles (Join-Path 'WindowsPowerShell' 'Modules') 22 | 23 | # Delete module 24 | Remove-PodeModule $modulePath 25 | 26 | 27 | # Remove PS-Core Module 28 | $def = (Get-Command pwsh -ErrorAction SilentlyContinue).Definition 29 | 30 | if (![string]::IsNullOrWhiteSpace($def)) 31 | { 32 | # Set the module path 33 | $modulePath = Join-Path $progFiles (Join-Path 'PowerShell' 'Modules') 34 | 35 | # Delete module 36 | Remove-PodeModule $modulePath 37 | } 38 | -------------------------------------------------------------------------------- /packers/docker/arm32/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM arm32v7/ubuntu:bionic 2 | 3 | ENV PS_VERSION=7.4.2 4 | ENV PS_PACKAGE=powershell-${PS_VERSION}-linux-arm32.tar.gz 5 | ENV PS_PACKAGE_URL=https://github.com/PowerShell/PowerShell/releases/download/v${PS_VERSION}/${PS_PACKAGE} 6 | 7 | RUN \ 8 | apt-get update \ 9 | && apt-get install --no-install-recommends ca-certificates libunwind8 libssl1.0 libicu60 wget --yes \ 10 | && wget https://github.com/PowerShell/PowerShell/releases/download/v${PS_VERSION}/${PS_PACKAGE} \ 11 | && mkdir ~/powershell \ 12 | && tar -xvf ./${PS_PACKAGE} -C ~/powershell \ 13 | && ln -s /root/powershell/pwsh /usr/bin/pwsh \ 14 | && apt-get clean \ 15 | && rm -rf /var/lib/apt/lists/* 16 | 17 | CMD ["pwsh"] -------------------------------------------------------------------------------- /src/Listener/FileSystemWatcher/EventQueueOverflowException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | // A tweaked version of the FileSystemWatcher from https://github.com/petermeinl/LeanWork.IO.FileSystem.Watcher 4 | namespace Pode.FileSystemWatcher 5 | { 6 | class EventQueueOverflowException : Exception 7 | { 8 | public EventQueueOverflowException() 9 | : base() { } 10 | 11 | public EventQueueOverflowException(string message) 12 | : base(message) { } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Listener/FileSystemWatcher/FileWatcherErrorEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | // A tweaked version of the FileSystemWatcher from https://github.com/petermeinl/LeanWork.IO.FileSystem.Watcher 5 | namespace Pode.FileSystemWatcher 6 | { 7 | public class FileWatcherErrorEventArgs : HandledEventArgs 8 | { 9 | public readonly Exception Error; 10 | 11 | public FileWatcherErrorEventArgs(Exception exception) 12 | { 13 | this.Error = exception; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Listener/NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Listener/Pode.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | $(NoWarn);SYSLIB0001 5 | 7.3 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | $(TargetFrameworks);net8.0 14 | 15 | 16 | 17 | $(TargetFrameworks);net9.0 18 | 19 | 20 | 21 | $(TargetFrameworks);net10.0 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Listener/PodeClientSignal.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Pode 4 | { 5 | public class PodeClientSignal : IDisposable 6 | { 7 | public PodeSignal Signal { get; private set; } 8 | public string Message { get; private set; } 9 | public DateTime Timestamp { get; private set; } 10 | public PodeListener Listener { get; private set; } 11 | 12 | public PodeClientSignal(PodeSignal signal, string message, PodeListener listener) 13 | { 14 | Signal = signal; 15 | Message = message; 16 | Timestamp = DateTime.UtcNow; 17 | Listener = listener; 18 | } 19 | 20 | public void Dispose() 21 | { 22 | Listener.RemoveProcessingClientSignal(this); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/Listener/PodeCompressionType.cs: -------------------------------------------------------------------------------- 1 | namespace Pode 2 | { 3 | public enum PodeCompressionType 4 | { 5 | Gzip, 6 | Deflate 7 | } 8 | } -------------------------------------------------------------------------------- /src/Listener/PodeConnector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace Pode 5 | { 6 | public class PodeConnector : IDisposable 7 | { 8 | public bool IsConnected { get; private set; } 9 | public bool IsDisposed { get; private set; } 10 | public bool ErrorLoggingEnabled { get; set; } 11 | public string[] ErrorLoggingLevels { get; set; } 12 | public CancellationToken CancellationToken { get; private set; } 13 | 14 | public PodeConnector(CancellationToken cancellationToken = default(CancellationToken)) 15 | { 16 | CancellationToken = cancellationToken == default(CancellationToken) 17 | ? cancellationToken 18 | : new CancellationTokenSource().Token; 19 | 20 | IsDisposed = false; 21 | } 22 | 23 | public virtual void Start() 24 | { 25 | IsConnected = true; 26 | } 27 | 28 | protected virtual void Close() 29 | { 30 | throw new NotImplementedException(); 31 | } 32 | 33 | public void Dispose() 34 | { 35 | // stop connecting 36 | IsConnected = false; 37 | 38 | // close 39 | Close(); 40 | 41 | // disposed 42 | IsDisposed = true; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/Listener/PodeContextState.cs: -------------------------------------------------------------------------------- 1 | namespace Pode 2 | { 3 | public enum PodeContextState 4 | { 5 | New, 6 | Open, 7 | Receiving, 8 | Received, 9 | Closing, 10 | Closed, 11 | Error, 12 | Timeout 13 | } 14 | } -------------------------------------------------------------------------------- /src/Listener/PodeFileEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Pode 5 | { 6 | public class PodeFileEvent : IDisposable 7 | { 8 | public PodeFileWatcher FileWatcher { get; private set; } 9 | public PodeFileWatcherChangeType ChangeType { get; private set; } 10 | public string Name { get; private set; } 11 | public string FullPath { get; private set; } 12 | public string OldName { get; private set; } 13 | public string OldFullPath { get; private set; } 14 | 15 | public PodeFileEvent(PodeFileWatcher watcher, FileSystemEventArgs e) 16 | { 17 | FileWatcher = watcher; 18 | ChangeType = MapChangeType(e.ChangeType); 19 | Name = e.Name; 20 | FullPath = e.FullPath; 21 | 22 | if (ChangeType == PodeFileWatcherChangeType.Renamed) 23 | { 24 | var re = e as RenamedEventArgs; 25 | OldName = re.OldName; 26 | OldFullPath = re.OldFullPath; 27 | } 28 | } 29 | 30 | private PodeFileWatcherChangeType MapChangeType(WatcherChangeTypes type) 31 | { 32 | switch (type) 33 | { 34 | case WatcherChangeTypes.All: 35 | return PodeFileWatcherChangeType.Existed; 36 | case WatcherChangeTypes.Changed: 37 | return PodeFileWatcherChangeType.Changed; 38 | case WatcherChangeTypes.Created: 39 | return PodeFileWatcherChangeType.Created; 40 | case WatcherChangeTypes.Deleted: 41 | return PodeFileWatcherChangeType.Deleted; 42 | case WatcherChangeTypes.Renamed: 43 | return PodeFileWatcherChangeType.Renamed; 44 | default: 45 | return PodeFileWatcherChangeType.Errored; 46 | } 47 | } 48 | 49 | public void Dispose() 50 | { 51 | FileWatcher.Watcher.RemoveProcessingFileEvent(this); 52 | FileWatcher = null; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/Listener/PodeFileWatcherChangeType.cs: -------------------------------------------------------------------------------- 1 | namespace Pode 2 | { 3 | public enum PodeFileWatcherChangeType 4 | { 5 | Created, 6 | Changed, 7 | Deleted, 8 | Renamed, 9 | Existed, 10 | Errored 11 | } 12 | } -------------------------------------------------------------------------------- /src/Listener/PodeFormData.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Collections.Generic; 3 | 4 | namespace Pode 5 | { 6 | public class PodeFormData 7 | { 8 | public string Key { get; private set; } 9 | 10 | private IList _values; 11 | public string[] Values => _values.ToArray(); 12 | 13 | public int Count => _values.Count; 14 | public bool IsSingular => _values.Count == 1; 15 | public bool IsEmpty => _values.Count == 0; 16 | 17 | public PodeFormData(string key, string value) 18 | { 19 | Key = key; 20 | 21 | _values = new List 22 | { 23 | value 24 | }; 25 | } 26 | 27 | public void AddValue(string value) 28 | { 29 | _values.Add(value); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/Listener/PodeFormFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Pode 5 | { 6 | public class PodeFormFile : IDisposable 7 | { 8 | public string ContentType { get; private set; } 9 | public string FileName { get; private set; } 10 | public string Name { get; private set; } 11 | public byte[] Bytes => _stream.ToArray(); 12 | 13 | private MemoryStream _stream; 14 | 15 | public PodeFormFile(string fileName, MemoryStream stream, string name, string contentType) 16 | { 17 | ContentType = contentType; 18 | FileName = fileName; 19 | Name = name; 20 | _stream = stream; 21 | } 22 | 23 | public void Save(string path) 24 | { 25 | using (var file = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) 26 | { 27 | _stream.WriteTo(file); 28 | } 29 | } 30 | 31 | public void Dispose() 32 | { 33 | _stream.Dispose(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/Listener/PodeItemQueue.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace Pode 7 | { 8 | public class PodeItemQueue 9 | { 10 | private BlockingCollection Items; 11 | private List ProcessingItems; 12 | 13 | public int Count { get => Items.Count + ProcessingItems.Count; } 14 | public int QueuedCount { get => Items.Count; } 15 | public int ProcessingCount { get => ProcessingItems.Count; } 16 | 17 | public PodeItemQueue() 18 | { 19 | Items = new BlockingCollection(); 20 | ProcessingItems = new List(); 21 | } 22 | 23 | public T Get(CancellationToken cancellationToken = default) 24 | { 25 | var item = Items.Take(cancellationToken == default ? CancellationToken.None : cancellationToken); 26 | 27 | lock (ProcessingItems) 28 | { 29 | ProcessingItems.Add(item); 30 | } 31 | 32 | return item; 33 | } 34 | 35 | public Task GetAsync(CancellationToken cancellationToken = default) 36 | { 37 | return cancellationToken == default 38 | ? Task.Factory.StartNew(() => Get()) 39 | : Task.Factory.StartNew(() => Get(cancellationToken), cancellationToken); 40 | } 41 | 42 | public void Add(T item) 43 | { 44 | lock (Items) 45 | { 46 | Items.Add(item); 47 | } 48 | } 49 | 50 | public void RemoveProcessing(T item) 51 | { 52 | lock (ProcessingItems) 53 | { 54 | ProcessingItems.Remove(item); 55 | } 56 | } 57 | 58 | public T[] ToArray() 59 | { 60 | return Items.ToArray(); 61 | } 62 | 63 | public void Clear() 64 | { 65 | Items = new BlockingCollection(); 66 | ProcessingItems = new List(); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /src/Listener/PodeKerberosAuth.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Security.Claims; 4 | using Kerberos.NET; 5 | using Kerberos.NET.Crypto; 6 | 7 | namespace Pode 8 | { 9 | public class PodeKerberosAuth 10 | { 11 | private string KeytabPath { get; set; } 12 | private KeyTable Keytab { get; set; } 13 | private KerberosAuthenticator Authenticator { get; set; } 14 | private KerberosValidator Validator { get; set; } 15 | 16 | public PodeKerberosAuth(string keytabPath) 17 | { 18 | KeytabPath = keytabPath; 19 | Keytab = new KeyTable(File.ReadAllBytes(KeytabPath)); 20 | Authenticator = new KerberosAuthenticator(Keytab); 21 | 22 | Validator = new KerberosValidator(Keytab) 23 | { 24 | ValidateAfterDecrypt = ValidationActions.Pac 25 | }; 26 | } 27 | 28 | public void Validate(string token) 29 | { 30 | // error if token not provided 31 | if (string.IsNullOrWhiteSpace(token)) 32 | { 33 | throw new ArgumentNullException(nameof(token)); 34 | } 35 | 36 | // trim token and get the last part if it contains spaces 37 | token = token.Trim(); 38 | if (token.IndexOf(' ') >= 1) 39 | { 40 | var split = token.Split(' '); 41 | token = split[split.Length - 1]; 42 | } 43 | 44 | // validate the token 45 | Validator.Validate(Convert.FromBase64String(token)).Wait(); 46 | } 47 | 48 | public ClaimsPrincipal Authenticate(string token) 49 | { 50 | var claims = Authenticator.Authenticate(token); 51 | claims.Wait(); 52 | return new ClaimsPrincipal(claims.Result); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/Listener/PodeLoggingLevel.cs: -------------------------------------------------------------------------------- 1 | namespace Pode 2 | { 3 | public enum PodeLoggingLevel 4 | { 5 | Error, 6 | Warning, 7 | Informational, 8 | Debug, 9 | Verbose 10 | } 11 | } -------------------------------------------------------------------------------- /src/Listener/PodeNative.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Pode 5 | { 6 | public static class NativeMethods 7 | { 8 | // Constants for standard Windows handles 9 | public const int STD_INPUT_HANDLE = -10; 10 | public const int STD_OUTPUT_HANDLE = -11; 11 | public const int STD_ERROR_HANDLE = -12; 12 | 13 | 14 | // Constants for standard UNIX file descriptors 15 | public const int STDIN_FILENO = 0; 16 | public const int STDOUT_FILENO = 1; 17 | public const int STDERR_FILENO = 2; 18 | 19 | 20 | // Import the GetStdHandle function from kernel32.dll 21 | [DllImport("kernel32.dll", SetLastError = true)] 22 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "SYSLIB1054:Use 'LibraryImportAttribute' instead of 'DllImportAttribute' to generate P/Invoke marshalling code at compile time", Justification = "")] 23 | private static extern IntPtr GetStdHandle(int nStdHandle); 24 | 25 | // Helper method to check if a handle is valid 26 | public static bool IsHandleValid(int handleType) 27 | { 28 | IntPtr handle = GetStdHandle(handleType); 29 | return handle != IntPtr.Zero; 30 | } 31 | 32 | 33 | // Import the isatty function from libc 34 | [DllImport("libc")] 35 | private static extern int isatty(int fd); 36 | 37 | // Method to check if a file descriptor is a terminal 38 | public static bool IsTerminal(int fileDescriptor) 39 | { 40 | return isatty(fileDescriptor) == 1; 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/Listener/PodeProtocol.cs: -------------------------------------------------------------------------------- 1 | namespace Pode 2 | { 3 | public class PodeProtocol 4 | { 5 | public PodeProtocolType Type { get; protected set; } 6 | 7 | public bool IsHttp 8 | { 9 | get => Type == PodeProtocolType.Http || Type == PodeProtocolType.HttpAndWs; 10 | } 11 | 12 | public bool IsWebSocket 13 | { 14 | get => Type == PodeProtocolType.Ws || Type == PodeProtocolType.HttpAndWs; 15 | } 16 | 17 | public bool IsSmtp 18 | { 19 | get => Type == PodeProtocolType.Smtp; 20 | } 21 | 22 | public bool IsTcp 23 | { 24 | get => Type == PodeProtocolType.Tcp; 25 | } 26 | 27 | public bool IsUnknown 28 | { 29 | get => Type == PodeProtocolType.Unknown; 30 | } 31 | 32 | public PodeProtocol(PodeProtocolType type = PodeProtocolType.Unknown) 33 | { 34 | Type = type; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/Listener/PodeProtocolType.cs: -------------------------------------------------------------------------------- 1 | namespace Pode 2 | { 3 | public enum PodeProtocolType 4 | { 5 | Unknown, 6 | Http, 7 | Ws, 8 | HttpAndWs, 9 | Smtp, 10 | Tcp 11 | } 12 | } -------------------------------------------------------------------------------- /src/Listener/PodeRequestException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | 4 | namespace Pode 5 | { 6 | public class PodeRequestException : HttpRequestException 7 | { 8 | // the status code of the exception 9 | #if NETCOREAPP2_1_OR_GREATER 10 | public new int StatusCode { get; private set; } = 400; 11 | #else 12 | public int StatusCode { get; private set; } = 400; 13 | #endif 14 | 15 | // is the exception a timeout status code (408? 16 | public bool IsTimeout => StatusCode == 408; 17 | 18 | // is the exception a client error status code (4xx)? 19 | public bool IsClientError => StatusCode >= 400 && StatusCode < 500; 20 | 21 | // is the exception a server error status code (5xx)? 22 | public bool IsServerError => StatusCode >= 500 && StatusCode < 600; 23 | 24 | // the logging level of the exception 25 | public PodeLoggingLevel LoggingLevel => IsClientError ? PodeLoggingLevel.Debug : PodeLoggingLevel.Error; 26 | 27 | 28 | // constructors 29 | public PodeRequestException(int statusCode = default) 30 | : this(string.Empty, null, statusCode) { } 31 | 32 | public PodeRequestException(string message, int statusCode = default) 33 | : this(message, null, statusCode) { } 34 | 35 | public PodeRequestException(Exception exception, int statusCode = default) 36 | : this(exception.Message, exception, statusCode) { } 37 | 38 | public PodeRequestException(string message, Exception innerException, int statusCode = default) 39 | : base(message, innerException) 40 | { 41 | if (statusCode > 0) 42 | { 43 | StatusCode = statusCode; 44 | } 45 | } 46 | 47 | } 48 | } -------------------------------------------------------------------------------- /src/Listener/PodeResponseHeaders.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Pode 5 | { 6 | public class PodeResponseHeaders 7 | { 8 | public object this[string name] 9 | { 10 | get => (Headers.ContainsKey(name) ? Headers[name][0] : string.Empty); 11 | set => Set(name, value); 12 | } 13 | 14 | public int Count => Headers.Count; 15 | public ICollection Keys => Headers.Keys; 16 | 17 | private IDictionary> Headers; 18 | 19 | public PodeResponseHeaders() 20 | { 21 | Headers = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); 22 | } 23 | 24 | public bool ContainsKey(string name) 25 | { 26 | return Headers.ContainsKey(name); 27 | } 28 | 29 | public IList Get(string name) 30 | { 31 | return Headers.ContainsKey(name) ? Headers[name] : default(IList); 32 | } 33 | 34 | public void Set(string name, object value) 35 | { 36 | if (!Headers.ContainsKey(name)) 37 | { 38 | Headers.Add(name, new List()); 39 | } 40 | 41 | Headers[name].Clear(); 42 | Headers[name].Add(value); 43 | } 44 | 45 | public void Add(string name, object value) 46 | { 47 | if (!Headers.ContainsKey(name)) 48 | { 49 | Headers.Add(name, new List()); 50 | } 51 | 52 | Headers[name].Add(value); 53 | } 54 | 55 | public void Remove(string name) 56 | { 57 | if (Headers.ContainsKey(name)) 58 | { 59 | Headers.Remove(name); 60 | } 61 | } 62 | 63 | public void Clear() 64 | { 65 | Headers.Clear(); 66 | } 67 | 68 | } 69 | } -------------------------------------------------------------------------------- /src/Listener/PodeServerEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace Pode 5 | { 6 | public class PodeServerEvent : IDisposable 7 | { 8 | public PodeContext Context { get; private set; } 9 | public string Name { get; private set; } 10 | public string Group { get; private set; } 11 | public string ClientId { get; private set; } 12 | public DateTime Timestamp { get; private set; } 13 | 14 | public PodeServerEvent(PodeContext context, string name, string group, string clientId) 15 | { 16 | Context = context; 17 | Name = name; 18 | Group = group; 19 | ClientId = clientId; 20 | Timestamp = DateTime.UtcNow; 21 | } 22 | 23 | public bool IsForGroup(string[] groups) 24 | { 25 | if (groups == default(string[]) || groups.Length == 0) 26 | { 27 | return true; 28 | } 29 | 30 | if (string.IsNullOrEmpty(Group)) 31 | { 32 | return false; 33 | } 34 | 35 | return groups.Any(x => x.Equals(Group, StringComparison.OrdinalIgnoreCase)); 36 | } 37 | 38 | public void Dispose() 39 | { 40 | Context.Dispose(true); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/Listener/PodeServerState.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// Represents the various states a Pode server can be in. 3 | /// 4 | namespace Pode 5 | { 6 | /// 7 | /// Enum for defining the states of the Pode server. 8 | /// 9 | public enum PodeServerState 10 | { 11 | /// 12 | /// The server has been completely terminated and is no longer running. 13 | /// 14 | Terminated, 15 | 16 | /// 17 | /// The server is in the process of terminating and shutting down its operations. 18 | /// 19 | Terminating, 20 | 21 | /// 22 | /// The server is resuming from a suspended state and is starting to run again. 23 | /// 24 | Resuming, 25 | 26 | /// 27 | /// The server is in the process of suspending its operations. 28 | /// 29 | Suspending, 30 | 31 | /// 32 | /// The server is currently suspended and not processing any requests. 33 | /// 34 | Suspended, 35 | 36 | /// 37 | /// The server is in the process of restarting its operations. 38 | /// 39 | Restarting, 40 | 41 | /// 42 | /// The server is starting its operations. 43 | /// 44 | Starting, 45 | 46 | /// 47 | /// The server is running and actively processing requests. 48 | /// 49 | Running 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Listener/PodeSignal.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Pode 4 | { 5 | public class PodeSignal : IDisposable 6 | { 7 | public PodeContext Context { get; private set; } 8 | public string Path { get; private set; } 9 | public string ClientId { get; private set; } 10 | public DateTime Timestamp { get; private set; } 11 | 12 | public PodeSignal(PodeContext context, string path, string clientId) 13 | { 14 | Context = context; 15 | Path = path; 16 | ClientId = clientId; 17 | Timestamp = DateTime.UtcNow; 18 | } 19 | 20 | public void Dispose() 21 | { 22 | Context.Dispose(true); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/Listener/PodeSmtpAttachment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Pode 5 | { 6 | public class PodeSmtpAttachment : IDisposable 7 | { 8 | public string Name { get; private set; } 9 | public string ContentType { get; private set; } 10 | public string ContentEncoding { get; private set; } 11 | public byte[] Bytes => _stream.ToArray(); 12 | 13 | private MemoryStream _stream; 14 | 15 | public PodeSmtpAttachment(string name, MemoryStream stream, string contentType, string contentEncoding) 16 | { 17 | Name = name; 18 | ContentType = contentType; 19 | ContentEncoding = contentEncoding; 20 | _stream = stream; 21 | } 22 | 23 | public void Save(string path, bool addNameToPath = true) 24 | { 25 | if (addNameToPath) 26 | { 27 | path = Path.Combine(path, Name); 28 | } 29 | 30 | using (var file = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) 31 | { 32 | _stream.WriteTo(file); 33 | } 34 | } 35 | 36 | public void Dispose() 37 | { 38 | _stream.Dispose(); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/Listener/PodeSmtpCommand.cs: -------------------------------------------------------------------------------- 1 | namespace Pode 2 | { 3 | public enum PodeSmtpCommand 4 | { 5 | None, 6 | Ehlo, 7 | Helo, 8 | Data, 9 | Quit, 10 | StartTls, 11 | RcptTo, 12 | MailFrom, 13 | NoOp, 14 | Reset 15 | } 16 | } -------------------------------------------------------------------------------- /src/Listener/PodeSmtpStartType.cs: -------------------------------------------------------------------------------- 1 | namespace Pode 2 | { 3 | public enum PodeSmtpStartType 4 | { 5 | None, 6 | Helo, 7 | Ehlo 8 | } 9 | } -------------------------------------------------------------------------------- /src/Listener/PodeSseScope.cs: -------------------------------------------------------------------------------- 1 | namespace Pode 2 | { 3 | public enum PodeSseScope 4 | { 5 | None, 6 | Local, 7 | Global 8 | } 9 | } -------------------------------------------------------------------------------- /src/Listener/PodeStreamState.cs: -------------------------------------------------------------------------------- 1 | namespace Pode 2 | { 3 | public enum PodeStreamState 4 | { 5 | New, 6 | Open, 7 | Closed, 8 | Error 9 | } 10 | } -------------------------------------------------------------------------------- /src/Listener/PodeTlsMode.cs: -------------------------------------------------------------------------------- 1 | namespace Pode 2 | { 3 | public enum PodeTlsMode 4 | { 5 | Implicit, 6 | Explicit 7 | } 8 | } -------------------------------------------------------------------------------- /src/Listener/PodeWebSocketCloseFrom.cs: -------------------------------------------------------------------------------- 1 | namespace Pode 2 | { 3 | public enum PodeWebSocketCloseFrom 4 | { 5 | Client, 6 | Server 7 | } 8 | } -------------------------------------------------------------------------------- /src/Listener/PodeWebSocketRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.IO; 4 | 5 | namespace Pode 6 | { 7 | public class PodeWebSocketRequest : IDisposable 8 | { 9 | 10 | public PodeWebSocket WebSocket { get; private set; } 11 | public byte[] RawBody { get; private set; } 12 | public Encoding ContentEncoding = new UTF8Encoding(); 13 | 14 | public int ContentLength 15 | { 16 | get => RawBody == default(byte[]) ? 0 : RawBody.Length; 17 | } 18 | 19 | private string _body = string.Empty; 20 | public string Body 21 | { 22 | get 23 | { 24 | if (RawBody != default(byte[]) && RawBody.Length > 0) 25 | { 26 | _body = Encoding.UTF8.GetString(RawBody); 27 | } 28 | 29 | return _body; 30 | } 31 | } 32 | 33 | public PodeWebSocketRequest(PodeWebSocket webSocket, MemoryStream bytes) 34 | { 35 | WebSocket = webSocket; 36 | RawBody = bytes.ToArray(); 37 | } 38 | 39 | public void Dispose() 40 | { 41 | WebSocket.Receiver.RemoveProcessingWebSocketRequest(this); 42 | RawBody = default; 43 | _body = string.Empty; 44 | } 45 | 46 | } 47 | } -------------------------------------------------------------------------------- /src/Listener/PodeWsOpCode.cs: -------------------------------------------------------------------------------- 1 | namespace Pode 2 | { 3 | public enum PodeWsOpCode 4 | { 5 | Continuation = 0, 6 | Text = 1, 7 | Binary = 2, 8 | Close = 8, 9 | Ping = 9, 10 | Pong = 10 11 | } 12 | } -------------------------------------------------------------------------------- /src/Misc/default-error-page.html.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $($data.status.code) 5 | 6 | 7 | 8 | 9 | 10 |
    11 |

    15 | $(if ($data.status.code -eq 418) { 16 | "☕ " 17 | } 18 | else { 19 | "⚠️ " 20 | }) 21 | $($data.status.description) 22 |

    23 |
    24 |

    25 | $($data.status.code) 26 |

    27 |

    28 | $($data.url) 29 |

    30 | 31 | $(if ($null -ne $data.exception) { 32 | "
    43 | $($data.exception.message)
    44 | $($data.exception.line)
    45 | $($data.exception.stacktrace)
    46 |     + $($data.exception.category)
    47 |                 
    " 48 | }) 49 |
    50 | 51 |

    56 | 🧡 Powered by Pode 57 |

    58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/Misc/default-error-page.json.pode: -------------------------------------------------------------------------------- 1 | $( 2 | $data.Remove('ContentType'); 3 | $data | ConvertTo-Json; 4 | ) -------------------------------------------------------------------------------- /src/Misc/default-error-page.xml.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | $($data.status.code) 4 | $($data.status.description) 5 | 6 | $($data.url) 7 | 8 | $( 9 | if ($data.exception) { 10 | " 11 | $($data.exception.message) 12 | $($data.exception.stacktrace) 13 | $($data.exception.line) 14 | $($data.exception.category) 15 | " 16 | } 17 | ) 18 | 19 | -------------------------------------------------------------------------------- /src/Misc/default-explorer.html.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | $($data.Title) 8 | 9 | 10 | 11 | 12 | 44 | 45 | 46 | 47 | 48 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/Misc/default-rapidoc.html.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $($data.Title) 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Misc/default-redoc.html.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $($data.Title) 5 | 6 | 7 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Misc/default-stoplight.html.pode: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | $($data.Title) 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Misc/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/src/Misc/favicon.ico -------------------------------------------------------------------------------- /src/Pode.Internal.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Internal module manifest for module 'Pode' 3 | # 4 | # Generated by: Matthew Kelly (Badgerati) 5 | # 6 | # Generated on: 24/01/2023 7 | # 8 | 9 | @{ 10 | # Script module or binary module file associated with this manifest. 11 | RootModule = 'Pode.Internal.psm1' 12 | 13 | # Version number of this module. 14 | ModuleVersion = '$version$' 15 | 16 | # ID used to uniquely identify this module 17 | GUID = '86b48c1c-8b59-4f3c-80bb-936d6b3218f6' 18 | 19 | # Author of this module 20 | Author = 'Matthew Kelly (Badgerati)' 21 | 22 | # Minimum version of the Windows PowerShell engine required by this module 23 | PowerShellVersion = '5.1' 24 | 25 | } -------------------------------------------------------------------------------- /src/Pode.Internal.psm1: -------------------------------------------------------------------------------- 1 | # root path 2 | $root = Split-Path -Parent -Path $MyInvocation.MyCommand.Path 3 | 4 | # import everything 5 | $sysfuncs = Get-ChildItem Function: 6 | 7 | # load private functions 8 | Get-ChildItem "$($root)/Private/*.ps1" | ForEach-Object { . ([System.IO.Path]::GetFullPath($_)) } 9 | 10 | # load public functions 11 | Get-ChildItem "$($root)/Public/*.ps1" | ForEach-Object { . ([System.IO.Path]::GetFullPath($_)) } 12 | 13 | # get functions from memory and compare to existing to find new functions added 14 | $funcs = Get-ChildItem Function: | Where-Object { $sysfuncs -notcontains $_ } 15 | 16 | # export the module's public functions 17 | Export-ModuleMember -Function ($funcs.Name) -------------------------------------------------------------------------------- /src/Private/Access.ps1: -------------------------------------------------------------------------------- 1 | function Get-PodeAccessMiddlewareScript { 2 | return { 3 | param($opts) 4 | 5 | if ($null -eq $WebEvent.Auth) { 6 | Set-PodeResponseStatus -Code 403 7 | return $false 8 | } 9 | 10 | # test access 11 | $WebEvent.Auth.IsAuthorised = Invoke-PodeAccessValidation -Name $opts.Name 12 | 13 | # 403 if unauthorised 14 | if (!$WebEvent.Auth.IsAuthorised) { 15 | Set-PodeResponseStatus -Code 403 16 | } 17 | 18 | # run next middleware or stop? 19 | return $WebEvent.Auth.IsAuthorised 20 | } 21 | } 22 | 23 | function Invoke-PodeAccessValidation { 24 | param( 25 | [Parameter(Mandatory = $true)] 26 | [string] 27 | $Name 28 | ) 29 | 30 | # get the access method 31 | $access = $PodeContext.Server.Authorisations.Methods[$Name] 32 | 33 | # if it's a merged access, re-call this function and check against "succeed" value 34 | if ($access.Merged) { 35 | foreach ($accName in $access.Access) { 36 | $result = Invoke-PodeAccessValidation -Name $accName 37 | 38 | # if the access passed, and we only need one access to pass, return true 39 | if ($result -and $access.PassOne) { 40 | return $true 41 | } 42 | 43 | # if the access failed, but we need all to pass, return false 44 | if (!$result -and !$access.PassOne) { 45 | return $false 46 | } 47 | } 48 | 49 | # if the last access failed, and we only need one access to pass, return false 50 | if (!$result -and $access.PassOne) { 51 | return $false 52 | } 53 | 54 | # if the last access succeeded, and we need all to pass, return true 55 | if ($result -and !$access.PassOne) { 56 | return $true 57 | } 58 | 59 | # default failure 60 | return $false 61 | } 62 | 63 | # main access validation logic 64 | return (Test-PodeAccessRoute -Name $Name) 65 | } -------------------------------------------------------------------------------- /src/Private/Endware.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-PodeEndware { 2 | param( 3 | [Parameter()] 4 | $Endware 5 | ) 6 | 7 | # if there's no endware, do nothing 8 | if (($null -eq $Endware) -or ($Endware.Length -eq 0)) { 9 | return 10 | } 11 | 12 | # loop through each of the endware, invoking the next if it returns true 13 | foreach ($eware in @($Endware)) { 14 | if (($null -eq $eware) -or ($null -eq $eware.Logic)) { 15 | continue 16 | } 17 | 18 | try { 19 | $null = Invoke-PodeScriptBlock -ScriptBlock $eware.Logic -Arguments $eware.Arguments -UsingVariables $eware.UsingVariables -Scoped -Splat 20 | } 21 | catch { 22 | $_ | Write-PodeErrorLog 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/Private/Events.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-PodeEvent { 2 | param( 3 | [Parameter(Mandatory = $true)] 4 | [Pode.PodeServerEventType] 5 | $Type 6 | ) 7 | 8 | # do nothing if no events 9 | if (($null -eq $PodeContext.Server.Events) -or ($PodeContext.Server.Events[$Type.ToString()].Count -eq 0)) { 10 | return 11 | } 12 | 13 | # invoke each event's scriptblock 14 | foreach ($evt in $PodeContext.Server.Events[$Type.ToString()].Values) { 15 | if (($null -eq $evt) -or ($null -eq $evt.ScriptBlock)) { 16 | continue 17 | } 18 | 19 | try { 20 | $null = Invoke-PodeScriptBlock -ScriptBlock $evt.ScriptBlock -Arguments $evt.Arguments -UsingVariables $evt.UsingVariables -Scoped -Splat 21 | } 22 | catch { 23 | $_ | Write-PodeErrorLog 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/Private/NameGenerator.ps1: -------------------------------------------------------------------------------- 1 | function Get-PodeRandomName { 2 | $adjs = @( 3 | 'admiring', 4 | 'agitated', 5 | 'blissful', 6 | 'dazzling', 7 | 'ecstatic', 8 | 'eloquent', 9 | 'friendly', 10 | 'gracious', 11 | 'hardcore', 12 | 'laughing', 13 | 'peaceful', 14 | 'pedantic', 15 | 'reverent', 16 | 'romantic', 17 | 'trusting', 18 | 'vigilant', 19 | 'vigorous', 20 | 'wizardly', 21 | 'youthful' 22 | ) 23 | 24 | $names = @( 25 | 'almeida', 26 | 'babbage', 27 | 'bardeen', 28 | 'shannon', 29 | 'davinci', 30 | 'feynman', 31 | 'galileo', 32 | 'goodall', 33 | 'hawking', 34 | 'hermann', 35 | 'hodgkin', 36 | 'hypatia', 37 | 'jackson', 38 | 'johnson', 39 | 'kapitsa', 40 | 'keldysh', 41 | 'khorana', 42 | 'lalande', 43 | 'lamport', 44 | 'leavitt', 45 | 'lumiere', 46 | 'mcnulty', 47 | 'meitner', 48 | 'mestorf', 49 | 'murdock', 50 | 'neumann', 51 | 'noether', 52 | 'pasteur', 53 | 'perlman', 54 | 'poitras', 55 | 'ptolemy', 56 | 'ritchie', 57 | 'shirley', 58 | 'swanson', 59 | 'swirles', 60 | 'vaughan', 61 | 'volhard', 62 | 'villani', 63 | 'wescoff', 64 | 'wozniak' 65 | ) 66 | 67 | $adjsRand = (Get-Random -Minimum 0 -Maximum $adjs.Length) 68 | $namesRand = (Get-Random -Minimum 0 -Maximum $names.Length) 69 | 70 | return "$($adjs[$adjsRand])_$($names[$namesRand])" 71 | } -------------------------------------------------------------------------------- /src/Private/ServiceServer.ps1: -------------------------------------------------------------------------------- 1 | function Start-PodeServiceServer { 2 | # ensure we have service handlers 3 | if (Test-PodeIsEmpty (Get-PodeHandler -Type Service)) { 4 | # No Service handlers have been defined 5 | throw ($PodeLocale.noServiceHandlersDefinedExceptionMessage) 6 | } 7 | 8 | # state we're running 9 | # Server looping every $PodeContext.Server.Interval secs 10 | Write-PodeHost ($PodeLocale.serverLoopingMessage -f $PodeContext.Server.Interval) -ForegroundColor Yellow 11 | 12 | # script for the looping server 13 | $serverScript = { 14 | 15 | try { 16 | while (!(Test-PodeCancellationTokenRequest -Type Terminate)) { 17 | # the event object 18 | $script:ServiceEvent = @{ 19 | Lockable = $PodeContext.Threading.Lockables.Global 20 | Metadata = @{} 21 | } 22 | 23 | # invoke the service handlers 24 | $handlers = Get-PodeHandler -Type Service 25 | foreach ($name in $handlers.Keys) { 26 | $handler = $handlers[$name] 27 | $null = Invoke-PodeScriptBlock -ScriptBlock $handler.Logic -Arguments $handler.Arguments -UsingVariables $handler.UsingVariables -Scoped -Splat 28 | } 29 | 30 | # sleep before next run 31 | Start-Sleep -Seconds $PodeContext.Server.Interval 32 | } 33 | } 34 | catch [System.OperationCanceledException] { 35 | $_ | Write-PodeErrorLog -Level Debug 36 | } 37 | catch { 38 | $_ | Write-PodeErrorLog 39 | throw $_.Exception 40 | } 41 | } 42 | 43 | # start the runspace for the server 44 | Add-PodeRunspace -Type Main -Name 'ServiceServer' -ScriptBlock $serverScript 45 | } -------------------------------------------------------------------------------- /tests/integration/Timers.Tests.ps1: -------------------------------------------------------------------------------- 1 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] 2 | param() 3 | 4 | Describe 'Timers' { 5 | 6 | BeforeAll { 7 | $Port = 8080 8 | $Endpoint = "http://127.0.0.1:$($Port)" 9 | 10 | Start-Job -Name 'Pode' -ErrorAction Stop -ScriptBlock { 11 | Import-Module -Name "$($using:PSScriptRoot)\..\..\src\Pode.psm1" 12 | 13 | Start-PodeServer -RootPath $using:PSScriptRoot -Quiet -ScriptBlock { 14 | Add-PodeEndpoint -Address localhost -Port $using:Port -Protocol Http 15 | 16 | New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging 17 | Add-PodeRoute -Method Get -Path '/close' -ScriptBlock { 18 | Close-PodeServer 19 | } 20 | 21 | Set-PodeState -Name 'Test1' -Value 0 22 | Add-PodeTimer -Name 'Test1' -Interval 1 -ScriptBlock { 23 | Set-PodeState -Name 'Test1' -Value 1337 24 | } 25 | 26 | Add-PodeRoute -Method Get -Path '/test1' -ScriptBlock { 27 | Invoke-PodeTimer -Name 'Test1' 28 | Write-PodeJsonResponse -Value @{ Result = (Get-PodeState -Name 'Test1') } 29 | } 30 | } 31 | } 32 | 33 | Start-Sleep -Seconds 10 34 | } 35 | 36 | AfterAll { 37 | Receive-Job -Name 'Pode' | Out-Default 38 | Invoke-RestMethod -Uri "$($Endpoint)/close" -Method Get | Out-Null 39 | Get-Job -Name 'Pode' | Remove-Job -Force 40 | } 41 | 42 | 43 | It 'timer updates state value' { 44 | $result = Invoke-RestMethod -Uri "$($Endpoint)/test1" -Method Get 45 | $result.Result | Should -Be 1337 46 | } 47 | } -------------------------------------------------------------------------------- /tests/integration/images/custom_ruler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/tests/integration/images/custom_ruler.png -------------------------------------------------------------------------------- /tests/integration/public/ruler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Badgerati/Pode/f940490890fc5a8d0652e245504d0b3a6f8451ee/tests/integration/public/ruler.png -------------------------------------------------------------------------------- /tests/integration/views/dynamic.pode: -------------------------------------------------------------------------------- 1 |

    $($data.Date)

    -------------------------------------------------------------------------------- /tests/integration/views/static.html: -------------------------------------------------------------------------------- 1 |

    2020-01-01

    -------------------------------------------------------------------------------- /tests/perf/README.md: -------------------------------------------------------------------------------- 1 | # Perf Tests 2 | 3 | These tests run using a tool called [k6](https://k6.readme.io/docs/welcome), and scripts are written in ES6 JavaScript to define individual User Scenarios. You can tell `k6` to run using a number of Virtual Users over a defined Duration, or you can specify stages to ramp up/down the number of Virtual Users over a period of time. 4 | 5 | ## Installing 6 | 7 | To install `k6` and run the tests locally, you can run the following command: 8 | 9 | * Windows 10 | 11 | ```powershell 12 | choco install k6 -y 13 | ``` 14 | 15 | * Linux 16 | 17 | ```bash 18 | sudo curl -OL https://github.com/loadimpact/k6/releases/download/v0.20.0/k6-v0.20.0-linux64.tar.gz 19 | sudo tar -xzf k6-v0.20.0-linux64.tar.gz 20 | sudo cp k6-v0.20.0-linux64/k6 /usr/local/bin 21 | ``` 22 | 23 | After this, all `k6` commands are identical on Windows and Linux. 24 | 25 | ## Running 26 | 27 | You can run `k6` against your local environment by using the following command (powershell/batch or bash): 28 | 29 | ```bash 30 | k6 run -u 10 -d 10s ./basic/root.js 31 | ``` 32 | 33 | This will run k6 with 10 virtual users (`-u 10`) over 10 seconds (`-d 10s`). -------------------------------------------------------------------------------- /tests/perf/basic/css_style.js: -------------------------------------------------------------------------------- 1 | import http from "k6/http"; 2 | import { group } from "k6"; 3 | import { urlbase, check_response, call_endpoint } from "../utils/common.js"; 4 | import { call_root } from "../basic/root.js"; 5 | 6 | // exported: retrieve a css style 7 | export function retrieve_css_style() { 8 | return call_endpoint(`${urlbase}/styles/simple.css`); 9 | }; 10 | 11 | // exercise calling the root and getting a css style 12 | export default function() { 13 | group("css_and_root", function() { 14 | var res = call_root(); 15 | check_response(res, { duration: 500, status: 200 }); 16 | 17 | res = retrieve_css_style(); 18 | check_response(res, { duration: 300, status: 200 }); 19 | }); 20 | }; -------------------------------------------------------------------------------- /tests/perf/basic/full_flow.js: -------------------------------------------------------------------------------- 1 | import http from "k6/http"; 2 | import { group } from "k6"; 3 | import { urlbase, check_response, call_endpoint } from "../utils/common.js"; 4 | import { call_root } from "../basic/root.js"; 5 | import { retrieve_image } from "../basic/image.js"; 6 | import { retrieve_css_style } from "../basic/css_style.js"; 7 | 8 | // exercise calling the root and getting an image 9 | export default function() { 10 | group("full_flow", function() { 11 | var res = call_root(); 12 | check_response(res, { duration: 500, status: 200 }); 13 | 14 | res = retrieve_css_style(); 15 | check_response(res, { duration: 300, status: 200 }); 16 | 17 | res = retrieve_image(); 18 | check_response(res, { duration: 1000, status: 200 }); 19 | }); 20 | }; -------------------------------------------------------------------------------- /tests/perf/basic/image.js: -------------------------------------------------------------------------------- 1 | import http from "k6/http"; 2 | import { group } from "k6"; 3 | import { urlbase, check_response, call_endpoint } from "../utils/common.js"; 4 | import { call_root } from "../basic/root.js"; 5 | 6 | // exported: retrieve an image file 7 | export function retrieve_image() { 8 | return call_endpoint(`${urlbase}/Anger.jpg`); 9 | }; 10 | 11 | // exercise calling the root and getting an image 12 | export default function() { 13 | group("image_and_root", function() { 14 | var res = call_root(); 15 | check_response(res, { duration: 500, status: 200 }); 16 | 17 | res = retrieve_image(); 18 | check_response(res, { duration: 1000, status: 200 }); 19 | }); 20 | }; -------------------------------------------------------------------------------- /tests/perf/basic/root.js: -------------------------------------------------------------------------------- 1 | import http from "k6/http"; 2 | import { group } from "k6"; 3 | import { urlbase, check_response, call_endpoint } from "../utils/common.js"; 4 | 5 | // exported: hit the root url 6 | export function call_root() { 7 | return call_endpoint(`${urlbase}`); 8 | }; 9 | 10 | // exercise calling the root url 11 | export default function() { 12 | group("root_url", function() { 13 | var res = call_root(); 14 | check_response(res, { duration: 500, status: 200 }); 15 | }); 16 | }; -------------------------------------------------------------------------------- /tests/perf/utils/common.js: -------------------------------------------------------------------------------- 1 | import http from "k6/http"; 2 | import { check } from "k6"; 3 | 4 | export let urlbase = 'http://127.0.0.1:8090'; 5 | 6 | export function check_response(res, opts) { 7 | opts = (opts || { duration: 800, status: 200 }); 8 | opts.duration = (opts.duration || 800); 9 | opts.status = (opts.status || 200); 10 | 11 | let checks = {}; 12 | checks[`Status is ${opts.status}`] = (res) => res.status === opts.status; 13 | checks[`Duration OK (<${opts.duration}ms)`] = (res) => res.timings.duration < opts.duration; 14 | 15 | return check(res, checks); 16 | }; 17 | 18 | export function call_endpoint(url, name) { 19 | name = (name || url); 20 | return http.get(url, { tags: { "name": name } }); 21 | } -------------------------------------------------------------------------------- /tests/shared/TestHelper.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Ensures the Pode assembly is loaded into the current session. 4 | 5 | .DESCRIPTION 6 | This function checks if the Pode assembly is already loaded into the current PowerShell session. 7 | If not, it determines the appropriate .NET runtime version and attempts to load the Pode.dll 8 | from the most compatible directory. If no specific version is found, it defaults to netstandard2.0. 9 | 10 | .PARAMETER SrcPath 11 | The base path where the Pode library (Libs folder) is located. 12 | 13 | .EXAMPLE 14 | Import-PodeAssembly -SrcPath 'C:\Projects\MyApp' 15 | Ensures that Pode.dll is loaded from the appropriate .NET folder. 16 | 17 | .NOTES 18 | Ensure that the Pode library path is correctly structured with folders named 19 | `netstandard2.0`, `net6.0`, etc., inside the `Libs` folder. 20 | #> 21 | function Import-PodeAssembly { 22 | param ( 23 | [Parameter(Mandatory = $true)] 24 | [string]$SrcPath 25 | ) 26 | 27 | # Check if Pode is already loaded 28 | if (!([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq 'Pode' })) { 29 | # Fetch the .NET runtime version 30 | $version = [System.Environment]::Version.Major 31 | $libsPath = Join-Path -Path $SrcPath -ChildPath 'Libs' 32 | 33 | # Filter .NET DLL folders based on version and get the latest one 34 | $netFolder = if (![string]::IsNullOrWhiteSpace($version)) { 35 | Get-ChildItem -Path $libsPath -Directory -Force | 36 | Where-Object { $_.Name -imatch "net[1-$($version)]" } | 37 | Sort-Object -Property Name -Descending | 38 | Select-Object -First 1 -ExpandProperty FullName 39 | } 40 | 41 | # Use netstandard2.0 if no folder found 42 | if ([string]::IsNullOrWhiteSpace($netFolder)) { 43 | $netFolder = Join-Path -Path $libsPath -ChildPath 'netstandard2.0' 44 | } 45 | 46 | # Append Pode.dll and mount 47 | Add-Type -LiteralPath (Join-Path -Path $netFolder -ChildPath 'Pode.dll') -ErrorAction Stop 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/unit/NameGenerator.Tests.ps1: -------------------------------------------------------------------------------- 1 | BeforeAll { 2 | $path = $PSCommandPath 3 | $src = (Split-Path -Parent -Path $path) -ireplace '[\\/]tests[\\/]unit', '/src/' 4 | Get-ChildItem "$($src)/*.ps1" -Recurse | Resolve-Path | ForEach-Object { . $_ } 5 | Import-LocalizedData -BindingVariable PodeLocale -BaseDirectory (Join-Path -Path $src -ChildPath 'Locales') -FileName 'Pode' 6 | } 7 | 8 | Describe 'Get-PodeRandomName' { 9 | 10 | 11 | It 'Returns correct name' { 12 | Mock 'Get-Random' { return 0 } 13 | Get-PodeRandomName | Should -Be 'admiring_almeida' 14 | } 15 | } --------------------------------------------------------------------------------