diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..96c2e0d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,15 @@ +# Needed for publishing of examples, build worker defaults to core.autocrlf=input. +* text eol=autocrlf + +*.mof text eol=crlf +*.sh text eol=lf +*.svg eol=lf + +# Ensure any exe files are treated as binary +*.exe binary +*.jpg binary +*.xl* binary +*.pfx binary +*.png binary +*.dll binary +*.so binary diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..134e9b5 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,50 @@ +# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners +# Each line is a file pattern followed by one or more owners. + +# These owners will be the default owners for everything in +# the repo. Unless a later match takes precedence, +# @global-owner1 and @global-owner2 will be requested for +# review when someone opens a pull request. +* @PSModule/module-maintainers + +# Order is important; the last matching pattern takes the most +# precedence. When someone opens a pull request that only +# modifies JS files, only @js-owner and not the global +# owner(s) will be requested for a review. +# *.js @js-owner + +# You can also use email addresses if you prefer. They'll be +# used to look up users just like we do for commit author +# emails. +# *.go docs@example.com + +# Teams can be specified as code owners as well. Teams should +# be identified in the format @org/team-name. Teams must have +# explicit write access to the repository. In this example, +# the octocats team in the octo-org organization owns all .txt files. +# *.txt @octo-org/octocats + +# In this example, @doctocat owns any files in the build/logs +# directory at the root of the repository and any of its +# subdirectories. +# /build/logs/ @doctocat + +# The `docs/*` pattern will match files like +# `docs/getting-started.md` but not further nested files like +# `docs/build-app/troubleshooting.md`. +# docs/* docs@example.com + +# In this example, @octocat owns any file in an apps directory +# anywhere in your repository. +# apps/ @octocat + +# In this example, @doctocat owns any file in the `/docs` +# directory in the root of your repository and any of its +# subdirectories. +# /docs/ @doctocat + +# In this example, @octocat owns any file in the `/apps` +# directory in the root of your repository except for the `/apps/github` +# subdirectory, as its owners are left empty. +# /apps/ @octocat +# /apps/github diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..b92544a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: github-actions # See documentation for possible values + directory: / # Location of package manifests + schedule: + interval: weekly + - package-ecosystem: nuget # See documentation for possible values + directory: / # Location of package manifests + schedule: + interval: weekly diff --git a/.github/linters/.markdown-lint.yml b/.github/linters/.markdown-lint.yml new file mode 100644 index 0000000..e8b1717 --- /dev/null +++ b/.github/linters/.markdown-lint.yml @@ -0,0 +1,16 @@ +########################### +## Markdown Linter rules ## +########################### + +# Linter rules doc: +# - https://github.com/DavidAnson/markdownlint + +############### +# Rules by id # +############### + + +################# +# Rules by tags # +################# + diff --git a/.github/linters/.powershell-psscriptanalyzer.psd1 b/.github/linters/.powershell-psscriptanalyzer.psd1 new file mode 100644 index 0000000..8d3d2cc --- /dev/null +++ b/.github/linters/.powershell-psscriptanalyzer.psd1 @@ -0,0 +1,15 @@ +#Documentation: https://github.com/PowerShell/PSScriptAnalyzer/blob/master/docs/Cmdlets/Invoke-ScriptAnalyzer.md#-settings +@{ + #CustomRulePath='path\to\CustomRuleModule.psm1' + #RecurseCustomRulePath='path\of\customrules' + #Severity = @( + # 'Error' + # 'Warning' + #) + #IncludeDefaultRules=${true} + #ExcludeRules = @() + #IncludeRules = @( + # 'PSAvoidUsingWriteHost', + # 'MyCustomRuleName' + #) +} diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..35c6ae8 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,18 @@ +# https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#configuring-automatically-generated-release-notes + +changelog: + exclude: + labels: + - NoRelease + categories: + - title: 🌟 Breaking Changes + labels: + - Major + - Breaking + - title: 🚀 New Features + labels: + - Minor + - Feature + - title: Other Changes + labels: + - '*' diff --git a/.github/workflows/Linter.yml b/.github/workflows/Linter.yml new file mode 100644 index 0000000..5c9f300 --- /dev/null +++ b/.github/workflows/Linter.yml @@ -0,0 +1,29 @@ +name: Linter + +run-name: "Linter - [${{ github.event.pull_request.title }} #${{ github.event.pull_request.number }}] by @${{ github.actor }}" + +on: [pull_request] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + packages: read + statuses: write + +jobs: + Lint: + name: Lint code base + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Lint code base + uses: super-linter/super-linter@latest + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/Process-PSModule.yml b/.github/workflows/Process-PSModule.yml new file mode 100644 index 0000000..43ca948 --- /dev/null +++ b/.github/workflows/Process-PSModule.yml @@ -0,0 +1,28 @@ +name: Process-PSModule + +run-name: "Process-PSModule - [${{ github.event.pull_request.title }} #${{ github.event.pull_request.number }}] by @${{ github.actor }}" + +on: + pull_request: + branches: + - main + types: + - closed + - opened + - reopened + - synchronize + - labeled + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: write + pull-requests: write + statuses: write + +jobs: + Process-PSModule: + uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@v1 + secrets: inherit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2d1f8d --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/* + +# PSModule framework outputs folder +outputs/* diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..92f4384 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 PSModule + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..36b835e --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# PSWinBGP + +WinBGP remote management module. + +## Prerequisites + +No prerequisites. + +## Installation + +To install the module and class run the following command: + +```powershell +Install-Module -Name PSWinBGP +Import-Module -Name PSWinBGP +``` + +## Usage + +Here is a list of example that are typical use cases for the module. +This section should provide a good overview of the module's capabilities. + +### Get WinBGPRoute + +```powershell +Get WinBGPRoute +``` + +## Contributing + +Coder or not, you can contribute to the project! We welcome all contributions. + +### For Users + +If you don't code, you still sit on valuable information that can make this project even better. If you experience that the +product does unexpected things, throw errors or is missing functionality, you can help by submitting bugs and feature requests. +Please see the issues tab on this project and submit a new issue that matches your needs. + +### For Developers + +If you do code, we'd love to have your contributions. Please read the [Contribution guidelines](CONTRIBUTING.md) for more information. +You can either help by picking up an existing issue or submit a new one if you have an idea for a new feature or improvement. + +## Links + +- [Semantic Versioning 2.0.0](https://semver.org/) diff --git a/src/PSWinBGP.psd1 b/src/PSWinBGP.psd1 new file mode 100644 index 0000000..d2e888e --- /dev/null +++ b/src/PSWinBGP.psd1 @@ -0,0 +1,129 @@ +# +# Module manifest for module 'PSWinBGP' +# + +@{ + +# Script module or binary module file associated with this manifest. +RootModule = 'PSWinBGP.psm1' + +# Version number of this module. +ModuleVersion = '0.1.0' + +# Supported PSEditions +CompatiblePSEditions = @('PSEdition_Desktop','PSEdition_Core','Windows','Linux','MacOS') + +# ID used to uniquely identify this module +GUID = 'a7c4be44-95a4-45d3-bcb3-c9f3deb1d7d4' + +# Author of this module +Author = 'Alexandre JARDON' + +# Company or vendor of this module +CompanyName = 'Webalex System' + +# Copyright statement for this module +Copyright = '(c) webalexeu. All rights reserved.' + +# Description of the functionality provided by this module +Description = 'WinBGP Remote Management' + +# Minimum version of the PowerShell engine required by this module +PowerShellVersion = '5.1' + +# Name of the PowerShell host required by this module +# PowerShellHostName = '' + +# Minimum version of the PowerShell host required by this module +# PowerShellHostVersion = '' + +# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# DotNetFrameworkVersion = '' + +# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# ClrVersion = '' + +# Processor architecture (None, X86, Amd64) required by this module +# ProcessorArchitecture = '' + +# Modules that must be imported into the global environment prior to importing this module +# RequiredModules = @() + +# Assemblies that must be loaded prior to importing this module +# RequiredAssemblies = @() + +# Script files (.ps1) that are run in the caller's environment prior to importing this module. +# ScriptsToProcess = @() + +# Type files (.ps1xml) to be loaded when importing this module +# TypesToProcess = @() + +# Format files (.ps1xml) to be loaded when importing this module +# FormatsToProcess = @() + +# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess +# NestedModules = @() + +# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. +FunctionsToExport = @('Get-WinBGPRoute','Start-WinBGPRoute','Stop-WinBGPRoute','Start-WinBGPRouteMaintenance','Stop-WinBGPRouteMaintenance') + +# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. +# CmdletsToExport = '*' + +# Variables to export from this module +# VariablesToExport = '*' + +# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. +# AliasesToExport = '*' + +# DSC resources to export from this module +# DscResourcesToExport = @() + +# List of all modules packaged with this module +# ModuleList = @() + +# List of all files packaged with this module +# FileList = @() + +# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. +PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + Tags = @('winbgp','bgp') + + # A URL to the license for this module. + LicenseUri = 'https://github.com/webalexeu/pswinbgp/blob/master/LICENSE' + + # A URL to the main website for this project. + ProjectUri = 'https://github.com/webalexeu/pswinbgp' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + # Prerelease string of this module + # Prerelease = '' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + RequireLicenseAcceptance = $false + + # External dependent modules of this module + # ExternalModuleDependencies = @() + + } # End of PSData hashtable + +} # End of PrivateData hashtable + +# HelpInfo URI of this module +# HelpInfoURI = '' + +# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. +# DefaultCommandPrefix = '' + +} + + diff --git a/src/PSWinBGP.psm1 b/src/PSWinBGP.psm1 new file mode 100644 index 0000000..a762ce0 --- /dev/null +++ b/src/PSWinBGP.psm1 @@ -0,0 +1,45 @@ +# Dot source public/private functions +$public = @(Get-ChildItem -Path (Join-Path -Path $PSScriptRoot -ChildPath 'Public/*.ps1') -Recurse -ErrorAction Stop) +$private = @(Get-ChildItem -Path (Join-Path -Path $PSScriptRoot -ChildPath 'Private/*.ps1') -Recurse -ErrorAction Stop) +foreach ($import in @($public + $private)) { + try { + . $import.FullName + } catch { + throw "Unable to dot source [$($import.FullName)]" + } +} + +Export-ModuleMember -Function $public.Basename + +# Route Argument Completer +$ArgumentCompleterBlock = { + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + + # Dynamically generate routes array + if ($FakeBoundParameters.ComputerName) { + [Array] $routes = (Get-WinBGPRoute -ComputerName $FakeBoundParameters.ComputerName) + } else { + [Array] $routes = (Get-WinBGPRoute) + } + # Return routes as arguments (Intellisense) + $routes | ForEach-Object { + New-Object -Type System.Management.Automation.CompletionResult -ArgumentList $_.Name, + #"$($_.ComputerName)_$($_.Name)", + "$(if ($_.ComputerName){"ComputerName: '$($_.ComputerName)' - RouteName: '$($_.Name)'"}else{$_.Name})", + "ParameterValue", + "$(if ($_.ComputerName){"ComputerName: '$($_.ComputerName)' - "})Network: '$($_.Network)' - Status: '$($_.Status)'" + } +} +Register-ArgumentCompleter -CommandName Start-WinBGPRoute,Stop-WinBGPRoute,Start-WinBGPRouteMaintenance,Stop-WinBGPRouteMaintenance -ParameterName RouteName -ScriptBlock $ArgumentCompleterBlock + +# Declare a module-level variable +$PSWinBGP = [ordered]@{ + LocalhostApiPort = 8888 + LocalhostApiProtocol = 'http' + LocalhostApiTimeout = 5 + ApiPort = 8888 + ApiProtocol = 'https' + ApiTimeout = 10 +} +New-Variable -Name PSWinBGP -Value $PSWinBGP -Scope Script -Force + diff --git a/src/Private/Invoke-PSWinBGP.ps1 b/src/Private/Invoke-PSWinBGP.ps1 new file mode 100644 index 0000000..aae560c --- /dev/null +++ b/src/Private/Invoke-PSWinBGP.ps1 @@ -0,0 +1,212 @@ +function Invoke-PSWinBGP() { + <# + .SYNOPSIS + Inkoke WinBGP + .DESCRIPTION + Inkoke WinBGP using local method or API + .PARAMETER ComputerName + Single or multiple ComputerName (Default: localhost) + .EXAMPLE + Invoke-PSWinBGP -ComputerName machine1,machine2 -Call routes + # Get WinBGP status (Display WinBGP routes status) + #> + + Param( + [Parameter(Mandatory=$true)] + [String[]]$ComputerName, + [Parameter(ParameterSetName='call',Mandatory=$true)] + [String]$Call, # Call to perform + [Parameter(Mandatory=$false)] + [String]$RouteName # Select route to control + ) + + if ($ComputerName -eq 'local') { + switch ($call) { + 'routes' { Invoke-Command {WinBGP} } + 'startroute' { Send-WinBGPRouteControl -RouteName $RouteName -Control 'start' } + 'stoproute' { Send-WinBGPRouteControl -RouteName $RouteName -Control 'stop'} + 'startmaintenance' { Send-WinBGPRouteControl -RouteName $RouteName -Control 'start' -Action 'maintenance' } + 'stopmaintenance' { Send-WinBGPRouteControl -RouteName $RouteName -Control 'stop' -Action 'maintenance' } + } + } else { + if ($ComputerName -eq 'localhost') { + [Int]$Port=$Script:PSWinBGP.LocalhostApiPort + [String]$Protocol=$Script:PSWinBGP.LocalhostApiProtocol + [Int]$Timeout=$Script:PSWinBGP.LocalhostApiTimeout + } else { + [Int]$Port=$Script:PSWinBGP.ApiPort + [String]$Protocol=$Script:PSWinBGP.ApiProtocol + [Int]$Timeout=$Script:PSWinBGP.ApiTimeout + } + + # Initialize output variable + $Output=@() + $ErrorOutput=@() + # Initialize error variable + $ErrorCount=0 + + ForEach ($Computer in $ComputerName) { + # Initialize output variable + $ApiOutput = [PSCustomObject]@{} + $ErrorOut = [PSCustomObject]@{} + $ApiDefaultRequestURL="$($Protocol)://$($Computer):$($Port)/api" + $params = @{} + $params.add('UseBasicParsing', $true) + $params.add('TimeoutSec', $Timeout) + $params.add('ContentType','application/json') + $params.add('UseDefaultCredentials', $true) + + # Get + if ($call -eq 'routes') { + $ApiRequestURL="$ApiDefaultRequestURL/routes" + } + # Post + if (($call -eq 'startmaintenance') -or ($call -eq 'stopmaintenance') -or ($call -eq 'startroute') -or ($call -eq 'stoproute')) { + $ApiRequestMethod='Post' + if ($call -eq 'startmaintenance') { + $ApiRequestURL="$ApiDefaultRequestURL/startmaintenance?routename=$RouteName" + } + if ($call -eq 'stopmaintenance') { + $ApiRequestURL="$ApiDefaultRequestURL/stopmaintenance?routename=$RouteName" + } + if ($call -eq 'startroute') { + $ApiRequestURL="$ApiDefaultRequestURL/startroute?routename=$RouteName" + } + if ($call -eq 'stoproute') { + $ApiRequestURL="$ApiDefaultRequestURL/stoproute?routename=$RouteName" + } + } + # Test if target is reachable + if ($PSVersionTable.PSVersion.Major -ge 7) { + $ConnectivityTest=(Test-Connection -TcpPort $Port -TimeoutSeconds $Timeout -TargetName $Computer -Quiet) + $params.add('SkipHttpErrorCheck', $true) + $params.add('StatusCodeVariable', 'StatusCode') + } else { + if ($ComputerName -eq 'localhost') { + # Bypass connectivity test when localhost (For speed performance) + $ConnectivityTest=$true + } else { + $ConnectivityTest=(Test-NetConnection -ComputerName $computer -Port $port).TcpTestSucceeded + } + } + if ($ConnectivityTest) { + $params.add('uri',$ApiRequestURL) + if ($ApiRequestMethod) { + $params.add('Method',$ApiRequestMethod) + } + # Perform Rest API Call + if ($PSVersionTable.PSVersion.Major -ge 7) { + $RestApiCall=Invoke-RestMethod @params + } else { + # Try/catch because PS5 don't support status code and skip http error check + Try { + $RestApiCall=Invoke-RestMethod @params + } Catch { + $ErrorOut | Add-member -MemberType NoteProperty -Name 'Result' -Value "API call error: $($_)" + $ErrorCount++ + } + } + + if ($RestApiCall) { + $ApiOutput=$RestApiCall + $ErrorOut | Add-member -MemberType NoteProperty -Name 'Result' -Value 'API connection OK' + } else { + if ($StatusCode) { + $ErrorOut | Add-member -MemberType NoteProperty -Name 'Result' -Value "API return code: $([System.Net.HttpStatusCode]$StatusCode) ($StatusCode)" + $ErrorCount++ + } else { + if ($PSVersionTable.PSVersion.Major -ge 7) { + $ErrorOut | Add-member -MemberType NoteProperty -Name 'Result' -Value 'API call timeout' + $ErrorCount++ + } + } + } + } else { + $ErrorOut | Add-member -MemberType NoteProperty -Name 'Result' -Value 'API connection timeout' + $ErrorCount++ + } + # Add ComputerName variable to output (except for localhost) + if ($Computer -ne 'localhost') { + $ApiOutput | Add-member -MemberType NoteProperty -Name 'ComputerName' -Value "$Computer" + } + $Output+=$ApiOutput + # Add ComputerName variable to output (except for localhost) + if ($Computer -ne 'localhost') { + $ErrorOut | Add-member -MemberType NoteProperty -Name 'ComputerName' -Value "$Computer" + } + $ErrorOutput+=$ErrorOut + } + + # If there is connection error, just return connection table + if ($ErrorCount -eq 0) { + # Return result + return [PSCustomObject]$Output + } else { + return [PSCustomObject]$ErrorOutput + } + } +} + +# IPC communication with WinBGP-Engine +Function Send-WinBGPPipeMessage () { + Param( + [Parameter(Mandatory=$true)] + [String]$PipeName, # Named pipe name + [Parameter(Mandatory=$true)] + [String]$Message # Message string + ) + $PipeDir = [System.IO.Pipes.PipeDirection]::Out + $PipeOpt = [System.IO.Pipes.PipeOptions]::Asynchronous + + $pipe = $null # Named pipe stream + $sw = $null # Stream Writer + try { + $pipe = new-object System.IO.Pipes.NamedPipeClientStream(".", $PipeName, $PipeDir, $PipeOpt) + $sw = new-object System.IO.StreamWriter($pipe) + $pipe.Connect(1000) + if (!$pipe.IsConnected) { + throw "Failed to connect client to pipe $pipeName" + } + $sw.AutoFlush = $true + $sw.WriteLine($Message) + } catch { + Write-Log "Error sending pipe $pipeName message: $_" -Level Error + } finally { + if ($sw) { + $sw.Dispose() # Release resources + $sw = $null # Force the PowerShell garbage collector to delete the .net object + } + if ($pipe) { + $pipe.Dispose() # Release resources + $pipe = $null # Force the PowerShell garbage collector to delete the .net object + } + } + } + +function Send-WinBGPRouteControl { + param ( + [Parameter(Mandatory=$false)] + [String]$Action='route', # Action + [Parameter(Mandatory=$true)] + [String]$RouteName, # Route Name + [Parameter(Mandatory=$true)] + [String]$Control # Control + ) + $PipeStatus=$null + # Performing Action + try { + # Temporary + $pipeName='Service_WinBGP' + $Message="$($Action) $($RouteName) $($Control)" + Send-WinBGPPipeMessage -PipeName $pipeName -Message $Message + } + catch { + $PipeStatus=($_).ToString() + } + if ($PipeStatus -like "*Pipe hasn't been connected yet*") { + return "WinBGP not ready" + } else { + # TO BE IMPROVED to get status + return "Success" + } +} diff --git a/src/Public/Get-WinBGPRoute.ps1 b/src/Public/Get-WinBGPRoute.ps1 new file mode 100644 index 0000000..0128cdd --- /dev/null +++ b/src/Public/Get-WinBGPRoute.ps1 @@ -0,0 +1,19 @@ +function Get-WinBGPRoute() { + <# + .SYNOPSIS + Get WinBGP Route + .DESCRIPTION + This function retrieve WinBGP Routes + .PARAMETER ComputerName + Single or multiple ComputerName (Default: localhost) + .EXAMPLE + Get-WinBGPRoute -ComputerName machine1,machine2 + #> + + Param( + [Parameter(Mandatory=$false)] + [String[]]$ComputerName='local' + ) + + Invoke-PSWinBGP -ComputerName $ComputerName -Call 'routes' +} diff --git a/src/Public/Set-PSWinBGPConfig.ps1 b/src/Public/Set-PSWinBGPConfig.ps1 new file mode 100644 index 0000000..0198eea --- /dev/null +++ b/src/Public/Set-PSWinBGPConfig.ps1 @@ -0,0 +1,49 @@ +function Set-PSWinBGPConfig { + <# + .SYNOPSIS + Set PSWinBBGP module configuration. + + .DESCRIPTION + Set PSWinBBGP module configuration, and $PSWinBBGP module variable. + + .PARAMETER ApiPort + Api Port (Default: 8888) + + .PARAMETER ApiProtocol + Api Protocol (Default: https) + + .PARAMETER ApiTimeout + Api Timeout (Default: 10s) + + .PARAMETER LocalhostApiPort + Localhost Api Port (Default: 8888) + + .PARAMETER LocalhostApiProtocol + Localhost Api Protocol (Default: http) + + .PARAMETER LocalhostApiTimeout + Localhost Api Timeout (Default: 5s) + + #> + [CmdletBinding(SupportsShouldProcess=$true)] + param( + [Int]$ApiPort, + [string]$ApiProtocol, + [Int]$ApiTimeout, + [Int]$LocalhostApiPort, + [string]$LocalhostApiProtocol, + [Int]$LocalhostApiTimeout + ) + + if ($pscmdlet.ShouldProcess('$Script:PSWinBGP','Set config')) { + Switch ($PSBoundParameters.Keys) + { + 'ApiPort' { $Script:PSWinBGP.ApiPort = $ApiPort } + 'ApiProtocol' { $Script:PSWinBGP.ApiProtocol = $ApiProtocol } + 'ApiTimeout' { $Script:PSWinBGP.ApiTimeout = $ApiTimeout } + 'LocalhostApiPort' { $Script:PSWinBGP.LocalhostApiPort = $LocalhostApiPort } + 'LocalhostApiProtocol' { $Script:PSWinBGP.LocalhostApiProtocol = $LocalhostApiProtocol } + 'LocalhostApiTimeout' { $Script:PSWinBGP.LocalhostApiTimeout = $LocalhostApiTimeout } + } + } +} diff --git a/src/Public/Start-WinBGPRoute.ps1 b/src/Public/Start-WinBGPRoute.ps1 new file mode 100644 index 0000000..d0b9738 --- /dev/null +++ b/src/Public/Start-WinBGPRoute.ps1 @@ -0,0 +1,25 @@ +function Start-WinBGPRoute() { + <# + .SYNOPSIS + WinBGP Remote Management - Route + .DESCRIPTION + WinBGP Remote Management + .PARAMETER ComputerName + Single or multiple ComputerName (Default: localhost) + .EXAMPLE + Get-WinBGPRoute -ComputerName machine1,machine2 + # Get WinBGP route + #> + + [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] + Param( + [Parameter(Mandatory=$false)] + [String[]]$ComputerName='local', + [Parameter(Mandatory=$true)] + [String]$RouteName + ) + # If action is confirmed + if ($pscmdlet.ShouldProcess($RouteName,'Start route')) { + Invoke-PSWinBGP -ComputerName $ComputerName -call 'startroute' -RouteName $RouteName + } +} diff --git a/src/Public/Start-WinBGPRouteMaintenance.ps1 b/src/Public/Start-WinBGPRouteMaintenance.ps1 new file mode 100644 index 0000000..ae2a87a --- /dev/null +++ b/src/Public/Start-WinBGPRouteMaintenance.ps1 @@ -0,0 +1,25 @@ +function Start-WinBGPRouteMaintenance() { + <# + .SYNOPSIS + WinBGP Remote Management - Route + .DESCRIPTION + WinBGP Remote Management + .PARAMETER ComputerName + Single or multiple ComputerName (Default: localhost) + .EXAMPLE + Get-WinBGPRoute -ComputerName machine1,machine2 + # Get WinBGP route + #> + + [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] + Param( + [Parameter(Mandatory=$false)] + [String[]]$ComputerName='local', + [Parameter(Mandatory=$true)] + [String]$RouteName + ) + + if ($pscmdlet.ShouldProcess($RouteName,'Start route maintenance')) { + Invoke-PSWinBGP -ComputerName $ComputerName -call 'startmaintenance' -routename $RouteName + } +} diff --git a/src/Public/Stop-WinBGPRoute.ps1 b/src/Public/Stop-WinBGPRoute.ps1 new file mode 100644 index 0000000..4383487 --- /dev/null +++ b/src/Public/Stop-WinBGPRoute.ps1 @@ -0,0 +1,24 @@ +function Stop-WinBGPRoute() { + <# + .SYNOPSIS + WinBGP Remote Management - Route + .DESCRIPTION + WinBGP Remote Management + .PARAMETER ComputerName + Single or multiple ComputerName (Default: localhost) + .EXAMPLE + Get-WinBGPRoute -ComputerName machine1,machine2 + # Get WinBGP route + #> + + [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] + Param( + [Parameter(Mandatory=$false)] + [String[]]$ComputerName='local', + [Parameter(Mandatory=$true)] + [String]$RouteName + ) + if ($pscmdlet.ShouldProcess($RouteName,'Stop route')) { + Invoke-PSWinBGP -ComputerName $ComputerName -call 'stoproute' -routename $RouteName + } +} diff --git a/src/Public/Stop-WinBGPRouteMaintenance.ps1 b/src/Public/Stop-WinBGPRouteMaintenance.ps1 new file mode 100644 index 0000000..a853335 --- /dev/null +++ b/src/Public/Stop-WinBGPRouteMaintenance.ps1 @@ -0,0 +1,24 @@ +function Stop-WinBGPRouteMaintenance() { + <# + .SYNOPSIS + WinBGP Remote Management - Route + .DESCRIPTION + WinBGP Remote Management + .PARAMETER ComputerName + Single or multiple ComputerName (Default: localhost) + .EXAMPLE + Get-WinBGPRoute -ComputerName machine1,machine2 + # Get WinBGP route + #> + + [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] + Param( + [Parameter(Mandatory=$false)] + [String[]]$ComputerName='local', + [Parameter(Mandatory=$true)] + [String]$RouteName + ) + if ($pscmdlet.ShouldProcess($RouteName,'Stop route maintenance')) { + Invoke-PSWinBGP -ComputerName $ComputerName -call 'stopmaintenance' -routename $RouteName + } +}