Datto.DBPool.API.psm1
#Region function Set-DBPoolApiParameter { <# .SYNOPSIS The Set-DBPoolApiParameter function is used to set parameters for the Datto DBPool API. .DESCRIPTION The Set-DBPoolApiParameter function is used to set the API URL and API Key for the Datto DBPool API. .PARAMETER base_uri Provide the URL of the Datto DBPool API. The default value is https://dbpool.datto.net. .PARAMETER apiKey Provide Datto DBPool API Key for authorization. You can find your user API key at [ /web/self ](https://dbpool.datto.net/web/self). .PARAMETER Force Force the operation without confirmation. .INPUTS [Uri] - The base URL of the DBPool API. [SecureString] - The API key for the DBPool. .OUTPUTS [void] - No output is returned. .EXAMPLE Set-DBPoolApiParameter Sets the default base URI and prompts for the API Key. .EXAMPLE Set-DBPoolApiParameter -base_uri "https://dbpool.example.com" -apiKey $secureString Sets the base URI to https://dbpool.example.com and sets the API Key. .NOTES See Datto DBPool API help files for more information. .LINK N/A #> [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')] [OutputType([void])] Param( [Parameter(Position = 0, Mandatory = $False, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True, HelpMessage = "Provide the base URL of the DBPool API.")] [Uri]$base_uri = "https://dbpool.datto.net", [Parameter(Position = 1, Mandatory = $True, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True, HelpMessage = "Provide Datto DBPool API Key for authorization.")] [securestring]$apiKey, [Parameter(Position = 2, Mandatory = $False, HelpMessage = "Force the operation without confirmation.")] [switch]$Force ) Begin { # Cast URI Variable to string type [String]$base_uri = $base_uri.AbsoluteUri # Check for trailing slash and remove if present $base_uri = $base_uri.TrimEnd('/') # Check to replace existing variables if ((Get-Variable -Name DBPool_Base_URI -ErrorAction SilentlyContinue) -and (Get-Variable -Name DBPool_ApiKey -ErrorAction SilentlyContinue)) { if (-not ($Force -or $PSCmdlet.ShouldContinue("Variables 'DBPool_Base_URI' and '$DBPool_ApiKey' already exist. Do you want to replace them?", "Confirm overwrite"))) { Write-Warning "Existing variables were not replaced." break } } } Process { # Set or replace the parameters try { Add-DBPoolBaseURI -base_uri $base_uri -Verbose:$PSBoundParameters.ContainsKey('Verbose') -ErrorAction Stop Add-DBPoolAPIKey -apiKey $apiKey -Verbose:$PSBoundParameters.ContainsKey('Verbose') -ErrorAction Stop } catch { Write-Error $_ } } End {} } #EndRegion #Region function Test-DBPoolApi { <# .SYNOPSIS Checks the availability of the DBPool API using an HTTP HEAD request. .DESCRIPTION This function sends an HTTP HEAD request to the specified API URL using Invoke-WebRequest. Checks if the HTTP status code is 200, indicating that the API is available. .PARAMETER base_uri The base URL of the API to be checked. .PARAMETER resource_Uri The URI of the API resource to be checked. The default value is '/api/docs/openapi.json'. .PARAMETER ApiKey Optional: Access token for authorization. .INPUTS [string] - The base URI for the DBPool API connection. [SecureString] - The API key for the DBPool. .OUTPUTS [System.Boolean] - Returns $true if the API is available, $false if not. .EXAMPLE Test-DBPoolApi -base_uri "https://api.example.com" Checks the availability of the API at https://api.example.com #> [CmdletBinding()] [OutputType([System.Boolean], ParameterSetName = "API_Available")] param ( [Parameter(Position = 0, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True, HelpMessage = "The URL of the API to be checked.")] [string]$base_uri = $DBPool_Base_URI, [Parameter(Position = 1, Mandatory = $false)] [string]$resource_Uri = '/api/docs/openapi.json', [Parameter(Position = 2, Mandatory = $false, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True, HelpMessage = "API Key for authorization.")] [securestring]$apiKey = $DBPool_ApiKey ) begin { # Check if API Parameters are set Write-Debug -Message "Api URL is $base_uri" Write-Debug -Message "Api Key is $DBPool_ApiKey" if (!($base_uri -and $apiKey)) { Write-Warning "API parameters are missing. Please run Set-DBPoolApiParameters first!" #break } # Sets the variable for the document URI to check, filtered to replace ending with /v2 with openapi docs #$base_uri = $base_uri.TrimEnd('/') # Use 'Add-DBPoolBaseURI' to remove superfluous trailing slashes Add-DBPoolBaseURI -base_uri $base_uri #$apiUri = $base_uri + $resource_Uri } process { Write-Verbose -Message "Checking API availability for URL $apiUri" try { Invoke-DBPoolRequest -Method 'HEAD' -resource_Uri $resource_Uri -ErrorAction Stop | Out-Null $true } catch { if ($_.Exception.Response.StatusCode -ne 200) { Write-Error $_.Exception.Message $false } } } end {} } #EndRegion #Region function ConvertTo-DBPoolQueryString { <# .SYNOPSIS Converts uri filter parameters As of June 2024, DBPool does not support any query parameters. This is only provided to allow forward compatibility .DESCRIPTION The ConvertTo-DBPoolQueryString cmdlet converts & formats uri filter parameters from a function which are later used to make the full resource uri for an API call This is an internal helper function the ties in directly with the Invoke-DBPoolRequest & any public functions that define parameters As of June 2024, DBPool does not support any query parameters. This is only provided to allow forward compatibility .PARAMETER uri_Filter Hashtable of values to combine a functions parameters with the resource_Uri parameter. This allows for the full uri query to occur As of June 2024, DBPool does not support any query parameters. This is only provided to allow forward compatibility .PARAMETER resource_Uri Defines the short resource uri (url) to use when creating the API call .INPUTS [hashtable] - uri_Filter .OUTPUTS [System.UriBuilder] - uri_Request .EXAMPLE ConvertTo-DBPoolQueryString -uri_Filter $uri_Filter -resource_Uri '/api/v2/containers' Example: (From public function) $uri_Filter = @{} ForEach ( $Key in $PSBoundParameters.GetEnumerator() ){ if( $excludedParameters -contains $Key.Key ){$null} else{ $uri_Filter += @{ $Key.Key = $Key.Value } } } 1x key = https://api.DBPool.com/v1/api/v2/containers?parentId=12345 2x key = https://api.DBPool.com/v1/api/v2/containers?parentId=12345&power=True .NOTES N/A .LINK N/A #> [CmdletBinding()] [OutputType([System.UriBuilder])] param( [Parameter(Mandatory = $false, ValueFromPipeline = $true)] [hashtable]$uri_Filter, [Parameter(Mandatory = $true)] [String]$resource_Uri ) begin {} process { $excludedParameters = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable', 'allPages', 'page', 'perPage' $query_Parameters = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) if ($uri_Filter) { ForEach ( $Key in $uri_Filter.GetEnumerator() ) { if ( $excludedParameters -contains $Key.Key ){$null} elseif ( $Key.Value.GetType().IsArray ) { Write-Verbose "[ $($Key.Key) ] is an array parameter" foreach ($Value in $Key.Value) { $query_Parameters.Add($Key.Key, $Value) } } else { $query_Parameters.Add($Key.Key, $Key.Value) } } } # Build the request and load it with the query string. $uri_Request = [System.UriBuilder]($DBPool_Base_URI + $resource_Uri) $uri_Request.Query = $query_Parameters.ToString() # Return the full uri $uri_Request } end {} } #EndRegion #Region function Get-DBPoolMetaData { <# .SYNOPSIS Gets various API metadata values .DESCRIPTION The Get-DBPoolMetaData cmdlet gets various API metadata values from an Invoke-WebRequest to assist in various troubleshooting scenarios such as rate-limiting. .PARAMETER base_uri Define the base URI for the DBPool API connection using Datto's DBPool URI or a custom URI. The default base URI is https://dbpool.datto.net .PARAMETER resource_uri Define the resource URI for the DBPool API connection. The default resource URI is /api/v2/self .INPUTS [string] - base_uri .OUTPUTS [PSCustomObject] - Various API metadata values .EXAMPLE Get-DBPoolMetaData Gets various API metadata values from an Invoke-WebRequest to assist in various troubleshooting scenarios such as rate-limiting. The default full base uri test path is: https://dbpool.datto.net .EXAMPLE Get-DBPoolMetaData -base_uri http://dbpool.example.com Gets various API metadata values from an Invoke-WebRequest to assist in various troubleshooting scenarios such as rate-limiting. The full base uri test path in this example is: http://dbpool.example.com/device .NOTES N/A .LINK N/A #> [CmdletBinding()] [OutputType([PSCustomObject])] Param ( [parameter(Mandatory = $false, ValueFromPipeline = $true)] [string]$base_uri = $DBPool_Base_URI, [string]$resource_uri = '/api/v2/self' ) begin { $method = 'GET' } process { try { $api_Key = $(Get-DBPoolAPIKey -AsPlainText).'ApiKey' $DBPool_Headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" $DBPool_Headers.Add("Content-Type", 'application/json') $DBPool_Headers.Add('X-App-APIkey', $api_Key) $rest_output = Invoke-WebRequest -method $method -uri ($base_uri + $resource_uri) -headers $DBPool_Headers -ErrorAction Stop } catch { [PSCustomObject]@{ URI = $($base_uri + $resource_uri) Method = $method StatusCode = $_.Exception.Response.StatusCode.value__ StatusDescription = $_.Exception.Response.ReasonPhrase Message = $_.Exception.Message } } finally { Remove-Variable -Name DBPool_Headers -Force } if ($rest_output){ $data = @{} $data = $rest_output [PSCustomObject]@{ RequestUri = $($DBPool_Base_URI + $resource_uri) StatusCode = $data.StatusCode StatusDescription = $data.StatusDescription 'Content-Type' = $data.headers.'Content-Type' <#'X-App-Request-Id' = $data.headers.'X-App-Request-Id' 'X-API-Limit-Remaining' = $data.headers.'X-API-Limit-Remaining' 'X-API-Limit-Resets' = $data.headers.'X-API-Limit-Resets' 'X-API-Limit-Cost' = $data.headers.'X-API-Limit-Cost'#> raw = $data } } } end {} } #EndRegion #Region function Invoke-DBPoolRequest { <# .SYNOPSIS Internal function to make an API request to the DBPool API .DESCRIPTION The Invoke-DBPoolRequest cmdlet invokes an API request to DBPool API This is an internal function that is used by all public functions .PARAMETER method Defines the type of API method to use Allowed values: 'DEFAULT', 'DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT' .PARAMETER resource_Uri Defines the resource uri (url) to use when creating the API call .PARAMETER uri_Filter Used with the internal function [ ConvertTo-DBPoolQueryString ] to combine a functions parameters with the resource_Uri parameter. This allows for the full uri query to occur The full resource path is made with the following data $DBPool_Base_URI + $resource_Uri + ConvertTo-DBPoolQueryString As of June 2024, DBPool does not support any query parameters. This is only provided to allow forward compatibility .PARAMETER data Defines the data to be sent with the API request body when using POST or PATCH .PARAMETER DBPool_JSON_Conversion_Depth Defines the depth of the JSON conversion for the 'data' parameter request body .PARAMETER allPages Returns all items from an endpoint When using this parameter there is no need to use either the page or perPage parameters As of June 2024, DBPool does not support any paging parameters. This is only provided to allow forward compatibility .INPUTS N/A .OUTPUTS [Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject] - The response from the DBPool API .EXAMPLE Invoke-DBPoolRequest -method GET -resource_Uri '/api/v2/self' -uri_Filter $uri_Filter Name Value ---- ----- Method GET Uri https://dbpool.datto.net/api/v2/self Headers {X-App-Apikey = 3feb2b29-919c-409c-985d-e99cbae43a6d} Body Invoke an API request against the defined resource using any of the provided parameters .EXAMPLE Invoke-DBPoolRequest -method GET -resource_Uri '/api/openapi.json' -uri_Filter $uri_Filter Name Value ---- ----- Method GET Uri https://dbpool.datto.net/api/openapi.json Headers {X-App-Apikey = 3feb2b29-919c-409c-985d-e99cbae43a6d} Body Invoke an API request against the defined resource using any of the provided parameters .NOTES N/A .LINK N/A #> [CmdletBinding()] [OutputType([Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject])] param ( [Parameter(Mandatory = $false)] [ValidateSet('DEFAULT', 'DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT')] [String]$method = 'DEFAULT', [Parameter(Mandatory = $true)] [String]$resource_Uri, [Parameter(DontShow = $true, Mandatory = $false)] [Hashtable]$uri_Filter = $null, [Parameter(Mandatory = $false)] [Hashtable]$data = $null, [Parameter(Mandatory = $false)] #[ValidateRange(0, [int]::MaxValue)] [int]$DBPool_JSON_Conversion_Depth = 5, [Parameter(DontShow = $true, Mandatory = $false)] [Switch]$allPages ) begin { $ConfirmPreference = 'None' } process { # Load Web assembly when needed as PowerShell Core has the assembly preloaded if ( !('System.Web.HttpUtility' -as [Type]) ) { Add-Type -Assembly System.Web } if (!($DBPool_base_URI)) { Write-Warning 'The DBPool base URI is not set. Run Add-DBPoolBaseURI to set the base URI.' } $query_String = ConvertTo-DBPoolQueryString -resource_Uri $resource_Uri -uri_Filter $uri_Filter Set-Variable -Name 'DBPool_queryString' -Value $query_String -Scope Global -Force if ($null -eq $data) { $request_Body = $null } else { $request_Body = $data | ConvertTo-Json -Depth $DBPool_JSON_Conversion_Depth } try { $api_Key = $(Get-DBPoolAPIKey -AsPlainText).'ApiKey' $parameters = [ordered] @{ 'Method' = $method 'Uri' = $query_String.Uri 'Headers' = @{ 'X-App-Apikey' = "$api_Key" } 'Body' = $request_Body } if ( $method -ne 'GET' ) { $parameters['ContentType'] = 'application/json; charset=utf-8' } Set-Variable -Name 'DBPool_invokeParameters' -Value $parameters -Scope Global -Force if ($allPages) { Write-Verbose "Gathering all items from [ $( $DBPool_Base_URI + $resource_Uri ) ] " $page_Number = 1 $all_responseData = [System.Collections.Generic.List[object]]::new() do { $parameters['Uri'] = $query_String.Uri -replace '_page=\d+', "_page=$page_Number" Write-Verbose "Making API request to Uri: [ $($parameters['Uri']) ]" $current_Page = Invoke-WebRequest @parameters -ErrorAction Stop Write-Verbose "[ $page_Number ] of [ $($current_Page.pagination.totalPages) ] pages" foreach ($item in $current_Page.items) { $all_responseData.add($item) } $page_Number++ } while ($current_Page.pagination.totalPages -ne $page_Number - 1 -and $current_Page.pagination.totalPages -ne 0) } else { Write-Verbose "Making API request to Uri: [ $($parameters['Uri']) ]" $api_Response = Invoke-WebRequest @parameters -ErrorAction Stop $appRequestId = $api_Response.Headers['X-App-Request-Id'] Write-Debug "If you need to report an error to the DBE team, include this request ID which can be used to search through the application logs for messages that were logged while processing your request [ X-App-Request-Id: $appRequestId ]" Set-Variable -Name 'DBPool_appRequestId' -Value $appRequestId -Scope Global -Force } } catch { $exceptionError = $_ Write-Warning 'The [ DBPool_invokeParameters, DBPool_queryString, DBPool_appRequestId, & DBPool_CmdletNameParameters ] variables can provide extra details' # Extract the 'X-App-Request-Id' header if needed for reporting to DBE team $appRequestId = $null if ($_.Exception.Response -and $_.Exception.Response.Headers) { $appRequestId = $_.Exception.Response.Headers.GetValues('X-App-Request-Id') Set-Variable -Name 'DBPool_appRequestId' -Value $appRequestId -Scope Global -Force Write-Debug "If you need to report an error to the DBE team, include this request ID which can be used to search through the application logs for messages that were logged while processing your request [ X-App-Request-Id: $appRequestId ]" } switch -Wildcard ( $($exceptionError.Exception.Message) ) { '*401*' { Write-Error 'Status 401 : Unauthorized. Invalid API key' } '*404*' { Write-Error "Status 404 : [ $( $DBPool_base_URI + $resource_Uri ) ] not found!" } '*429*' { Write-Error 'Status 429 : API rate limited' } '*500*' { $e = $($exceptionError.ErrorDetails.Message) if ($null -ne $e) { [string]$e = $( $e | ConvertFrom-Json -ErrorAction SilentlyContinue ).error.message } Write-Error "Status 500 : Internal Server Error. $e" } '*504*' { Write-Error "Status 504 : Gateway Timeout" } default { Write-Error $_ } } } finally { $Auth = $DBPool_invokeParameters['headers']['X-App-Apikey'] $DBPool_invokeParameters['headers']['X-App-Apikey'] = $Auth.Substring( 0, [Math]::Min($Auth.Length, 9) ) + '*******' } if($allPages){ #Making output consistent if( [string]::IsNullOrEmpty($all_responseData.data) ){ $api_Response = $null } else{ $api_Response = [PSCustomObject]@{ pagination = $null items = $all_responseData } } # Return the response $api_Response } else{ $api_Response } } end { # Variables to remove $var = @( 'api_Key', 'parameters', 'Auth' ) foreach ($v in $var) { Remove-Variable -Name $v -ErrorAction SilentlyContinue -Force } } } #EndRegion #Region function Add-DBPoolApiKey { <# .SYNOPSIS Sets the API key for the DBPool. .DESCRIPTION The Add-DBPoolApiKey cmdlet sets the API key which is used to authenticate API calls made to DBPool. Once the API key is defined, the secret key is encrypted using SecureString. The DBPool API key is retrieved via the DBPool UI at My Profile -> API key .PARAMETER ApiKey Defines your API key for the DBPool. .INPUTS [SecureString] - The API key for the DBPool. .OUTPUTS [void] - No output is returned. .EXAMPLE Add-DBPoolApiKey Prompts to enter in your personal API key. .EXAMPLE Add-DBPoolApiKey -ApiKey $secureString Read-Host "Enter your DBPool API Key" -AsSecureString | Add-DBPoolApiKey Sets the API key for the DBPool. .NOTES N/A .LINK N/A #> [CmdletBinding()] [Alias("Set-DBPoolApiKey")] [OutputType([void])] param ( [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "API Key for authorization to DBPool.")] [ValidateNotNullOrEmpty()] [securestring]$apiKey ) begin {} process { Write-Verbose "Setting the DBPool API Key." Set-Variable -Name "DBPool_ApiKey" -Value $apiKey -Option ReadOnly -Scope global -Force } end {} } #EndRegion #Region function Get-DBPoolApiKey { <# .SYNOPSIS Gets the DBPool API key global variable. .DESCRIPTION The Get-DBPoolApiKey cmdlet gets the DBPool API key global variable and returns this as an object. .PARAMETER AsPlainText Decrypt and return the API key in plain text. .INPUTS N/A .OUTPUTS [PSCustomObject] - The DBPool API key global variable. .EXAMPLE Get-DBPoolApiKey Gets the DBPool API key global variable and returns this as an object with the secret key as a SecureString. .EXAMPLE Get-DBPoolApiKey -AsPlainText Gets the DBPool API key global variable and returns this as an object with the secret key as plain text. .NOTES N\A .LINK N/A #> [cmdletbinding()] [OutputType([PSCustomObject])] Param ( [Parameter( Mandatory = $false )] [Switch]$AsPlainText ) begin {} process { try { if ($DBPool_ApiKey) { if ($AsPlainText) { if ($isWindows -or $PSEdition -eq 'Desktop') { $ApiKeyBSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($DBPool_ApiKey) try { $ApiKeyPlainText = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($ApiKeyBSTR) [PSCustomObject]@{ "ApiKey" = $ApiKeyPlainText } } finally { [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ApiKeyBSTR) } } else { $ApiKeyPlainText = ConvertFrom-SecureString -SecureString $DBPool_ApiKey -AsPlainText [PSCustomObject]@{ "ApiKey" = $ApiKeyPlainText } } $ApiKeyPlainText = $null } else { [PSCustomObject]@{ "ApiKey" = $DBPool_ApiKey } } } else { Write-Warning "The DBPool API [ secret ] key is not set. Run Add-DBPoolApiKey to set the API key." } } catch { Write-Error $_ } finally { if ($ApiKeyBSTR) { [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ApiKeyBSTR) } } } end {} } #EndRegion #Region function Remove-DBPoolApiKey { <# .SYNOPSIS Removes the DBPool API Key global variable. .DESCRIPTION The Remove-DBPoolAPIKey cmdlet removes the DBPool API Key global variable. .PARAMETER Force Forces the removal of the DBPool API Key global variable without prompting for confirmation. .INPUTS N/A .OUTPUTS [void] - No output is returned. .EXAMPLE Remove-DBPoolAPIKey Removes the DBPool API Key global variable. .NOTES N/A .LINK N/A #> [cmdletbinding(SupportsShouldProcess, ConfirmImpact = 'Low')] [OutputType([void])] Param ( [switch]$Force ) begin {} process { switch ([bool]$DBPool_ApiKey) { $true { if ($Force -or $PSCmdlet.ShouldProcess('DBPool_ApiKey', 'Remove variable')) { Write-Verbose 'Removing the DBPool API Key.' try { Remove-Variable -Name 'DBPool_ApiKey' -Scope Global -Force } catch { Write-Error $_ } } } $false { Write-Warning "The DBPool API [ secret ] key is not set. Nothing to remove" } } } end {} } #EndRegion #Region function Test-DBPoolApiKey { <# .SYNOPSIS Test the DBPool API Key. .DESCRIPTION The Test-DBPoolApiKey cmdlet tests the base URI & API Key that were defined in the Add-DBPoolBaseURI & Add-DBPoolAPIKey cmdlets. .PARAMETER base_uri Define the base URI for the DBPool API connection using Datto's DBPool URI or a custom URI. The default base URI is https://dbpool.datto.net/api .INPUTS [string] - base_uri .OUTPUTS [PSCustomObject] - Various API metadata values .EXAMPLE Test-DBPoolApiKey Tests the base URI & API key that was defined in the Add-DBPoolBaseURI & Add-DBPoolAPIKey cmdlets. The default full base uri test path is: https://dbpool.datto.net/api/v2/self .EXAMPLE Test-DBPoolApiKey -base_uri http://dbpool.example.com Tests the base URI & API key that was defined in the Add-DBPoolBaseURI & Add-DBPoolAPIKey cmdlets. The full base uri test path in this example is: http://dbpool.example.com/api/v2/self .NOTES N/A .LINK N/A #> [cmdletbinding()] [OutputType([PSCustomObject])] Param ( [parameter( Position = 0, Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Define the base URI for the DBPool connection. Default is Datto's DBPool URI or set a custom URI." )] [string]$base_uri = $DBPool_Base_URI ) begin { $resource_uri = "/api/v2/self" } process { try { $api_key = $(Get-DBPoolAPIKey -AsPlainText).'API_Key' $DBPool_Headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" $DBPool_Headers.Add("Content-Type", 'application/json') $DBPool_Headers.Add('X-App-Apikey', $api_key) $rest_output = Invoke-WebRequest -method Get -uri ($base_uri + $resource_uri) -headers $DBPool_Headers -ErrorAction Stop } catch { [PSCustomObject]@{ Method = $_.Exception.Response.Method StatusCode = $_.Exception.Response.StatusCode.value__ StatusDescription = $_.Exception.Response.StatusDescription Message = $_.Exception.Message URI = $($DBPool_Base_URI + $resource_uri) } } finally { Remove-Variable -Name DBPool_Headers -Force } if ($rest_output){ $data = @{} $data = $rest_output [PSCustomObject]@{ StatusCode = $data.StatusCode StatusDescription = $data.StatusDescription URI = $($DBPool_Base_URI + $resource_uri) } } } end {} } #EndRegion #Region function Add-DBPoolBaseURI { <# .SYNOPSIS Sets the base URI for the DBPool API connection. .DESCRIPTION The Add-DBPoolBaseURI cmdlet sets the base URI which is later used to construct the full URI for all API calls. .PARAMETER base_uri Define the base URI for the DBPool API connection using Datto's DBPool URI or a custom URI. .PARAMETER instance DBPool's URI connection point that can be one of the predefined data centers. The accepted values for this parameter are: [ DEFAULT ] DEFAULT = https://dbpool.datto.net Placeholder for other data centers. .INPUTS [string] - The base URI for the DBPool API connection. .OUTPUTS [void] - No output is returned. .EXAMPLE Add-DBPoolBaseURI The base URI will use https://dbpool.datto.net which is Datto's default DBPool URI. .EXAMPLE Add-DBPoolBaseURI -instance Datto The base URI will use https://dbpool.datto.net which is DBPool's default URI. .EXAMPLE Add-DBPoolBaseURI -base_uri http://dbpool.example.com A custom API gateway of http://dbpool.example.com will be used for all API calls to DBPool's API. .NOTES N/A .LINK N/A #> [cmdletbinding()] [OutputType([void])] [Alias("Set-DBPoolBaseURI")] Param ( [Parameter(Mandatory = $false , ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [string]$base_uri = 'https://dbpool.datto.net', [ValidateSet('Datto')] [String]$instance ) begin {} process { # Trim superfluous forward slash from address (if applicable) $base_uri = $base_uri.TrimEnd('/') switch ($instance) { 'Datto' { $base_uri = 'https://dbpool.datto.net' } } Set-Variable -Name "DBPool_Base_URI" -Value $base_uri -Option ReadOnly -Scope Global -Force Write-Verbose "DBPool Base URI set to `'$base_uri`'." } end {} } #EndRegion #Region function Get-DBPoolBaseURI { <# .SYNOPSIS Shows the DBPool base URI global variable. .DESCRIPTION The Get-DBPoolBaseURI cmdlet shows the DBPool base URI global variable value. .INPUTS N/A .OUTPUTS [void] - No output is returned. .EXAMPLE Get-DBPoolBaseURI Shows the DBPool base URI global variable value. .NOTES N/A .LINK N/A #> [cmdletbinding()] [OutputType([void])] Param () begin {} process { switch ([bool]$DBPool_Base_URI) { $true { $DBPool_Base_URI } $false { Write-Warning "The DBPool base URI is not set. Run Add-DBPoolBaseURI to set the base URI." } } } end {} } #EndRegion #Region function Remove-DBPoolBaseURI { <# .SYNOPSIS Removes the DBPool base URI global variable. .DESCRIPTION The Remove-DBPoolBaseURI cmdlet removes the DBPool base URI global variable. .PARAMETER Force Forces the removal of the DBPool base URI global variable without prompting for confirmation. .INPUTS N/A .OUTPUTS [void] - No output is returned. .EXAMPLE Remove-DBPoolBaseURI Removes the DBPool base URI global variable. .NOTES N/A .LINK N/A #> [cmdletbinding(SupportsShouldProcess)] [OutputType([void])] Param () begin {} process { switch ([bool]$DBPool_Base_URI) { $true { Remove-Variable -Name "DBPool_Base_URI" -Scope Global -Force } $false { Write-Warning "The DBPool base URI variable is not set. Nothing to remove" } } } end {} } #EndRegion #Region function Export-DBPoolModuleSetting { <# .SYNOPSIS Exports the DBPool BaseURI, API Key, & JSON configuration information to file. .DESCRIPTION The Export-DBPoolModuleSetting cmdlet exports the DBPool BaseURI, API Key, & JSON configuration information to file. Making use of PowerShell's System.Security.SecureString type, exporting module settings encrypts your API key in a format that can only be unencrypted with the your Windows account as this encryption is tied to your user principal. This means that you cannot copy your configuration file to another computer or user account and expect it to work. .PARAMETER DBPoolConfPath Define the location to store the DBPool configuration file. By default the configuration file is stored in the following location: $env:USERPROFILE\DBPoolAPI .PARAMETER DBPoolConfFile Define the name of the DBPool configuration file. By default the configuration file is named: config.psd1 .INPUTS N/A .OUTPUTS [void] - No output is returned. .EXAMPLE Export-DBPoolModuleSetting Validates that the BaseURI, API Key, and JSON depth are set then exports their values to the current user's DBPool configuration file located at: $env:USERPROFILE\DBPoolAPI\config.psd1 .EXAMPLE Export-DBPoolModuleSetting -DBPoolConfPath C:\DBPoolAPI -DBPoolConfFile MyConfig.psd1 Validates that the BaseURI, API Key, and JSON depth are set then exports their values to the current user's DBPool configuration file located at: C:\DBPoolAPI\MyConfig.psd1 .NOTES N/A .LINK N/A #> [CmdletBinding(DefaultParameterSetName = 'set')] [OutputType([void])] Param ( [Parameter(ParameterSetName = 'set')] [string]$DBPoolConfPath = $(Join-Path -Path $home -ChildPath $(if ($IsWindows -or $PSEdition -eq 'Desktop'){"DBPoolAPI"}else{".DBPoolAPI"}) ), [Parameter(ParameterSetName = 'set')] [string]$DBPoolConfFile = 'config.psd1' ) begin {} process { if (-not ($IsWindows -or $PSEdition -eq 'Desktop') ) { Write-Warning "Secrets are stored using Windows Data Protection API (DPAPI)" Write-Warning "DPAPI provides user context encryption in Windows but NOT in other operating systems like Linux or UNIX. It is recommended to use a more secure & cross-platform storage method" } $DBPoolConfig = Join-Path -Path $DBPoolConfPath -ChildPath $DBPoolConfFile # Confirm variables exist and are not null before exporting if ($DBPool_Base_URI -and $DBPool_ApiKey -and $DBPool_JSON_Conversion_Depth) { $secureString = $DBPool_ApiKey | ConvertFrom-SecureString if ($IsWindows -or $PSEdition -eq 'Desktop') { New-Item -Path $DBPoolConfPath -ItemType Directory -Force | ForEach-Object { $_.Attributes = $_.Attributes -bor "Hidden" } } else { New-Item -Path $DBPoolConfPath -ItemType Directory -Force } @" @{ DBPool_Base_URI = '$DBPool_Base_URI' DBPool_ApiKey = '$secureString' DBPool_JSON_Conversion_Depth = '$DBPool_JSON_Conversion_Depth' } "@ | Out-File -FilePath $DBPoolConfig -Force Write-Verbose "DBPool Module settings exported to [ $DBPoolConfig ]" } else { Write-Error "Failed to export DBPool Module settings to [ $DBPoolConfig ]" Write-Error $_ -ErrorAction Stop } } end {} } #EndRegion #Region function Get-DBPoolModuleSetting { <# .SYNOPSIS Gets the saved DBPool configuration settings .DESCRIPTION The Get-DBPoolModuleSetting cmdlet gets the saved DBPool configuration settings from the local system. By default the configuration file is stored in the following location: $env:USERPROFILE\DBPoolAPI .PARAMETER DBPoolConfPath Define the location to store the DBPool configuration file. By default the configuration file is stored in the following location: $env:USERPROFILE\DBPoolAPI .PARAMETER DBPoolConfFile Define the name of the DBPool configuration file. By default the configuration file is named: config.psd1 .PARAMETER openConfFile Opens the DBPool configuration file .INPUTS N/A .OUTPUTS [void] - No output is returned. .EXAMPLE Get-DBPoolModuleSetting Gets the contents of the configuration file that was created with the Export-DBPoolModuleSetting The default location of the DBPool configuration file is: $env:USERPROFILE\DBPoolAPI\config.psd1 .EXAMPLE Get-DBPoolModuleSetting -DBPoolConfPath C:\DBPoolAPI -DBPoolConfFile MyConfig.psd1 -openConfFile Opens the configuration file from the defined location in the default editor The location of the DBPool configuration file in this example is: C:\DBPoolAPI\MyConfig.psd1 .NOTES N/A .LINK N/A #> [CmdletBinding(DefaultParameterSetName = 'index')] [OutputType([void])] Param ( [Parameter(Mandatory = $false, ParameterSetName = 'index')] [string]$DBPoolConfPath = $(Join-Path -Path $home -ChildPath $(if ($IsWindows -or $PSEdition -eq 'Desktop'){"DBPoolAPI"}else{".DBPoolAPI"}) ), [Parameter(Mandatory = $false, ParameterSetName = 'index')] [String]$DBPoolConfFile = 'config.psd1', [Parameter(Mandatory = $false, ParameterSetName = 'show')] [Switch]$openConfFile ) begin { $DBPoolConfig = Join-Path -Path $DBPoolConfPath -ChildPath $DBPoolConfFile } process { if ( Test-Path -Path $DBPoolConfig ){ if($openConfFile){ Invoke-Item -Path $DBPoolConfig } else{ Import-LocalizedData -BaseDirectory $DBPoolConfPath -FileName $DBPoolConfFile } } else{ Write-Verbose "No configuration file found at [ $DBPoolConfig ]" } } end {} } #EndRegion #Region function Import-DBPoolModuleSetting { <# .SYNOPSIS Imports the DBPool BaseURI, API Key, & JSON configuration information to the current session. .DESCRIPTION The Import-DBPoolModuleSetting cmdlet imports the DBPool BaseURI, API Key, & JSON configuration information stored in the DBPool configuration file to the users current session. By default the configuration file is stored in the following location: $env:USERPROFILE\DBPoolAPI .PARAMETER DBPoolConfPath Define the location to store the DBPool configuration file. By default the configuration file is stored in the following location: $env:USERPROFILE\DBPoolAPI .PARAMETER DBPoolConfFile Define the name of the DBPool configuration file. By default the configuration file is named: config.psd1 .INPUTS N/A .OUTPUTS N/A .EXAMPLE Import-DBPoolModuleSetting Validates that the configuration file created with the Export-DBPoolModuleSetting cmdlet exists then imports the stored data into the current users session. The default location of the DBPool configuration file is: $env:USERPROFILE\DBPoolAPI\config.psd1 .EXAMPLE Import-DBPoolModuleSetting -DBPoolConfPath C:\DBPoolAPI -DBPoolConfFile MyConfig.psd1 Validates that the configuration file created with the Export-DBPoolModuleSetting cmdlet exists then imports the stored data into the current users session. The location of the DBPool configuration file in this example is: C:\DBPoolAPI\MyConfig.psd1 .NOTES N/A .LINK N/A #> [CmdletBinding(DefaultParameterSetName = 'set')] Param ( [Parameter(ParameterSetName = 'set')] [string]$DBPoolConfPath = $(Join-Path -Path $home -ChildPath $(if ($IsWindows -or $PSEdition -eq 'Desktop'){"DBPoolAPI"}else{".DBPoolAPI"}) ), [Parameter(ParameterSetName = 'set')] [string]$DBPoolConfFile = 'config.psd1' ) begin { $DBPoolConfig = Join-Path -Path $DBPoolConfPath -ChildPath $DBPoolConfFile } process { if ( Test-Path $DBPoolConfig ) { $tmp_config = Import-LocalizedData -BaseDirectory $DBPoolConfPath -FileName $DBPoolConfFile # Send to function to strip potentially superfluous slash (/) Add-DBPoolBaseURI $tmp_config.DBPool_Base_URI $tmp_config.DBPool_ApiKey = ConvertTo-SecureString $tmp_config.DBPool_ApiKey Set-Variable -Name "DBPool_ApiKey" -Value $tmp_config.DBPool_ApiKey -Option ReadOnly -Scope global -Force Set-Variable -Name "DBPool_JSON_Conversion_Depth" -Value $tmp_config.DBPool_JSON_Conversion_Depth -Scope global -Force Write-Verbose "DBPoolAPI Module configuration loaded successfully from [ $DBPoolConfig ]" # Clean things up Remove-Variable "tmp_config" } else { Write-Verbose "No configuration file found at [ $DBPoolConfig ] run Add-DBPoolAPIKey to get started." Add-DBPoolBaseURI Set-Variable -Name "DBPool_Base_URI" -Value $(Get-DBPoolBaseURI) -Option ReadOnly -Scope global -Force Set-Variable -Name "DBPool_JSON_Conversion_Depth" -Value 100 -Scope global -Force } } end {} } #EndRegion #Region # Used to auto load either baseline settings or saved configurations when the module is imported Import-DBPoolModuleSetting -Verbose:$false #EndRegion #Region function Remove-DBPoolModuleSetting { <# .SYNOPSIS Removes the stored DBPool configuration folder. .DESCRIPTION The Remove-DBPoolModuleSetting cmdlet removes the DBPool folder and its files. This cmdlet also has the option to remove sensitive DBPool variables as well. By default configuration files are stored in the following location and will be removed: $env:USERPROFILE\DBPoolAPI .PARAMETER DBPoolConfPath Define the location of the DBPool configuration folder. By default the configuration folder is located at: $env:USERPROFILE\DBPoolAPI .PARAMETER andVariables Define if sensitive DBPool variables should be removed as well. By default the variables are not removed. .INPUTS N/A .OUTPUTS [void] - No output is returned. .EXAMPLE Remove-DBPoolModuleSetting Checks to see if the default configuration folder exists and removes it if it does. The default location of the DBPool configuration folder is: $env:USERPROFILE\DBPoolAPI .EXAMPLE Remove-DBPoolModuleSetting -DBPoolConfPath C:\DBPoolAPI -andVariables Checks to see if the defined configuration folder exists and removes it if it does. If sensitive DBPool variables exist then they are removed as well. The location of the DBPool configuration folder in this example is: C:\DBPoolAPI .NOTES N/A .LINK N/A #> [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'set')] [OutputType([void])] Param ( [Parameter(ParameterSetName = 'set')] [string]$DBPoolConfPath = $(Join-Path -Path $home -ChildPath $(if ($IsWindows -or $PSEdition -eq 'Desktop'){"DBPoolAPI"}else{".DBPoolAPI"}) ), [Parameter(ParameterSetName = 'set')] [switch]$andVariables ) begin {} process { if (Test-Path $DBPoolConfPath) { Remove-Item -Path $DBPoolConfPath -Recurse -Force -WhatIf:$WhatIfPreference If ($andVariables) { Remove-DBPoolAPIKey Remove-DBPoolBaseURI } if (!(Test-Path $DBPoolConfPath)) { Write-Output "The DBPoolAPI configuration folder has been removed successfully from [ $DBPoolConfPath ]" } else { Write-Error "The DBPoolAPI configuration folder could not be removed from [ $DBPoolConfPath ]" } } else { Write-Warning "No configuration folder found at [ $DBPoolConfPath ]" } } end {} } #EndRegion #Region function Get-DBPoolContainer { <# .SYNOPSIS The Get-DBPoolContainer function retrieves container information from the DBPool API. .DESCRIPTION This function retrieves container details from the DBPool API. It can get containers, parent containers, or child containers, and also retrieve containers or container status by ID. This also can filter or exclude by container name or database. .PARAMETER Id The ID of the container details to get from the DBPool. This parameter is required when using the 'ContainerStatus' parameter set. .PARAMETER Status Gets the status of a container by ID. Returns basic container details, and dockerContainerRunning, mysqlServiceResponding, and mysqlServiceRespondingCached statuses. .PARAMETER ListContainer Retrieves a list of containers from the DBPool API. This is the default parameter set. .PARAMETER ParentContainer Retrieves a list of parent containers from the DBPool API. .PARAMETER ChildContainer Retrieves a list of child containers from the DBPool API. .PARAMETER Name Filters containers returned from the DBPool API by name. Accepts wildcard input. .PARAMETER DefaultDatabase Filters containers returned from the DBPool API by database. Accepts wildcard input. .PARAMETER NotLike Excludes containers returned from the DBPool API by Name or DefaultDatabase using the -NotLike switch. Requires the -Name or -DefaultDatabase parameter to be specified. Returns containers where the Name or DefaultDatabase does not match the provided filter. .INPUTS [int] - Id The ID of the container to get details for. [string] Name The name of the container to get details for. [string] - DefaultDatabase The database of the container to get details for. .OUTPUTS [PSCustomObject] - The response from the DBPool API. .EXAMPLE Get-DBPoolContainer Get a list of all containers from the DBPool API .EXAMPLE Get-DBPoolContainer -Id 12345 Get a list of containers from the DBPool API by ID .EXAMPLE Get-DBPoolContainer -Status -Id @( 12345, 67890 ) Get the status of an array of containers by IDs .EXAMPLE Get-DBPoolContainer -ParentContainer Get a list of parent containers from the DBPool API .EXAMPLE Get-DBPoolContainer -ParentContainer -Id 12345 Get a list of parent containers from the DBPool API by ID .EXAMPLE Get-DBPoolContainer -ChildContainer Get a list of child containers from the DBPool API .EXAMPLE Get-DBPoolContainer -Name 'MyContainer' Get-DBPoolContainer -ParentContainer -Name 'ParentContainer*' Uses 'Where-Object' to get a list of containers from the DBPool API, or parent containers by name Accepts wildcard input .EXAMPLE Get-DBPoolContainer -Name 'MyContainer' -NotLike Get-DBPoolContainer -ParentContainer -Name 'ParentContainer*' -NotLike Uses 'Where-Object' to get a list of containers from the DBPool API, or parent containers where the name does not match the filter Accepts wildcard input .EXAMPLE Get-DBPoolContainer -DefaultDatabase 'Database' Get-DBPoolContainer -ParentContainer -DefaultDatabase 'Database*' Get a list of containers from the DBPool API, or parent containers by database Accepts wildcard input .EXAMPLE Get-DBPoolContainer -DefaultDatabase 'Database' -NotLike Get-DBPoolContainer -ParentContainer -DefaultDatabase 'Database*' -NotLike Get a list of containers from the DBPool API, or parent containers where the database does not match the filter Accepts wildcard input .NOTES The -Name, and -DefaultDatabase parameters are not native endpoints of the DBPool API. This is a custom function which uses 'Where-Object', along with the optional -NotLike parameter to return the response using the provided filter. If no match is found an error is output, and the original response is returned. .LINK N/A #> [CmdletBinding(DefaultParameterSetName = 'ListContainer')] [OutputType([PSCustomObject])] param ( [Parameter(ParameterSetName = 'ListContainer')] [switch]$ListContainer, [Parameter(ParameterSetName = 'ParentContainer')] [switch]$ParentContainer, [Parameter(ParameterSetName = 'ChildContainer')] [switch]$ChildContainer, [Parameter(ParameterSetName = 'ParentContainer', Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Parameter(ParameterSetName = 'ListContainer', Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Parameter(ParameterSetName = 'ContainerStatus', Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] #[ValidateRange(0, [int]::MaxValue)] [int[]]$Id, [Parameter(ParameterSetName = 'ContainerStatus')] [switch]$Status, [Parameter(ParameterSetName = 'ListContainer', ValueFromPipelineByPropertyName = $true)] [Parameter(ParameterSetName = 'ParentContainer', ValueFromPipelineByPropertyName = $true)] [SupportsWildcards()][string[]]$Name, [Parameter(ParameterSetName = 'ListContainer', ValueFromPipelineByPropertyName = $true)] [Parameter(ParameterSetName = 'ParentContainer', ValueFromPipelineByPropertyName = $true)] [Alias('Database')] [SupportsWildcards()][string[]]$DefaultDatabase, [Parameter(ParameterSetName = 'ListContainer')] [Parameter(ParameterSetName = 'ParentContainer')] [switch]$NotLike ) begin { $method = 'GET' switch ($PSCmdlet.ParameterSetName) { 'ListContainer' { $requestPath = '/api/v2/containers' } 'ParentContainer' { $requestPath = '/api/v2/parents' } 'ChildContainer' { $requestPath = '/api/v2/children' } 'ContainerStatus' { $requestPath = '/api/v2/containers' } } # Validate filter parameters for name or DefaultDatabase if -NotLike switch is used if ($PSCmdlet.ParameterSetName -eq 'ListContainer' -or $PSCmdlet.ParameterSetName -eq 'ParentContainer') { if ($NotLike -and -not ($Name -or $DefaultDatabase)) { Write-Error 'The -NotLike switch requires either the -Name or -DefaultDatabase parameter to be specified.' -ErrorAction Stop } } # Internal Function to filter the response by Container Name or DefaultDatabase if provided function Select-DBPoolContainer { param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [PSObject[]]$Container, [Parameter(Mandatory = $false)] [string[]]$Name, [Parameter(Mandatory = $false)] [string[]]$DefaultDatabase, [Parameter(Mandatory = $false)] [switch]$NotLike ) process { # Verbose filter output $Filter = @() $filterParameter = @() if ($Name) { $Filter += 'Name' $filterParameter += ($Name -join ', ') } if ($DefaultDatabase) { $Filter += 'DefaultDatabase' $filterParameter += ($DefaultDatabase -join ', ') } $filterHeader = $Filter -join '; ' $filterValues = @() if ($Name) { $filterValues += ($Name -join ', ') } if ($DefaultDatabase) { $filterValues += ($DefaultDatabase -join ', ') } if ($NotLike) { Write-Verbose "Excluding response by containers matching $filterHeader [ $($filterValues -join '; ') ]" } else { Write-Verbose "Filtering response by containers matching $filterHeader [ $($filterValues -join '; ') ]" } # Filter containers $FilteredContainers = $Container | Where-Object { $matchesName = $true $matchesDB = $true # Handle Name filtering if ($Name) { $matchesName = $false foreach ($n in $Name) { if ($_.name -like $n) { $matchesName = $true break } } if ($NotLike) { $matchesName = -not $matchesName } } # Handle DefaultDatabase filtering if ($DefaultDatabase) { $matchesDB = $false foreach ($db in $DefaultDatabase) { if ($_.defaultDatabase -like $db) { $matchesDB = $true break } } if ($NotLike) { $matchesDB = -not $matchesDB } } # Return true if both conditions match $matchesName -and $matchesDB } # Output filtered containers if (!$FilteredContainers) { Write-Warning "No containers found matching the $filterHeader filter parameter [ $($filterValues -join '; ') ]. Returning all containers." return $Container } return $FilteredContainers } } } process { # Get list of containers by ID if ($PSBoundParameters.ContainsKey('Id')) { $response = foreach ($n in $Id) { $requestResponse = $null Write-Verbose "Running the [ $($PSCmdlet.ParameterSetName) ] parameter set for ID $n" # Define the ContainerStatus parameter request path if set $uri = "$requestPath/$n" if ($Status) { $uri += '/status' } try { $requestResponse = Invoke-DBPoolRequest -method $method -resource_Uri $uri -ErrorAction Stop } catch { Write-Error $_ continue } if ($null -ne $requestResponse) { $requestResponse | ConvertFrom-Json } } # Get list of containers based on the parameter set, returns all listed containers } else { Write-Verbose "Running the [ $($PSCmdlet.ParameterSetName) ] parameter set" try { $requestResponse = Invoke-DBPoolRequest -method $method -resource_Uri $requestPath -ErrorAction Stop } catch { Write-Error $_ } # Convert the response to JSON, return the response based on the parameter set if ($null -ne $requestResponse) { $response = $requestResponse | ConvertFrom-Json if ($PSCmdlet.ParameterSetName -eq 'ParentContainer') { $response = $response.parents } elseif ($PSCmdlet.ParameterSetName -eq 'ListContainer') { $response = $response.containers } } } # Filter the response by Name or DefaultDatabase if provided using internal helper function if ($PSBoundParameters.ContainsKey('Name') -or $PSBoundParameters.ContainsKey('DefaultDatabase')) { try { $response = Select-DBPoolContainer -Container $response -Name $Name -DefaultDatabase $DefaultDatabase -NotLike:$NotLike -ErrorAction Stop } catch { Write-Error $_ } } # Return the response $response } end {} } #EndRegion #Region function New-DBPoolContainer { <# .SYNOPSIS The New-DBPoolContainer function is used to create a new container from the DBPool API. .DESCRIPTION This function creates a new container in the DBPool based on the provided container name and parent container information. The ContainerName parameter is mandatory, and at least one of the parent parameters (ParentId, ParentName, or ParentDefaultDatabase) must be specified. .PARAMETER ContainerName The name for the new container. .PARAMETER ParentId The ID of the parent container to clone. .PARAMETER ParentName The name of the parent container to clone. .PARAMETER ParentDefaultDatabase The default database of the parent container to clone. .PARAMETER Force Force the operation without confirmation. .INPUTS [string] - ContainerName The name for the new container. [int] - ParentId The ID of the parent container to clone. [string] - ParentName The name of the parent container to clone. [string] - ParentDefaultDatabase The default database of the parent container to clone. .OUTPUTS [PSCustomObject] - The response from the DBPool API. .EXAMPLE New-DBPoolContainer -ContainerName 'MyNewContainer' -ParentId 12345 This will create a new container named 'MyNewContainer' based on the parent container with ID 12345. .EXAMPLE Get-DBPoolContainer -ParentContainer -Id 1 | New-DBPoolContainer -ContainerName 'MyNewContainer' This will create a new container named 'MyNewContainer' based on the piped in parent container. .NOTES N/A .LINK N/A #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')] [OutputType([PSCustomObject])] param ( [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string]$ContainerName, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [ValidateRange(1, [int]::MaxValue)] [Alias("Id")] [int]$ParentId, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [Alias("Name")] [string]$ParentName, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [Alias("DefaultDatabase")] [string]$ParentDefaultDatabase, [Parameter(Mandatory = $false, DontShow = $true)] [Switch]$Force ) begin { $method = 'POST' $requestPath = "/api/v2/containers" $body = @{} } process { $body['name'] = $ContainerName # Check that at least one parent parameter is provided # This is done rather than using parameter sets or mandatory parameters to allow for multiple parent parameters to be provided as API accepts multiple parent parameter inputs # If multiple fields are specified, both conditions will have to match a parent for it to be selected. if (-not ($PSBoundParameters.ContainsKey('ParentId') -or $PSBoundParameters.ContainsKey('ParentName') -or $PSBoundParameters.ContainsKey('ParentDefaultDatabase'))) { Write-Error "At least one parent parameter (ParentId, ParentName, or ParentDefaultDatabase) must be provided." -ErrorAction Stop } # Insert specified parent parameters into the request body if ($PSBoundParameters.ContainsKey('ParentId')) { $body.'parent.id' = $ParentId } if ($PSBoundParameters.ContainsKey('ParentName')) { $body.'parent.name' = $ParentName } if ($PSBoundParameters.ContainsKey('ParentDefaultDatabase')) { $body.'parent.defaultDatabase' = $ParentDefaultDatabase } try { if ($Force -or $PSCmdlet.ShouldProcess("Container Name: $ContainerName", "Create new Container")) { $response = Invoke-DBPoolRequest -Method $method -resource_Uri $requestPath -data $body -ErrorAction Stop } if ($null -ne $response) { $response = $response | ConvertFrom-Json } } catch { Write-Error $_ } # Return the response $response } end {} } #EndRegion #Region function Remove-DBPoolContainer { <# .SYNOPSIS The Remove-DBPoolContainer function is used to delete a container in the DBPool. .DESCRIPTION The Remove-DBPoolContainer function is used to delete containers in the DBPool based on the provided container ID. !! This is a destructive operation and will destory the container !! .PARAMETER Id The ID of the container to delete. This accepts an array of integers. .PARAMETER Force Forces the removal of the container without prompting for confirmation. .INPUTS [int] - The ID of the container to delete. .OUTPUTS [void] - No output is returned. .EXAMPLE Remove-DBPoolContainer -Id '12345' This will delete the provided container by ID. .EXAMPLE @( 12345, 56789 ) | Remove-DBPoolContainer -Confirm:$false This will delete the containers with ID 12345, and 56789. .NOTES N/A .LINK N/A #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] [OutputType([void])] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateRange(1, [int]::MaxValue)] [Alias('ContainerId')] [int[]]$Id, [switch]$Force ) begin { $method = 'DELETE' # Pass the InformationAction parameter if bound, default to 'Continue' if ($PSBoundParameters.ContainsKey('InformationAction')) { $InformationPreference = $PSBoundParameters['InformationAction'] } else { $InformationPreference = 'Continue' } } process { foreach ($n in $Id) { $response = $null $requestPath = "/api/v2/containers/$n" # Try to get the container name to output for the ID when using the Verbose preference if ($VerbosePreference -eq 'Continue') { try { $containerName = (Get-DBPoolContainer -Id $n -ErrorAction Stop).name } catch { Write-Warning "Failed to get the container name for ID $n. $_" $containerName = '## FailedToGetContainerName ##' } } if ($Force -or $PSCmdlet.ShouldProcess("Container [ ID: $n ]", 'Destroy')) { Write-Verbose "Destroying Container [ ID: $n, Name: $containerName ]" try { $response = Invoke-DBPoolRequest -method $method -resource_Uri $requestPath -ErrorAction Stop } catch { Write-Error $_ } if ($response.StatusCode -eq 204) { Write-Information "Success: Container [ ID: $n ] destroyed." } } } } end {} } #EndRegion #Region function Rename-DBPoolContainer { <# .SYNOPSIS The Rename-DBPoolContainer function is used to update a container in the DBPool. .DESCRIPTION The Rename-DBPoolContainer function is used to change the name a container in the DBPool API. .PARAMETER Id The ID of the container to update. This accepts an array of integers. .PARAMETER Name The new name for the container. .INPUTS [int] - The ID of the container to update. [string] - The new name for the container. .OUTPUTS [PSCustomObject] - The response from the DBPool API. .EXAMPLE Rename-DBPoolContainer -Id 12345 -Name 'NewContainerName' This will update the container with ID 12345 to have the name 'NewContainerName' .EXAMPLE @( 12345, 56789 ) | Rename-DBPoolContainer -Name 'NewContainerName' This will update the containers with ID 12345, and 56789 to have the name 'NewContainerName' .NOTES N/A .LINK N/A #> [CmdletBinding()] [OutputType([PSCustomObject])] param ( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateRange(1, [int]::MaxValue)] [Alias('ContainerId')] [int[]]$Id, [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string]$Name ) begin { $method = 'PATCH' $body = @{ name = $Name } # Pass the InformationAction parameter if bound, default to 'Continue' if ($PSBoundParameters.ContainsKey('InformationAction')) { $InformationPreference = $PSBoundParameters['InformationAction'] } else { $InformationPreference = 'Continue' } } process { $response = foreach ($n in $Id) { $requestResponse = $null $requestPath = "/api/v2/containers/$n" # Try to get the container name to output for the ID when using the Verbose preference if ($VerbosePreference -eq 'Continue') { try { $containerName = (Get-DBPoolContainer -Id $n -ErrorAction Stop).name } catch { Write-Warning "Failed to get the container name for ID $n. $_" $containerName = '## FailedToGetContainerName ##' } } try { Write-Verbose "Updating Container [ ID: $n, Name: $containerName ]" $requestResponse = Invoke-DBPoolRequest -method $method -resource_Uri $requestPath -data $body -ErrorAction Stop if ($requestResponse.StatusCode -eq 200) { Write-Information "Successfully updated Container [ ID: $n ]" } } catch { Write-Error $_ } if ($null -ne $requestResponse) { $requestResponse | ConvertFrom-Json } } # Return the response $response } end {} } #EndRegion #Region function Invoke-DBPoolContainerAccess { <# .SYNOPSIS The Invoke-DBPoolContainerAccess function is used to interact with various container access operations in the Datto DBPool API. .DESCRIPTION The Invoke-DBPoolContainerAccess function is used to Get, Add, or Remove access to a container in the Datto DBPool API based on a given username. .PARAMETER Id The ID of the container to access. This accepts an array of integers. .PARAMETER Username The username to access the container. This accepts an array of strings. .PARAMETER GetAccess Gets the current access to a container by ID for the given username. .PARAMETER AddAccess Adds access to a container by ID for the given username. .PARAMETER RemoveAccess Removes access to a container by ID for the given username. .INPUTS [int] - The ID of the container to access. [string] - The username to access the container. .OUTPUTS [PSCustomObject] - The response from the DBPool API. [void] - No output is returned. .EXAMPLE Invoke-DBPoolContainerAccess -Id '12345' -Username 'John.Doe' Invoke-DBPoolContainerAccess -Id '12345' -Username 'John.Doe' -GetAccess This will get access to the container with ID 12345 for the user "John.Doe" .EXAMPLE Invoke-DBPoolContainerAccess -Id @( '12345', '56789' ) -Username 'John.Doe' -AddAccess This will add access to the containers with ID 12345, and 56789 for the user "John.Doe" .EXAMPLE Invoke-DBPoolContainerAccess -Id '12345' -Username @( 'Jane.Doe', 'John.Doe' ) -RemoveAccess This will remove access to the container with ID 12345 for the users "Jane.Doe", and "John.Doe" .NOTES N/A .LINK N/A #> [CmdletBinding(DefaultParameterSetName = 'GetAccess', SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] [OutputType([PSCustomObject], ParameterSetName = { 'GetAccess', 'AddAccess' })] [OutputType([void], ParameterSetName = 'RemoveAccess')] param ( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] #[ValidateRange(1, [int]::MaxValue)] [Alias('ContainerId')] [int[]]$Id, [Parameter(Mandatory = $true, Position = 1, ParameterSetName = 'GetAccess', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Parameter(Mandatory = $true, Position = 1, ParameterSetName = 'AddAccess', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Parameter(Mandatory = $true, Position = 1, ParameterSetName = 'RemoveAccess', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]]$Username, [Parameter(Mandatory = $false, ParameterSetName = 'GetAccess')] [Switch]$GetAccess, [Parameter(Mandatory = $false, ParameterSetName = 'AddAccess')] [Switch]$AddAccess, [Parameter(Mandatory = $false, ParameterSetName = 'RemoveAccess')] [Switch]$RemoveAccess ) begin { # Pass the InformationAction parameter if bound, default to 'Continue' if ($PSBoundParameters.ContainsKey('InformationAction')) { $InformationPreference = $PSBoundParameters['InformationAction'] } else { $InformationPreference = 'Continue' } } process { $response = foreach ($n in $Id) { foreach ($uName in $Username) { $requestPath = "/api/v2/containers/$n/access/$uName" $method = $null $requestResponse = $null $responseContent = $null switch ($PSCmdlet.ParameterSetName) { 'GetAccess' { $method = 'GET' } 'AddAccess' { if ($PSCmdlet.ShouldProcess("[ $uName ] for Container [ ID: $n ]", "[ $($PSCmdlet.ParameterSetName) ]")) { $method = 'PUT' } } 'RemoveAccess' { if ($PSCmdlet.ShouldProcess("[ $uName ] for Container [ ID: $n ]", "[ $($PSCmdlet.ParameterSetName) ]")) { $method = 'DELETE' } } } if ($method) { try { $requestResponse = Invoke-DBPoolRequest -method $method -resource_Uri $requestPath -ErrorAction Stop } catch { $requestResponse = $null Write-Error $_ } if ($null -ne $requestResponse) { $responseContent = $requestResponse.Content | ConvertFrom-Json } switch ($PSCmdlet.ParameterSetName) { 'GetAccess' { $responseContent } 'AddAccess' { if ($requestResponse.StatusCode -eq 200) { Write-Information "User access on Container [ ID: $n ] already exists for [ $uName ]" } elseif ($requestResponse.StatusCode -eq 201) { Write-Information "User access on Container [ ID: $n ] successfully created for [ $uName ]" } $responseContent } 'RemoveAccess' { if ($requestResponse.StatusCode -eq 204) { Write-Information "User access on Container [ ID: $n ] successfully removed for [ $uName ]" } $responseContent } } } } } # Return the responses $response } end {} } #EndRegion #Region function Invoke-DBPoolContainerAction { <# .SYNOPSIS The Invoke-DBPoolContainerAction function is used to interact with various container action operations in the Datto DBPool API. .DESCRIPTION The Invoke-DBPoolContainerAction function is used to perform actions on a container such as refresh, schema-merge, start, restart, or stop. .PARAMETER Id The ID(s) of the container(s) to perform the action on. .PARAMETER Action The action to perform on the container. Valid actions are: refresh, schema-merge, start, restart, or stop. Start, Stop, and Restart are all considered minor actions and will not require a confirmation prompt. Refresh and Schema-Merge are considered major actions and will require a confirmation prompt. .PARAMETER Force Skip the confirmation prompt for major actions, such as 'Refresh' and 'Schema-Merge'. .PARAMETER TimeoutSeconds The maximum time in seconds to wait for the action to complete. Default is 3600 seconds (60 minutes). .PARAMETER ThrottleLimit The maximum number of containers to process in parallel. Default is twice the number of processor cores. .INPUTS [int] - The ID of the container to perform the action on. [string] - The action to perform on the container. .OUTPUTS [void] - No output is returned. .EXAMPLE Invoke-DBPoolContainerAction -Action 'restart' -Id '12345' This will restart the container with ID 12345 .EXAMPLE Invoke-DBPoolContainerAction refresh 12345,56789 This will refresh the containers with ID 12345, and 56789 .EXAMPLE Invoke-DBPoolContainerAction -Action refresh -Id (Get-DBPoolContainer).Id -Force This will refresh all containers without prompting for confirmation. .NOTES Actions: refresh: Recreate the Docker container and ZFS snapshot for the container. schema-merge: Attempt to apply upstream changes to the parent container to this child container. This may break your container. Refreshing a container is the supported way to update a child container's database schema. start: Start the Docker container for the container. restart: Stop and start the Docker container. stop: Stop the Docker container. .LINK N/A #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] [OutputType([void])] param ( [Parameter(Mandatory = $true, Position = 0)] [ValidateSet('refresh', 'schema-merge', 'start', 'restart', 'stop', IgnoreCase = $false)] [string]$Action, [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateRange(1, [int]::MaxValue)] [Alias('ContainerId')] [int[]]$Id, [switch]$Force, [Parameter(DontShow = $true)] [ValidateRange(0, [int]::MaxValue)] [int]$TimeoutSeconds = 3600, # Default timeout of 60 minutes (3600 seconds) for longer running actions [Parameter(DontShow = $true)] [ValidateRange(1, [int]::MaxValue)] [int]$ThrottleLimit = ([Environment]::ProcessorCount * 2) ) begin { $method = 'POST' # Pass the InformationAction parameter if bound, default to 'Continue' if ($PSBoundParameters.ContainsKey('InformationAction')) { $InformationPreference = $PSBoundParameters['InformationAction'] } else { $InformationPreference = 'Continue' } # Write warning when using deprecated 'schema-merge' action, otherwise set confirmation prompt for 'major' actions if ($Action -eq 'schema-merge') { Write-Warning 'The action [ schema-merge ] is deprecated! Use the [ refresh ] action as the supported way to update a container.' $ConfirmPreference = 'Medium' } elseif ($Action -eq 'refresh' -and -not $Force) { $ConfirmPreference = 'Medium' } $moduleName = $MyInvocation.MyCommand.Module.Name if ([string]::IsNullOrEmpty($moduleName)) { Write-Error 'This function is not loaded as part of a module or the module name is unavailable.' -ErrorAction Stop } $modulePath = (Get-Module -Name $moduleName).Path if ($Id.Count -gt 1) { # Check if the ForEach-Object cmdlet supports the Parallel parameter $supportsParallel = ((Get-Command ForEach-Object).Parameters.keys) -contains 'Parallel' # Create shared runspace pool for parallel tasks if (!$supportsParallel) { $runspacePool = [runspacefactory]::CreateRunspacePool(1, $ThrottleLimit) $runspacePool.Open() $runspaceQueue = [System.Collections.Concurrent.ConcurrentQueue[PSCustomObject]]::new() } } } process { if ($Id.Count -eq 1) { # Process a single container ID without parallel processing $n = $Id[0] $requestPath = "/api/v2/containers/$n/actions/$Action" if ($Force -or $PSCmdlet.ShouldProcess("Container [ ID: $n ]", "[ $Action ]")) { # Try to get the container name to output for the ID when using the Verbose preference if ($VerbosePreference -eq 'Continue') { try { $containerName = (Get-DBPoolContainer -Id $n -ErrorAction stop -Verbose:($VerbosePreference -eq 'SilentlyContinue')).name } catch { Write-Error "Failed to get the container name for ID $n. $_" $containerName = '## FailedToGetContainerName ##' } } Write-Verbose "Performing action [ $Action ] on Container [ ID: $n, Name: $containerName ]" try { $requestResponse = Invoke-DBPoolRequest -method $method -resource_Uri $requestPath -ErrorAction Stop if ($requestResponse.StatusCode -eq 204) { Write-Information "Success: Invoking Action [ $Action ] on Container [ ID: $n ]." } } catch { Write-Error $_ } } } elseif ($supportsParallel) { $IdsToProcess = [System.Collections.ArrayList]::new() foreach ($n in $Id) { if ($Force -or $PSCmdlet.ShouldProcess("Container [ ID: $n ]", "[ $Action ]")) { $IdsToProcess.Add($n) | Out-Null } } if ($IdsToProcess.Count -gt 0) { $IdsToProcess | ForEach-Object -Parallel { $n = $_ Import-Module $using:modulePath Add-DBPoolBaseURI -base_uri $using:DBPool_Base_URI Add-DBPoolApiKey -apiKey $using:DBPool_ApiKey $requestPath = "/api/v2/containers/$n/actions/$using:Action" # Try to get the container name to output for the ID when using the Verbose preference if ($using:VerbosePreference -eq 'Continue') { try { $containerName = (Get-DBPoolContainer -Id $n -ErrorAction Stop).name } catch { Write-Error "Failed to get the container name for ID $n. $_" $containerName = '## FailedToGetContainerName ##' } } Write-Verbose "Performing action [ $using:Action ] on Container [ ID: $n, Name: $containerName ]" -Verbose:($using:VerbosePreference -eq 'Continue') try { $requestResponse = Invoke-DBPoolRequest -method $using:method -resource_Uri $requestPath -ErrorAction Stop -WarningAction:SilentlyContinue if ($requestResponse.StatusCode -eq 204) { Write-Information "Success: Invoking Action [ $using:Action ] on Container [ ID: $n ]." } } catch { Write-Error $_ } } -ThrottleLimit $ThrottleLimit -TimeoutSeconds $TimeoutSeconds } } else { # Process each container ID in parallel using runspaces where the ForEach-Object cmdlet does not support the Parallel parameter in Windows PowerShell 5.1 _(or version prior to [PowerShell 7.0](https://devblogs.microsoft.com/powershell/powershell-foreach-object-parallel-feature/))_ # This is a manual implementation workaround of parallel processing using runspaces # TODO: Refactor to use [Invoke-Parallel](https://github.com/RamblingCookieMonster/Invoke-Parallel), or [PSParallelPipeline](https://github.com/santisq/PSParallelPipeline) module for parallel processing for better performance optimization as current implementation appears to have high performance overheard foreach ($n in $Id) { $requestPath = "/api/v2/containers/$n/actions/$Action" if ($Force -or $PSCmdlet.ShouldProcess("Container [ ID: $n ]", "[ $Action ]")) { # Try to get the container name to output for the ID when using the Verbose preference if ($VerbosePreference -eq 'Continue') { try { $containerName = (Get-DBPoolContainer -Id $n -ErrorAction stop -Verbose:($VerbosePreference -eq 'SilentlyContinue')).name } catch { Write-Error "Failed to get the container name for ID $n. $_" $containerName = '## FailedToGetContainerName ##' } } Write-Verbose "Performing action [ $Action ] on Container [ ID: $n, Name: $containerName ]" $runspace = [powershell]::Create().AddScript({ param ($method, $requestPath, $modulePath, $baseUri, $apiKey, $containerId) Import-Module $modulePath Add-DBPoolBaseURI -base_uri $baseUri Add-DBPoolApiKey -apiKey $apiKey $VerbosePreference = $VerbosePreference try { $requestResponse = Invoke-DBPoolRequest -method $method -resource_Uri $requestPath -ErrorAction Stop return [pscustomobject]@{ Success = $true StatusCode = $requestResponse.StatusCode Content = $requestResponse.Content ContainerId = $containerId } } catch { return [pscustomobject]@{ Success = $false ErrorMessage = $_.Exception.Message ErrorDetails = $_.Exception.ToString() ContainerId = $containerId } } }).AddArgument($method).AddArgument($requestPath).AddArgument($modulePath).AddArgument($DBPool_Base_URI).AddArgument($DBPool_ApiKey).AddArgument($n) $runspaceQueue.Enqueue([PSCustomObject]@{ Pipe = $runspace; ContainerId = $n; Status = $runspace.BeginInvoke(); StartTime = [datetime]::Now }) } } # Initialize sleep control variables $sleepDuration = 1 # Initial sleep duration in seconds $i = 0 # Counter to track iterations $initialThreshold = 10 # Initial threshold to increase sleep duration $maxSleepDuration = 60 # Maximum sleep duration in seconds # Process results as they complete or timeout while ($runspaceQueue.Count -gt 0) { $task = $null while ($runspaceQueue.TryDequeue([ref]$task)) { if ($task.Status.IsCompleted) { $result = $task.Pipe.EndInvoke($task.Status) $task.Pipe.Dispose() if ($result.Success) { $statusCode = $result.StatusCode if ($statusCode -eq 204) { Write-Information "Success: Invoking Action [ $Action ] on Container [ ID: $($result.ContainerId) ]." } else { Write-Error "Failed: Status $statusCode. Response: $($result.Content)" } } else { Write-Error "$($result.ErrorMessage)" } } elseif ($TimeoutSeconds -gt 0 -and $(([datetime]::Now - $task.StartTime).TotalSeconds) -ge $TimeoutSeconds) { Write-Error "Action [ $Action ] on Container [ ID: $($task.ContainerId) ] exceeded timeout of $TimeoutSeconds seconds." $task.Pipe.Stop() $task.Pipe.Dispose() } else { # If task has neither completed nor timed out, re-enqueue it $runspaceQueue.Enqueue($task) } } Start-Sleep -Seconds $sleepDuration # Increment the counter $i++ # Check if the counter has reached the dynamic threshold if ($i -ge $threshold) { # Increase the sleep duration exponentially $sleepDuration = [math]::Min($sleepDuration * 2, $maxSleepDuration) # Increase the threshold linearly $threshold += $initialThreshold # Reset the counter $i = 0 } } } } end { # Close and dispose of the runspace pool if ($Id.Count -gt 1 -and !$supportsParallel) { $runspacePool.Close() $runspacePool.Dispose() } } } #EndRegion #Region function Invoke-DBPoolDebug { <# .SYNOPSIS Provides an example exception response from the DBPool API for debugging purposes. .DESCRIPTION Uses the Invoke-DBPoolRequest function to make a request to the DBPool API. Returns an example exception response for debugging and testing purposes. .PARAMETER method The HTTP method to use when making the request to the DBPool API. Default is 'GET'. .INPUTS N/A .OUTPUTS [System.Management.Automation.ErrorRecord] - Returns an example exception response from the DBPool API. .EXAMPLE Invoke-DBPoolDebug -method GET Sends a 'GET' request to the DBPool API and returns a '418' exception response error. .NOTES N/A .LINK N/A #> [CmdletBinding()] [OutputType([System.Management.Automation.ErrorRecord])] param ( [Parameter(Mandatory = $false)] [ValidateSet('DELETE', 'GET', 'PATCH', 'POST')] [string]$method = 'GET' ) begin { $requestPath = '/api/docs/error' } process { Write-Debug "Invoking DBPool Debug Exception API with method [ $method ]" try { $response = Invoke-DBPoolRequest -method $method -resource_Uri $requestPath -ErrorAction Stop } catch { Write-Error $_ } if ($null -ne $response) { $response = $response | ConvertFrom-Json } # Return the response $response } end {} } #EndRegion #Region function Get-DBPoolOpenAPI { <# .SYNOPSIS Gets the DBPool OpenAPI documentation. .DESCRIPTION Gets the OpenAPI json spec for the DBPool API documentation. .PARAMETER OpenAPI_Path The path to the OpenAPI json spec. This defaults to '/api/docs/openapi.json' .INPUTS N/A .OUTPUTS [PSCustomObject] - The OpenAPI json spec for the DBPool API documentation. .EXAMPLE Get-DBPoolOpenAPI This will get the OpenAPI json spec for the DBPool API documentation. .NOTES N/A .LINK N/A #> [CmdletBinding()] [Alias("Get-DBPoolApiSpec", "Get-DBPoolSwagger")] [OutputType([PSCustomObject])] param ( [Parameter(Mandatory = $false)] [string]$OpenAPI_Path = '/api/docs/openapi.json' ) begin { $requestPath = $OpenAPI_Path } process { try { $response = Invoke-DBPoolRequest -Method Get -resource_Uri $requestPath -ErrorAction Stop -WarningAction SilentlyContinue } catch { Write-Error $_ } if ($null -ne $response) { $response = $response | ConvertFrom-Json } # Return the response $response } end {} } #EndRegion #Region function Get-DBPoolUser { <# .SYNOPSIS Get a user from DBPool .DESCRIPTION The Get-DBPoolUser function is used to get a user details from DBPool. Default will get the current authenticated user details, but can be used to get any user details by username. .PARAMETER username The username of the user to get details for. This accepts an array of strings. .INPUTS [string] - The username of the user to get details for. .OUTPUTS [PSCustomObject] - The user details from DBPool. .EXAMPLE Get-DBPoolUser This will get the user details for the current authenticated user. .EXAMPLE Get-DBPoolUser -username "John.Doe" This will get the user details for the user "John.Doe". .NOTES N/A .LINK N/A #> [CmdletBinding(DefaultParameterSetName = 'Self')] [OutputType([PSCustomObject])] param ( [Parameter(ParameterSetName = 'User', Mandatory = $false, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]]$Username ) begin { $method = 'GET' } process { if ($null -eq $Username -or $Username.Count -eq 0) { Write-Verbose "Running the [ $($PSCmdlet.ParameterSetName) ] parameter set" try { $response = Invoke-DBPoolRequest -Method $method -resource_Uri '/api/v2/self' -ErrorAction Stop } catch { Write-Error $_ } if ($null -ne $response) { $response = $response | ConvertFrom-Json } } else { $response = foreach ($uName in $Username) { $requestResponse = $null Write-Verbose "Running the [ $($PSCmdlet.ParameterSetName) ] parameter set for Username $uName" $requestPath = "/api/v2/users/$uName" try { $requestResponse = Invoke-DBPoolRequest -Method $method -resource_Uri $requestPath -ErrorAction Stop } catch { Write-Error $_ } if ($null -ne $requestResponse) { $requestResponse | ConvertFrom-Json } } } # Return the response $response } end {} } #EndRegion # This section is used to dot source all the module functions for development if (Test-Path -Path $(Join-Path -Path $PSScriptRoot -ChildPath 'Public')) { # Directories to import from $directory = 'Public', 'Private' # Import functions $functionsToExport = @() foreach ($dir in $directory) { $Functions = @( Get-ChildItem -Path (Join-Path -Path $PSScriptRoot -ChildPath "$dir/*ps1") -Recurse -ErrorAction SilentlyContinue) foreach ($Import in @($Functions)) { try { . $Import.fullname $functionsToExport += $Import.BaseName } catch { throw "Could not import function [$($Import.fullname)]: $_" } } } Export-ModuleMember -Function $functionsToExport } |