├── release └── .gitkeep ├── GitVersion.yml ├── .vscode ├── PSShlink.code-workspace ├── launch.json └── tasks.json ├── .gitignore ├── src ├── PSShlink.psm1 ├── Public │ ├── Get-ShlinkServer.ps1 │ ├── Get-ShlinkDomains.ps1 │ ├── Set-ShlinkTag.ps1 │ ├── Get-ShlinkTags.ps1 │ ├── Get-ShlinkVisitsNonOrphan.ps1 │ ├── Get-ShlinkVisitsOrphan.ps1 │ ├── Set-ShlinkDomainRedirects.ps1 │ ├── Remove-ShlinkUrl.ps1 │ ├── Remove-ShlinkTag.ps1 │ ├── Invoke-ShlinkRestMethod.ps1 │ ├── Get-ShlinkVisits.ps1 │ ├── New-ShlinkUrl.ps1 │ ├── Set-ShlinkUrl.ps1 │ └── Get-ShlinkUrl.ps1 ├── PSShlink.Format.ps1xml ├── en-US │ └── about_PSShlink.help.txt ├── Private │ ├── GetShlinkConnection.ps1 │ └── InvokeShlinkRestMethod.ps1 └── PSShlink.psd1 ├── tests ├── invoke.tests.ps1 └── Public │ ├── Get-ShlinkServer.Tests.ps1 │ ├── Get-ShlinkDomains.Tests.ps1 │ ├── Get-ShlinkUrl.Tests.ps1 │ ├── Save-ShlinkUrlQrCode.Tests.ps1 │ ├── Set-ShlinkTag.Tests.ps1 │ ├── Get-ShlinkTags.Tests.ps1 │ ├── Remove-ShlinkTag.Tests.ps1 │ ├── Set-ShlinkUrl.Tests.ps1 │ ├── Get-ShlinkVisitsNonOrphan.Tests.ps1 │ ├── Remove-ShlinkUrl.Tests.ps1 │ ├── Get-ShlinkVisitsOrphan.Tests.ps1 │ ├── New-ShlinkUrl.Tests.ps1 │ └── Get-ShlinkVisits.Tests.ps1 ├── custom.build.ps1 ├── CONTRIBUTING.md ├── PSShlink.todo ├── docs ├── Get-ShlinkServer.md ├── Get-ShlinkDomains.md ├── Get-ShlinkTags.md ├── Set-ShlinkTag.md ├── Get-ShlinkVisitsNonOrphan.md ├── Get-ShlinkVisitsOrphan.md ├── Remove-ShlinkTag.md ├── Remove-ShlinkUrl.md ├── Set-ShlinkDomainRedirects.md ├── Invoke-ShlinkRestMethod.md ├── Get-ShlinkVisits.md ├── Save-ShlinkUrlQrCode.md ├── Get-ShlinkUrl.md ├── Set-ShlinkUrl.md └── New-ShlinkUrl.md ├── .github └── workflows │ └── pipeline.yml ├── README.md └── invoke.build.ps1 /release/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /GitVersion.yml: -------------------------------------------------------------------------------- 1 | mode: Mainline 2 | no-bump-message: '\+semver:\s?(none|skip)|^Released\s\d\.\d\.\d$' 3 | branches: 4 | hotfix: 5 | regex: ^(hot)?fix(es)?[/-] 6 | ignore: 7 | sha: [] 8 | merge-message-formats: {} -------------------------------------------------------------------------------- /.vscode/PSShlink.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": ".." 5 | } 6 | ], 7 | "settings": {}, 8 | "extensions": { 9 | "recommendations": [ 10 | "ms-vscode.PowerShell" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This file does not start with a period in the codaamok.build FileList because there seems to be an issue with using files in a module manifest's FileList starting with a period 2 | build/* 3 | !*.gitkeep 4 | release/* 5 | .DS_Store 6 | testResults.xml -------------------------------------------------------------------------------- /src/PSShlink.psm1: -------------------------------------------------------------------------------- 1 | $Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction "SilentlyContinue" ) 2 | $Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction "SilentlyContinue" ) 3 | 4 | Foreach($import in @($Public + $Private)) { 5 | try { 6 | . $import.fullname 7 | } 8 | catch { 9 | Write-Error -Message "Failed to import function $($import.fullname): $_" 10 | } 11 | } 12 | Export-ModuleMember -Function $Public.Basename -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "PowerShell: Interactive Session", 9 | "type": "PowerShell", 10 | "request": "launch", 11 | "cwd": "" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /tests/invoke.tests.ps1: -------------------------------------------------------------------------------- 1 | $PesterConfig = New-PesterConfiguration -Hashtable @{ 2 | Run = @{ 3 | Path = @( 4 | '{0}/Public/New-*.Tests.ps1' -f $PSScriptRoot 5 | '{0}/Public/Get-*.Tests.ps1' -f $PSScriptRoot 6 | '{0}/Public/Save-*.Tests.ps1' -f $PSScriptRoot 7 | '{0}/Public/Set-ShlinkUrl.Tests.ps1' -f $PSScriptRoot 8 | '{0}/Public/Set-ShlinkTag.Tests.ps1' -f $PSScriptRoot 9 | '{0}/Public/Remove-*.Tests.ps1' -f $PSScriptRoot 10 | ) 11 | Throw = $true 12 | SkipRemainingOnFailure = 'Block' 13 | } 14 | Output = @{ 15 | Verbosity = 'Detailed' 16 | } 17 | TestResult = @{ 18 | Enabled = $true 19 | OutputFormat = 'NUnit2.5' 20 | } 21 | } 22 | 23 | Invoke-Pester -Configuration $PesterConfig -ErrorAction 'Stop' 24 | -------------------------------------------------------------------------------- /custom.build.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Build script which leverages the InvokeBuild module. 4 | .DESCRIPTION 5 | Build script which leverages the InvokeBuild module. 6 | This build script is used in the build pipeline and local development for building this project. 7 | Invoked by invoke.build.ps1 in this project where its intent is to implement project-specific custom pre/post build actions during the build pipeline andds local development. 8 | #> 9 | [CmdletBinding()] 10 | param ( 11 | [Parameter()] 12 | [ValidateNotNullOrEmpty()] 13 | [String]$ModuleName, 14 | 15 | [Parameter()] 16 | [ValidateNotNullOrEmpty()] 17 | [String]$Author, 18 | 19 | [Parameter()] 20 | [String]$Version, 21 | 22 | [Parameter()] 23 | [Bool]$NewRelease 24 | ) 25 | 26 | task PreBuild { 27 | 28 | } 29 | 30 | task PostBuild { 31 | 32 | } 33 | 34 | task PreRelease { 35 | 36 | } 37 | 38 | task PostRelease { 39 | 40 | } 41 | -------------------------------------------------------------------------------- /tests/Public/Get-ShlinkServer.Tests.ps1: -------------------------------------------------------------------------------- 1 | BeforeAll { 2 | # Always use built code if running in a pipeline 3 | if ($env:USER -eq 'runner') { 4 | Import-Module "$PSScriptRoot/../../build/PSShlink/PSShlink.psd1" -Force 5 | } 6 | # Check if module is already imported, as it can be via VSCode task where you can choose what code base to test 7 | # and you might not want to cloober it with the non-built code 8 | elseif (-not (Get-Module PSShlink)) { 9 | Import-Module "$PSScriptRoot/../../src/PSShlink.psd1" -Force 10 | } 11 | } 12 | 13 | Describe "Get-ShlinkServer" { 14 | It "Returns Shlink instance information" { 15 | $Params = @{ 16 | ShlinkServer = $env:ShlinkServer 17 | ErrorAction = 'Stop' 18 | } 19 | $Object = Get-ShlinkServer @Params 20 | $Object.status | Should -Be 'Pass' 21 | [System.Version]$Object.version | Should -BeOfType [System.Version] 22 | } 23 | } -------------------------------------------------------------------------------- /tests/Public/Get-ShlinkDomains.Tests.ps1: -------------------------------------------------------------------------------- 1 | BeforeAll { 2 | # Always use built code if running in a pipeline 3 | if ($env:USER -eq 'runner') { 4 | Import-Module "$PSScriptRoot/../../build/PSShlink/PSShlink.psd1" -Force 5 | } 6 | # Check if module is already imported, as it can be via VSCode task where you can choose what code base to test 7 | # and you might not want to cloober it with the non-built code 8 | elseif (-not (Get-Module PSShlink)) { 9 | Import-Module "$PSScriptRoot/../../src/PSShlink.psd1" -Force 10 | } 11 | } 12 | 13 | Describe "Get-ShlinkDomains" { 14 | It "Returns domains configured with Shlink" { 15 | $Params = @{ 16 | ShlinkServer = $env:ShlinkServer 17 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 18 | ErrorAction = 'Stop' 19 | } 20 | $Object = Get-ShlinkDomains @Params 21 | $Object.data.domain | Should -Be 'psshlink.codaamok' 22 | $Object.data.isDefault | Should -BeTrue 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/Public/Get-ShlinkUrl.Tests.ps1: -------------------------------------------------------------------------------- 1 | BeforeAll { 2 | # Always use built code if running in a pipeline 3 | if ($env:USER -eq 'runner') { 4 | Import-Module "$PSScriptRoot/../../build/PSShlink/PSShlink.psd1" -Force 5 | } 6 | # Check if module is already imported, as it can be via VSCode task where you can choose what code base to test 7 | # and you might not want to cloober it with the non-built code 8 | elseif (-not (Get-Module PSShlink)) { 9 | Import-Module "$PSScriptRoot/../../src/PSShlink.psd1" -Force 10 | } 11 | } 12 | 13 | Describe "Get-ShlinkUrl" { 14 | It "Retrieve 'PSShlink-Test' short URL " -ForEach @( 15 | @{ Type = 'exactly'; Parameter = 'ShortCode'; Value = 'PSShlink-Test' } 16 | @{ Type = 'vaguely'; Parameter = 'SearchTerm'; Value = 'test' } 17 | ) { 18 | $Params = @{ 19 | $Parameter = $Value 20 | ShlinkServer = $env:ShlinkServer 21 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 22 | ErrorAction = 'Stop' 23 | } 24 | $Object = Get-ShlinkUrl @Params 25 | $Object.shortCode | Should -Be 'PSShlink-Test' 26 | $Object.shortUrl | Should -Be ('{0}/PSShlink-Test' -f $env:ShlinkServer) 27 | $Object.tags | Should -Be 'PSShlinkTag1', 'PSShlinkTag2' 28 | $Object.longUrl | Should -Be 'https://google.co.uk' 29 | } 30 | } -------------------------------------------------------------------------------- /tests/Public/Save-ShlinkUrlQrCode.Tests.ps1: -------------------------------------------------------------------------------- 1 | BeforeAll { 2 | # Check if module is already imported, as it can be via VSCode task where you can choose what code base to test 3 | # and you might not want to cloober it with the non-built code 4 | if (-not (Get-Module PSShlink)) { 5 | Import-Module $PSScriptRoot/../../src/PSShlink.psd1 -Force 6 | } 7 | } 8 | 9 | Describe "Save-ShlinkUrlQrCode" { 10 | It "Create '' QR code image file of expected SHA256 hash ''" -TestCases @( 11 | @{ Format = 'png'; SHA256 = 'A3D4EA74661878D8AB15AD864705AB43A095D5B60416F0B33F3E5212EEB527EF' } 12 | @{ Format = 'svg'; SHA256 = '380E532048FD830255CF8C34579D92813CB0B78F131D0E5790257A3155943391' } 13 | ) { 14 | $Params = @{ 15 | Path = $TestDrive 16 | ShortCode = 'PSShlink-Test' 17 | Format = $Format 18 | Size = 100 19 | Margin = 10 20 | ErrorCorrection = 'L' 21 | RoundBlockSize = $false 22 | ShlinkServer = $env:ShlinkServer 23 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 24 | PassThru = $true 25 | ErrorAction = 'Stop' 26 | } 27 | $File = Save-ShlinkUrlQrCode @Params 28 | 29 | (Get-FileHash $File -Algorithm SHA256).Hash | Should -Be $SHA256 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/Public/Set-ShlinkTag.Tests.ps1: -------------------------------------------------------------------------------- 1 | BeforeAll { 2 | # Always use built code if running in a pipeline 3 | if ($env:USER -eq 'runner') { 4 | Import-Module "$PSScriptRoot/../../build/PSShlink/PSShlink.psd1" -Force 5 | } 6 | # Check if module is already imported, as it can be via VSCode task where you can choose what code base to test 7 | # and you might not want to cloober it with the non-built code 8 | elseif (-not (Get-Module PSShlink)) { 9 | Import-Module "$PSScriptRoot/../../src/PSShlink.psd1" -Force 10 | } 11 | } 12 | 13 | Describe "Set-ShlinkTag" { 14 | It "Rename an existing tag" { 15 | $Params = @{ 16 | OldTagName = 'psshlinktag3' 17 | NewTagName = 'psshlinktag5' 18 | ShlinkServer = $env:ShlinkServer 19 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 20 | ErrorAction = 'Stop' 21 | } 22 | Set-ShlinkTag @Params 23 | 24 | $Params = @{ 25 | OldTagName = 'psshlinktag3' 26 | NewTagName = 'psshlinktag5' 27 | ShlinkServer = $env:ShlinkServer 28 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 29 | ErrorAction = 'Stop' 30 | } 31 | $Object = Get-ShlinkTags -SearchTerm 'psshlinktag5' 32 | $Object.Count | Should -Be 1 33 | $Object.tag | Should -Be 'psshlinktag5' 34 | } 35 | } -------------------------------------------------------------------------------- /tests/Public/Get-ShlinkTags.Tests.ps1: -------------------------------------------------------------------------------- 1 | BeforeAll { 2 | # Always use built code if running in a pipeline 3 | if ($env:USER -eq 'runner') { 4 | Import-Module "$PSScriptRoot/../../build/PSShlink/PSShlink.psd1" -Force 5 | } 6 | # Check if module is already imported, as it can be via VSCode task where you can choose what code base to test 7 | # and you might not want to cloober it with the non-built code 8 | elseif (-not (Get-Module PSShlink)) { 9 | Import-Module "$PSScriptRoot/../../src/PSShlink.psd1" -Force 10 | } 11 | } 12 | 13 | Describe "Get-ShlinkTags" { 14 | It "Returns all tags on the Shlink instance" { 15 | $Params = @{ 16 | ShlinkServer = $env:ShlinkServer 17 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 18 | ErrorAction = 'Stop' 19 | } 20 | $Object = Get-ShlinkTags @Params 21 | $Object.tag | Should -Be 'psshlinktag1', 'psshlinktag2' 22 | $Object.shortUrlsCount | Should -Be '1','1' 23 | } 24 | 25 | It "Returns tags on Shlink instance using search term '<_>'" -ForEach 1,2 { 26 | $Params = @{ 27 | SearchTerm = $_ 28 | ShlinkServer = $env:ShlinkServer 29 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 30 | ErrorAction = 'Stop' 31 | } 32 | $Object = Get-ShlinkTags @Params 33 | $Object.tag | Should -Be ('psshlinktag{0}' -f $_) 34 | } 35 | } -------------------------------------------------------------------------------- /src/Public/Get-ShlinkServer.ps1: -------------------------------------------------------------------------------- 1 | function Get-ShlinkServer { 2 | <# 3 | .SYNOPSIS 4 | Checks the healthiness of the service, making sure it can access required resources. 5 | .DESCRIPTION 6 | Checks the healthiness of the service, making sure it can access required resources. 7 | 8 | https://api-spec.shlink.io/#/Monitoring/health 9 | .PARAMETER ShlinkServer 10 | The URL of your Shlink server (including schema). For example "https://example.com". 11 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 12 | .EXAMPLE 13 | PS C:\> Get-ShlinkServer 14 | 15 | Returns the healthiness of the service. 16 | .INPUTS 17 | This function does not accept pipeline input. 18 | .OUTPUTS 19 | System.Management.Automation.PSObject 20 | #> 21 | [CmdletBinding()] 22 | param ( 23 | [Parameter()] 24 | [String]$ShlinkServer 25 | ) 26 | 27 | try { 28 | GetShlinkConnection -Server $ShlinkServer -ServerOnly 29 | } 30 | catch { 31 | Write-Error -ErrorRecord $_ -ErrorAction "Stop" 32 | } 33 | 34 | $Uri = "{0}/rest/health" -f $Script:ShlinkServer 35 | 36 | try { 37 | Invoke-RestMethod -Uri $Uri -ErrorAction "Stop" 38 | } 39 | catch { 40 | Write-Error -ErrorRecord $_ 41 | } 42 | } -------------------------------------------------------------------------------- /src/PSShlink.Format.ps1xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PSShlinkVisits 6 | 7 | PSShlinkVisits 8 | 9 | 10 | 11 | 12 | 13 | 14 | date 15 | 16 | 17 | referer 18 | 19 | 20 | userAgent 21 | 22 | 23 | visitLocation 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | PSShlinkDomains 32 | 33 | PSShlinkDomains 34 | 35 | 36 | 37 | 38 | 39 | 40 | data 41 | 42 | 43 | defaultRedirects 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /tests/Public/Remove-ShlinkTag.Tests.ps1: -------------------------------------------------------------------------------- 1 | BeforeAll { 2 | # Always use built code if running in a pipeline 3 | if ($env:USER -eq 'runner') { 4 | Import-Module "$PSScriptRoot/../../build/PSShlink/PSShlink.psd1" -Force 5 | } 6 | # Check if module is already imported, as it can be via VSCode task where you can choose what code base to test 7 | # and you might not want to cloober it with the non-built code 8 | elseif (-not (Get-Module PSShlink)) { 9 | Import-Module "$PSScriptRoot/../../src/PSShlink.psd1" -Force 10 | } 11 | } 12 | 13 | Describe "Remove-ShlinkTag" { 14 | It "Removes a tag from the Shlink instance (WhatIf enabled: )" -TestCases @( 15 | @{ WhatIf = $true } 16 | @{ WhatIf = $false } 17 | ) { 18 | $Params = @{ 19 | ShlinkServer = $env:ShlinkServer 20 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 21 | ErrorAction = 'Stop' 22 | } 23 | 24 | Remove-ShlinkTag -Tag 'psshlinktag1' -Confirm:$false -WhatIf:$WhatIf @Params 25 | 26 | switch ($WhatIf) { 27 | $true { 28 | Get-ShlinkTags -SearchTerm 'psshlinktag1' @Params | Should -Not -BeNullOrEmpty 29 | } 30 | $false { 31 | Get-ShlinkTags -SearchTerm 'psshlinktag1' @Params | Should -BeNullOrEmpty 32 | } 33 | } 34 | } 35 | 36 | It "Remove all tags" { 37 | $Params = @{ 38 | ShlinkServer = $env:ShlinkServer 39 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 40 | ErrorAction = 'Stop' 41 | } 42 | 43 | Get-ShlinkTags @Params | Remove-ShlinkTag @Params -Confirm:$false 44 | 45 | Get-ShlinkTags @Params | Should -BeNullOrEmpty 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Kindly adhere to the principles detailed in this document while contributing. 4 | 5 | This project leverages [GitVersion](https://gitversion.net) and tries to adhere to [SemVer](https://semver.org/). 6 | 7 | ## Issues 8 | 9 | ### Bug reports 10 | 11 | Raise issues and bug reports with regards to this product in the Issues tab of this project. If an issue exists that might have something to do with yours, e.g. is the basis for something your are requesting, please link this issue to yours. 12 | 13 | Provide as much detail as possible. Spare no detail when it comes to logs, console output, or screenshots. 14 | 15 | ### Fixing an issue 16 | 17 | If you're interested in fixing an issue in this project, firstly, thank you! 18 | 19 | 1. Contact or discussion ahead of your contribution is encouraged, even if it is just to soundboard. Reach me via email or on [Twitter](https://twitter.com/codaamok), or simply raise an issue or comment on an existing one. 20 | 2. Fork the repository and create a branch off of `main`/`master` 21 | 1. If you're creating a new feature, name your branch `feature/`. If you're fixing a bug, name your branch `fix/`. 22 | 3. Write your code 23 | 4. Update CHANGELOG.md with your changes (preferably using the [ChangeLogManagement](https://www.powershellgallery.com/packages/ChangelogManagement) PowerShell module for formatting consistency) 24 | 5. For good measure, check for any changes to the repo: 25 | ```powershell 26 | git remote add upstream https://github.com/codaamok/ 27 | git fetch upstream 28 | # If there are changes, pull and work on merge conflicts 29 | git pull --rebase upstream develop 30 | ``` 31 | 6. Make sure you have pushed your commits to your new branch and then create a pull request 32 | -------------------------------------------------------------------------------- /PSShlink.todo: -------------------------------------------------------------------------------- 1 | ✔ look in to more object orientated way to build uri with parameters and queries for InvokeRestMethod @done (04/11/2020, 21:14:27) 2 | ✔ need to select & expand shortUrls/data if no parameter/query is passed for InvokeRestMethod, and omit if parameter/query is passed @done (04/11/2020, 21:14:21) 3 | ✔ create format data file @done (17/11/2020, 19:52:28) 4 | ✔ create comment based help @done (17/11/2020, 20:11:39) 5 | ✔ flesh out the read me @done (24/11/2020, 22:40:15) 6 | ✔ decide whether to make 5.1 or 7 the minimum powershell verison @done (17/11/2020, 20:11:49) 7 | ✔ would be cool to save QR code to file, maybe with Get-ShlinkUrl ? @done (18/11/2020, 00:08:11) 8 | ✔ note or investigate whether can get QR code for short codes for non-default domain @done (22/11/2020, 14:49:46) 9 | ✔ fill out CBH for it @done (22/11/2020, 15:03:58) 10 | ✔ consider dropping begin{} process{} end{} blocks where appropriate @done (24/11/2020, 22:40:09) 11 | ✔ add pipeline support to remove/set @done (24/11/2020, 22:40:01) 12 | ✔ consider disabling parameter positional binding on some commands for the benefit of clear command syntax when user uses Get-Help @done (27/11/2020, 22:03:36) 13 | ✔ check if things like shortcodes exist and inform user if they don't before making changes to them @done (27/11/2020, 22:03:22) 14 | ✔ create proper error records @done (27/11/2020, 22:03:12) 15 | ✔ update CBH where pipeline support has been added @done (25/11/2020, 22:58:01) 16 | ☐ add support to InvokeShlinkRestMethod so it can call endpoints without the hardcoded root of /rest/v2, would help Save-ShlinkUrlQrCode and Get-ShlinkServer 17 | ☐ ditch use of enumerating over bound parameters when trying to discern user supplied parameters, it's not appropriate. not a big deal though 18 | ☐ add Get-ShlinkUrl to Remove-ShlinkUrl so can include long url in the shouldprocess messages -------------------------------------------------------------------------------- /tests/Public/Set-ShlinkUrl.Tests.ps1: -------------------------------------------------------------------------------- 1 | BeforeAll { 2 | # Always use built code if running in a pipeline 3 | if ($env:USER -eq 'runner') { 4 | Import-Module "$PSScriptRoot/../../build/PSShlink/PSShlink.psd1" -Force 5 | } 6 | # Check if module is already imported, as it can be via VSCode task where you can choose what code base to test 7 | # and you might not want to cloober it with the non-built code 8 | elseif (-not (Get-Module PSShlink)) { 9 | Import-Module "$PSScriptRoot/../../src/PSShlink.psd1" -Force 10 | } 11 | } 12 | 13 | Describe "Set-ShlinkUrl" { 14 | It "Update an existing short code" { 15 | $Date = Get-Date '2000-01-01 00:00:00' 16 | $Params = @{ 17 | ShortCode = 'PSShlink-Test' 18 | LongUrl = 'https://google.com' 19 | Tags = 'psshlinktag3','psshlinktag4' 20 | ValidSince = $Date.AddDays(-1) 21 | ValidUntil = $Date.AddDays(1) 22 | MaxVisits = 100 23 | Title = 'Google (USA)' 24 | ForwardQuery = $false 25 | Crawlable = $true 26 | ShlinkServer = $env:ShlinkServer 27 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 28 | ErrorAction = 'Stop' 29 | } 30 | $Object = Set-ShlinkUrl @Params 31 | $Object.longUrl | Should -Be 'https://google.com' 32 | $Object.tags | Should -Be 'psshlinktag3','psshlinktag4' 33 | $Object.meta.validSince | Should -Be $Date.AddDays(-1) 34 | $Object.meta.validUntil | Should -Be $Date.AddDays(1) 35 | $Object.meta.maxVisits | Should -Be 100 36 | $Object.title | Should -be 'Google (USA)' 37 | $Object.forwardQuery | Should -BeFalse 38 | $Object.crawlable | Should -BeTrue 39 | } 40 | } -------------------------------------------------------------------------------- /tests/Public/Get-ShlinkVisitsNonOrphan.Tests.ps1: -------------------------------------------------------------------------------- 1 | BeforeAll { 2 | # Always use built code if running in a pipeline 3 | if ($env:USER -eq 'runner') { 4 | Import-Module "$PSScriptRoot/../../build/PSShlink/PSShlink.psd1" -Force 5 | } 6 | # Check if module is already imported, as it can be via VSCode task where you can choose what code base to test 7 | # and you might not want to cloober it with the non-built code 8 | elseif (-not (Get-Module PSShlink)) { 9 | Import-Module "$PSScriptRoot/../../src/PSShlink.psd1" -Force 10 | } 11 | } 12 | 13 | Describe "Get-ShlinkVisitsNonOrphan" { 14 | It "Get (non orphan) visit data for the Shlink instance" { 15 | $Params = @{ 16 | ShlinkServer = $env:ShlinkServer 17 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 18 | ErrorAction = 'Stop' 19 | } 20 | $Object = Get-ShlinkVisitsNonOrphan @Params 21 | $Count = $Object.Count 22 | $Url = '{0}/PSShlink-Test' -f $env:ShlinkServer 23 | Invoke-WebRequest $Url -ErrorAction 'Stop' 24 | $Object = Get-ShlinkVisitsNonOrphan @Params 25 | $Object.Count | Should -Be ($Count + 1) 26 | } 27 | 28 | It "Get (non orphan) visit data for the Shlink instance after a specified date" { 29 | Start-Sleep -Seconds 1 30 | $Date = Get-Date 31 | $Params = @{ 32 | StartDate = $Date 33 | ShlinkServer = $env:ShlinkServer 34 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 35 | ErrorAction = 'Stop' 36 | } 37 | $Object = Get-ShlinkVisitsNonOrphan @Params 38 | $Object | Should -BeNullOrEmpty 39 | $Url = '{0}/PSShlink-Test' -f $env:ShlinkServer 40 | Invoke-WebRequest $Url -ErrorAction 'Stop' 41 | $Object = Get-ShlinkVisitsNonOrphan @Params 42 | $Object.Count | Should -Be 1 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /docs/Get-ShlinkServer.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-ShlinkServer 9 | 10 | ## SYNOPSIS 11 | Checks the healthiness of the service, making sure it can access required resources. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Get-ShlinkServer [[-ShlinkServer] ] [] 17 | ``` 18 | 19 | ## DESCRIPTION 20 | Checks the healthiness of the service, making sure it can access required resources. 21 | 22 | https://api-spec.shlink.io/#/Monitoring/health 23 | 24 | ## EXAMPLES 25 | 26 | ### EXAMPLE 1 27 | ``` 28 | Get-ShlinkServer 29 | ``` 30 | 31 | Returns the healthiness of the service. 32 | 33 | ## PARAMETERS 34 | 35 | ### -ShlinkServer 36 | The URL of your Shlink server (including schema). 37 | For example "https://example.com". 38 | It is not required to use this parameter for every use of this function. 39 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 40 | 41 | ```yaml 42 | Type: String 43 | Parameter Sets: (All) 44 | Aliases: 45 | 46 | Required: False 47 | Position: 1 48 | Default value: None 49 | Accept pipeline input: False 50 | Accept wildcard characters: False 51 | ``` 52 | 53 | ### CommonParameters 54 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 55 | 56 | ## INPUTS 57 | 58 | ### This function does not accept pipeline input. 59 | ## OUTPUTS 60 | 61 | ### System.Management.Automation.PSObject 62 | ## NOTES 63 | 64 | ## RELATED LINKS 65 | -------------------------------------------------------------------------------- /tests/Public/Remove-ShlinkUrl.Tests.ps1: -------------------------------------------------------------------------------- 1 | BeforeAll { 2 | # Always use built code if running in a pipeline 3 | if ($env:USER -eq 'runner') { 4 | Import-Module "$PSScriptRoot/../../build/PSShlink/PSShlink.psd1" -Force 5 | } 6 | # Check if module is already imported, as it can be via VSCode task where you can choose what code base to test 7 | # and you might not want to cloober it with the non-built code 8 | elseif (-not (Get-Module PSShlink)) { 9 | Import-Module "$PSScriptRoot/../../src/PSShlink.psd1" -Force 10 | } 11 | } 12 | 13 | Describe "Remove-ShlinkUrl" { 14 | It "Removes a short code URL from the Shlink instance (WhatIf enabled: )" -TestCases @( 15 | @{ WhatIf = $true } 16 | @{ WhatIf = $false } 17 | ) { 18 | $Params = @{ 19 | ShortCode = 'PSShlink-Test' 20 | ShlinkServer = $env:ShlinkServer 21 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 22 | Confirm = $false 23 | WhatIf = $WhatIf 24 | ErrorAction = 'Stop' 25 | } 26 | Remove-ShlinkUrl @Params 27 | 28 | switch ($WhatIf) { 29 | $true { 30 | Get-ShlinkUrl -ShortCode 'PSShlink-Test' | Should -Not -BeNullOrEmpty 31 | } 32 | $false { 33 | { Get-ShlinkUrl -ShortCode 'PSShlink-Test' -ErrorAction 'Stop' } | Should -Throw -ExceptionType ([System.Management.Automation.ItemNotFoundException]) 34 | } 35 | } 36 | 37 | } 38 | 39 | It "Remove all short codes" { 40 | $Params = @{ 41 | ShlinkServer = $env:ShlinkServer 42 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 43 | ErrorAction = 'Stop' 44 | } 45 | 46 | Get-ShlinkUrl @Params | Remove-ShlinkUrl @Params -Confirm:$false 47 | 48 | Get-ShlinkUrl @Params | Should -BeNullOrEmpty 49 | } 50 | } -------------------------------------------------------------------------------- /src/Public/Get-ShlinkDomains.ps1: -------------------------------------------------------------------------------- 1 | function Get-ShlinkDomains { 2 | <# 3 | .SYNOPSIS 4 | Returns the list of all domains ever used, with a flag that tells if they are the default domain 5 | .DESCRIPTION 6 | Returns the list of all domains ever used, with a flag that tells if they are the default domain 7 | .PARAMETER ShlinkServer 8 | The URL of your Shlink server (including schema). For example "https://example.com". 9 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 10 | .PARAMETER ShlinkApiKey 11 | A SecureString object of your Shlink server's API key. 12 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 13 | .EXAMPLE 14 | PS C:\> Get-ShlinkDomains 15 | 16 | Returns the list of all domains ever used, with a flag that tells if they are the default domain 17 | .INPUTS 18 | This function does not accept pipeline input. 19 | .OUTPUTS 20 | System.Management.Automation.PSObject 21 | #> 22 | [CmdletBinding()] 23 | param ( 24 | [Parameter()] 25 | [String]$ShlinkServer, 26 | 27 | [Parameter()] 28 | [SecureString]$ShlinkApiKey 29 | ) 30 | 31 | try { 32 | GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey 33 | } 34 | catch { 35 | Write-Error -ErrorRecord $_ -ErrorAction "Stop" 36 | } 37 | 38 | $Params = @{ 39 | Endpoint = "domains" 40 | PropertyTree = "domains" 41 | PSTypeName = "PSShlinkDomains" 42 | ErrorAction = "Stop" 43 | } 44 | 45 | try { 46 | InvokeShlinkRestMethod @Params 47 | } 48 | catch { 49 | Write-Error -ErrorRecord $_ 50 | } 51 | } -------------------------------------------------------------------------------- /tests/Public/Get-ShlinkVisitsOrphan.Tests.ps1: -------------------------------------------------------------------------------- 1 | BeforeAll { 2 | # Always use built code if running in a pipeline 3 | if ($env:USER -eq 'runner') { 4 | Import-Module "$PSScriptRoot/../../build/PSShlink/PSShlink.psd1" -Force 5 | } 6 | # Check if module is already imported, as it can be via VSCode task where you can choose what code base to test 7 | # and you might not want to cloober it with the non-built code 8 | elseif (-not (Get-Module PSShlink)) { 9 | Import-Module "$PSScriptRoot/../../src/PSShlink.psd1" -Force 10 | } 11 | } 12 | 13 | Describe "Get-ShlinkVisitsOrphan" { 14 | It "Get (orphan) visit data for the Shlink instance" { 15 | $Params = @{ 16 | ShlinkServer = $env:ShlinkServer 17 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 18 | ErrorAction = 'Stop' 19 | } 20 | $Object = Get-ShlinkVisitsOrphan @Params 21 | $Count = $Object.Count 22 | try { 23 | $Url = '{0}/{1}' -f $env:ShlinkServer, (New-Guid).Guid 24 | Invoke-WebRequest $Url -ErrorAction 'Stop' 25 | } 26 | catch { 27 | $_.Exception.Response.StatusCode | Should -Be 'NotFound' 28 | } 29 | $Object = Get-ShlinkVisitsOrphan @Params 30 | $Object.Count | Should -Be ($Count + 1) 31 | } 32 | 33 | It "Get (orphan) visit data for the Shlink instance after a specified date" { 34 | Start-Sleep -Seconds 1 35 | $Date = Get-Date 36 | $Params = @{ 37 | StartDate = $Date 38 | ShlinkServer = $env:ShlinkServer 39 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 40 | ErrorAction = 'Stop' 41 | } 42 | $Object = Get-ShlinkVisitsOrphan @Params 43 | $Object | Should -BeNullOrEmpty 44 | try { 45 | $Url = '{0}/{1}' -f $env:ShlinkServer, (New-Guid).Guid 46 | Invoke-WebRequest $Url -ErrorAction 'Stop' 47 | } 48 | catch { 49 | $_.Exception.Response.StatusCode | Should -Be 'NotFound' 50 | } 51 | $Object = Get-ShlinkVisitsOrphan @Params 52 | $Object.Count | Should -Be 1 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/en-US/about_PSShlink.help.txt: -------------------------------------------------------------------------------- 1 | TOPIC 2 | about_PSShlink 3 | 4 | SHORT DESCRIPTION 5 | PSShlink is an unofficial PowerShell module for Shlink (https://shlink.io), 6 | an open-source self-hosted and PHP-based URL shortener application. 7 | 8 | LONG DESCRIPTION 9 | PSShlink is an unofficial PowerShell module for Shlink (https://shlink.io), 10 | an open-source self-hosted and PHP-based URL shortener application. 11 | 12 | To learn how to use any of the functions, it is recommended you make use of 13 | the command: `Get-Help `. For example, 14 | `Get-Help Get-ShlinkUrl` will show you how to use the Get-ShlinkUrl 15 | function. 16 | 17 | You can also find documentation for each of the functions of PSShlink on the 18 | project's GitHub repository: https://github.com/codaamok/PSShlink. 19 | 20 | If you experience any issues with PSShlink, please raise an issue on GitHub. 21 | 22 | AUTHENTICATION 23 | Each function will have two parameters for authentication to your Shlink 24 | instance: 25 | 26 | -ShlinkServer: a string value of the Shlink server address 27 | e.g. https://example.com 28 | -ShlinkApiKey: a SecureString value for the Shlink server's API key 29 | 30 | After using any function of PSShlink for the first time after importing the 31 | module - which have both parameters -ShlinkServer and -ShlinkApiKey * - it 32 | is not necessary to use the parameters again in subsequent uses for other 33 | functions of PSShlink. These values are held in memory for as long as the 34 | PowerShell session exists. 35 | 36 | * Some functions do not require both -ShlinkServer and -ShlinkApiKey, e.g. 37 | Get-ShlinkServer. Therefore if the first function you use after importing 38 | PSShlink accepts only -ShlinkServer, you will not be asked again for this 39 | value by other functions of PSShlink. You will however be prompted for the 40 | API key. Again, subsequent uses of other functions will no longer require 41 | -ShlinkServer and -ShlinkApiKey. 42 | 43 | If the first function you use after importing PSShlink requires 44 | -ShlinkServer and/or -ShlinkApiKey and you have not passed the parameter(s), 45 | you will be prompted for them. -------------------------------------------------------------------------------- /src/Public/Set-ShlinkTag.ps1: -------------------------------------------------------------------------------- 1 | function Set-ShlinkTag { 2 | <# 3 | .SYNOPSIS 4 | Renames an existing tag to a new value on the Shlink server. 5 | .DESCRIPTION 6 | Renames an existing tag to a new value on the Shlink server. 7 | .PARAMETER OldTagName 8 | The name of the old tag you want to change the name of. 9 | .PARAMETER NewTagName 10 | The name fo the new tag you want to the new name to be. 11 | .PARAMETER ShlinkServer 12 | The URL of your Shlink server (including schema). For example "https://example.com". 13 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 14 | .PARAMETER ShlinkApiKey 15 | A SecureString object of your Shlink server's API key. 16 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 17 | .EXAMPLE 18 | PS C:\> Set-ShlinkTag -OldTagName "oldwebsite" -NewTagName "veryoldwebsite" 19 | 20 | Updates the tag with the name "oldwebsite" to have a new name of "veryoldwebsite". 21 | .INPUTS 22 | This function does not accept pipeline input. 23 | .OUTPUTS 24 | System.Management.Automation.PSObject 25 | #> 26 | [CmdletBinding()] 27 | param ( 28 | [Parameter(Mandatory)] 29 | [String]$OldTagName, 30 | 31 | [Parameter(Mandatory)] 32 | [String]$NewTagName, 33 | 34 | [Parameter()] 35 | [String]$ShlinkServer, 36 | 37 | [Parameter()] 38 | [SecureString]$ShlinkApiKey 39 | ) 40 | 41 | try { 42 | GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey 43 | } 44 | catch { 45 | Write-Error -ErrorRecord $_ -ErrorAction "Stop" 46 | } 47 | 48 | $Params = @{ 49 | Endpoint = "tags" 50 | Method = "PUT" 51 | Body = @{ 52 | oldName = $OldTagName 53 | newName = $NewTagName 54 | } 55 | ErrorAction = "Stop" 56 | } 57 | 58 | try { 59 | InvokeShlinkRestMethod @Params 60 | } 61 | catch { 62 | Write-Error -ErrorRecord $_ 63 | } 64 | } -------------------------------------------------------------------------------- /docs/Get-ShlinkDomains.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-ShlinkDomains 9 | 10 | ## SYNOPSIS 11 | Returns the list of all domains ever used, with a flag that tells if they are the default domain 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Get-ShlinkDomains [[-ShlinkServer] ] [[-ShlinkApiKey] ] [] 17 | ``` 18 | 19 | ## DESCRIPTION 20 | Returns the list of all domains ever used, with a flag that tells if they are the default domain 21 | 22 | ## EXAMPLES 23 | 24 | ### EXAMPLE 1 25 | ``` 26 | Get-ShlinkDomains 27 | ``` 28 | 29 | Returns the list of all domains ever used, with a flag that tells if they are the default domain 30 | 31 | ## PARAMETERS 32 | 33 | ### -ShlinkServer 34 | The URL of your Shlink server (including schema). 35 | For example "https://example.com". 36 | It is not required to use this parameter for every use of this function. 37 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 38 | 39 | ```yaml 40 | Type: String 41 | Parameter Sets: (All) 42 | Aliases: 43 | 44 | Required: False 45 | Position: 1 46 | Default value: None 47 | Accept pipeline input: False 48 | Accept wildcard characters: False 49 | ``` 50 | 51 | ### -ShlinkApiKey 52 | A SecureString object of your Shlink server's API key. 53 | It is not required to use this parameter for every use of this function. 54 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 55 | 56 | ```yaml 57 | Type: SecureString 58 | Parameter Sets: (All) 59 | Aliases: 60 | 61 | Required: False 62 | Position: 2 63 | Default value: None 64 | Accept pipeline input: False 65 | Accept wildcard characters: False 66 | ``` 67 | 68 | ### CommonParameters 69 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 70 | 71 | ## INPUTS 72 | 73 | ### This function does not accept pipeline input. 74 | ## OUTPUTS 75 | 76 | ### System.Management.Automation.PSObject 77 | ## NOTES 78 | 79 | ## RELATED LINKS 80 | -------------------------------------------------------------------------------- /tests/Public/New-ShlinkUrl.Tests.ps1: -------------------------------------------------------------------------------- 1 | BeforeAll { 2 | # Always use built code if running in a pipeline 3 | if ($env:USER -eq 'runner') { 4 | Import-Module "$PSScriptRoot/../../build/PSShlink/PSShlink.psd1" -Force 5 | } 6 | # Check if module is already imported, as it can be via VSCode task where you can choose what code base to test 7 | # and you might not want to cloober it with the non-built code 8 | elseif (-not (Get-Module PSShlink)) { 9 | Import-Module "$PSScriptRoot/../../src/PSShlink.psd1" -Force 10 | } 11 | } 12 | 13 | Describe "New-ShlinkUrl" { 14 | It "New valid short URL" { 15 | $Params = @{ 16 | LongUrl = 'https://google.co.uk' 17 | CustomSlug = 'PSShlink-Test' 18 | Tags = 'psshlinktag1', 'psshlinktag2' 19 | ShlinkServer = $env:ShlinkServer 20 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 21 | ErrorAction = 'Stop' 22 | } 23 | $Object = New-ShlinkUrl @Params 24 | $Object.shortCode | Should -Be 'PSShlink-Test' 25 | $Object.shortUrl | Should -Be ('{0}/PSShlink-Test' -f $env:ShlinkServer) 26 | $Object.tags | Should -Be 'psshlinktag1', 'psshlinktag2' 27 | $Object.longUrl | Should -Be 'https://google.co.uk' 28 | } 29 | 30 | It "New invalid short URL" { 31 | $Guid = (New-Guid).Guid 32 | $Params = @{ 33 | LongUrl = 'https://{0}.com' -f ([String[]]$Guid * 3 -join '-') 34 | CustomSlug = $Guid 35 | ShlinkServer = $env:ShlinkServer 36 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 37 | ValidateUrl = $true 38 | ErrorAction = 'Stop' 39 | } 40 | { New-ShlinkUrl @Params } | Should -Throw -ExceptionType ([System.ArgumentException]) 41 | } 42 | 43 | It "New invalid short URL with validation off" { 44 | $Guid = (New-Guid).Guid 45 | $Url = 'https://{0}.com' -f ([String[]]$Guid * 3 -join '-') 46 | { Invoke-WebRequest -Uri $Url -ErrorAction 'Stop' } | Should -Throw -ExceptionType ([System.Net.Http.HttpRequestException]) 47 | $Params = @{ 48 | LongUrl = $Url 49 | CustomSlug = $Guid 50 | ShlinkServer = $env:ShlinkServer 51 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 52 | ValidateUrl = $false 53 | ErrorAction = 'Stop' 54 | } 55 | $Object = New-ShlinkUrl @Params 56 | $Object.shortCode | Should -Be $Guid 57 | $Object.shortUrl | Should -Be ('{0}/{1}' -f $env:ShlinkServer, $Guid) 58 | $Object.longUrl | Should -Be $Url 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Public/Get-ShlinkTags.ps1: -------------------------------------------------------------------------------- 1 | function Get-ShlinkTags { 2 | <# 3 | .SYNOPSIS 4 | Returns the list of all tags used in any short URL, including stats and ordered by name. 5 | .DESCRIPTION 6 | Returns the list of all tags used in any short URL, including stats and ordered by name. 7 | .PARAMETER SearchTerm 8 | A query used to filter results by searching for it on the tag name. 9 | .PARAMETER ShlinkServer 10 | The URL of your Shlink server (including schema). For example "https://example.com". 11 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 12 | .PARAMETER ShlinkApiKey 13 | A SecureString object of your Shlink server's API key. 14 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 15 | .EXAMPLE 16 | PS C:\> Get-ShlinkTags 17 | 18 | Returns the list of all tags used in any short URL, including stats and ordered by name. 19 | .EXAMPLE 20 | PS C:\> Get-ShlinkTags -SearchTerm "pwsh" 21 | 22 | Returns the list of all tags used in any short URL, including stats and ordered by name, where those match the term "pwsh" by name of tag. 23 | .INPUTS 24 | This function does not accept pipeline input. 25 | .OUTPUTS 26 | System.Management.Automation.PSObject 27 | #> 28 | [CmdletBinding()] 29 | param ( 30 | [Parameter()] 31 | [String]$SearchTerm, 32 | 33 | [Parameter()] 34 | [String]$ShlinkServer, 35 | 36 | [Parameter()] 37 | [SecureString]$ShlinkApiKey 38 | ) 39 | 40 | try { 41 | GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey 42 | } 43 | catch { 44 | Write-Error -ErrorRecord $_ -ErrorAction "Stop" 45 | } 46 | 47 | $QueryString = [System.Web.HttpUtility]::ParseQueryString('') 48 | 49 | $Params = @{ 50 | Endpoint = "tags" 51 | Path = "stats" 52 | PropertyTree = "tags", "data" 53 | } 54 | 55 | if ($PSBoundParameters.ContainsKey("SearchTerm")) { 56 | $QueryString.Add("searchTerm", $SearchTerm) 57 | } 58 | 59 | $Params["Query"] = $QueryString 60 | 61 | try { 62 | InvokeShlinkRestMethod @Params 63 | } 64 | catch { 65 | Write-Error -ErrorRecord $_ 66 | } 67 | } -------------------------------------------------------------------------------- /docs/Get-ShlinkTags.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-ShlinkTags 9 | 10 | ## SYNOPSIS 11 | Returns the list of all tags used in any short URL, including stats and ordered by name. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Get-ShlinkTags [[-SearchTerm] ] [[-ShlinkServer] ] [[-ShlinkApiKey] ] 17 | [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | Returns the list of all tags used in any short URL, including stats and ordered by name. 22 | 23 | ## EXAMPLES 24 | 25 | ### EXAMPLE 1 26 | ``` 27 | Get-ShlinkTags 28 | ``` 29 | 30 | Returns the list of all tags used in any short URL, including stats and ordered by name. 31 | 32 | ### EXAMPLE 2 33 | ``` 34 | Get-ShlinkTags -SearchTerm "pwsh" 35 | ``` 36 | 37 | Returns the list of all tags used in any short URL, including stats and ordered by name, where those match the term "pwsh" by name of tag. 38 | 39 | ## PARAMETERS 40 | 41 | ### -SearchTerm 42 | A query used to filter results by searching for it on the tag name. 43 | 44 | ```yaml 45 | Type: String 46 | Parameter Sets: (All) 47 | Aliases: 48 | 49 | Required: False 50 | Position: 1 51 | Default value: None 52 | Accept pipeline input: False 53 | Accept wildcard characters: False 54 | ``` 55 | 56 | ### -ShlinkServer 57 | The URL of your Shlink server (including schema). 58 | For example "https://example.com". 59 | It is not required to use this parameter for every use of this function. 60 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 61 | 62 | ```yaml 63 | Type: String 64 | Parameter Sets: (All) 65 | Aliases: 66 | 67 | Required: False 68 | Position: 2 69 | Default value: None 70 | Accept pipeline input: False 71 | Accept wildcard characters: False 72 | ``` 73 | 74 | ### -ShlinkApiKey 75 | A SecureString object of your Shlink server's API key. 76 | It is not required to use this parameter for every use of this function. 77 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 78 | 79 | ```yaml 80 | Type: SecureString 81 | Parameter Sets: (All) 82 | Aliases: 83 | 84 | Required: False 85 | Position: 3 86 | Default value: None 87 | Accept pipeline input: False 88 | Accept wildcard characters: False 89 | ``` 90 | 91 | ### CommonParameters 92 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 93 | 94 | ## INPUTS 95 | 96 | ### This function does not accept pipeline input. 97 | ## OUTPUTS 98 | 99 | ### System.Management.Automation.PSObject 100 | ## NOTES 101 | 102 | ## RELATED LINKS 103 | -------------------------------------------------------------------------------- /docs/Set-ShlinkTag.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Set-ShlinkTag 9 | 10 | ## SYNOPSIS 11 | Renames an existing tag to a new value on the Shlink server. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Set-ShlinkTag [-OldTagName] [-NewTagName] [[-ShlinkServer] ] 17 | [[-ShlinkApiKey] ] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | Renames an existing tag to a new value on the Shlink server. 22 | 23 | ## EXAMPLES 24 | 25 | ### EXAMPLE 1 26 | ``` 27 | Set-ShlinkTag -OldTagName "oldwebsite" -NewTagName "veryoldwebsite" 28 | ``` 29 | 30 | Updates the tag with the name "oldwebsite" to have a new name of "veryoldwebsite". 31 | 32 | ## PARAMETERS 33 | 34 | ### -OldTagName 35 | The name of the old tag you want to change the name of. 36 | 37 | ```yaml 38 | Type: String 39 | Parameter Sets: (All) 40 | Aliases: 41 | 42 | Required: True 43 | Position: 1 44 | Default value: None 45 | Accept pipeline input: False 46 | Accept wildcard characters: False 47 | ``` 48 | 49 | ### -NewTagName 50 | The name fo the new tag you want to the new name to be. 51 | 52 | ```yaml 53 | Type: String 54 | Parameter Sets: (All) 55 | Aliases: 56 | 57 | Required: True 58 | Position: 2 59 | Default value: None 60 | Accept pipeline input: False 61 | Accept wildcard characters: False 62 | ``` 63 | 64 | ### -ShlinkServer 65 | The URL of your Shlink server (including schema). 66 | For example "https://example.com". 67 | It is not required to use this parameter for every use of this function. 68 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 69 | 70 | ```yaml 71 | Type: String 72 | Parameter Sets: (All) 73 | Aliases: 74 | 75 | Required: False 76 | Position: 3 77 | Default value: None 78 | Accept pipeline input: False 79 | Accept wildcard characters: False 80 | ``` 81 | 82 | ### -ShlinkApiKey 83 | A SecureString object of your Shlink server's API key. 84 | It is not required to use this parameter for every use of this function. 85 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 86 | 87 | ```yaml 88 | Type: SecureString 89 | Parameter Sets: (All) 90 | Aliases: 91 | 92 | Required: False 93 | Position: 4 94 | Default value: None 95 | Accept pipeline input: False 96 | Accept wildcard characters: False 97 | ``` 98 | 99 | ### CommonParameters 100 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 101 | 102 | ## INPUTS 103 | 104 | ### This function does not accept pipeline input. 105 | ## OUTPUTS 106 | 107 | ### System.Management.Automation.PSObject 108 | ## NOTES 109 | 110 | ## RELATED LINKS 111 | -------------------------------------------------------------------------------- /src/Public/Get-ShlinkVisitsNonOrphan.ps1: -------------------------------------------------------------------------------- 1 | function Get-ShlinkVisitsNonOrphan { 2 | <# 3 | .SYNOPSIS 4 | Get the list of visits to all valid short URLs. 5 | .DESCRIPTION 6 | Get the list of visits to all valid short URLs. 7 | .PARAMETER StartDate 8 | A datetime object to filter the visit data where the start date is equal or greater than this value. 9 | .PARAMETER EndDate 10 | A datetime object to filter the visit data where its end date is equal or less than this value. 11 | .PARAMETER ExcludeBots 12 | Exclude visits from bots or crawlers. 13 | .PARAMETER ShlinkServer 14 | The URL of your Shlink server (including schema). For example "https://example.com". 15 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 16 | .PARAMETER ShlinkApiKey 17 | A SecureString object of your Shlink server's API key. 18 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 19 | .EXAMPLE 20 | PS C:\> Get-ShlinkVisitsNonOrphan 21 | 22 | Get the list of visits to all valid short URLs. 23 | .EXAMPLE 24 | PS C:\> Get-ShlinkVisitsNonOrphan -StartDate (Get-Date "2020-11-01") -EndDate (Get-Date "2020-12-01") -ExcludeBots 25 | 26 | Get the list of visits to all valid short URLs for the whole of November and excluding bots/crawlers. 27 | .INPUTS 28 | This function does not accept pipeline input. 29 | .OUTPUTS 30 | System.Management.Automation.PSObject 31 | #> 32 | [CmdletBinding()] 33 | param ( 34 | [Parameter()] 35 | [datetime]$StartDate, 36 | 37 | [Parameter()] 38 | [datetime]$EndDate, 39 | 40 | [Parameter()] 41 | [Switch]$ExcludeBots, 42 | 43 | [Parameter()] 44 | [String]$ShlinkServer, 45 | 46 | [Parameter()] 47 | [SecureString]$ShlinkApiKey 48 | ) 49 | 50 | try { 51 | GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey 52 | } 53 | catch { 54 | Write-Error -ErrorRecord $_ -ErrorAction "Stop" 55 | } 56 | 57 | $QueryString = [System.Web.HttpUtility]::ParseQueryString('') 58 | 59 | $Params = @{ 60 | Endpoint = "visits" 61 | Path = "non-orphan" 62 | PropertyTree = "visits", "data" 63 | } 64 | 65 | switch ($PSBoundParameters.Keys) { 66 | "StartDate" { 67 | $QueryString.Add("startDate", (Get-Date $StartDate -Format "yyyy-MM-ddTHH:mm:sszzzz")) 68 | } 69 | "EndDate" { 70 | $QueryString.Add("endDate", (Get-Date $EndDate -Format "yyyy-MM-ddTHH:mm:sszzzz")) 71 | } 72 | "ExcludeBots" { 73 | $QueryString.Add("excludeBots", "true") 74 | } 75 | } 76 | 77 | $Params["Query"] = $QueryString 78 | 79 | try { 80 | InvokeShlinkRestMethod @Params 81 | } 82 | catch { 83 | Write-Error -ErrorRecord $_ 84 | } 85 | } -------------------------------------------------------------------------------- /src/Public/Get-ShlinkVisitsOrphan.ps1: -------------------------------------------------------------------------------- 1 | function Get-ShlinkVisitsOrphan { 2 | <# 3 | .SYNOPSIS 4 | Get the list of visits to invalid short URLs, the base URL or any other 404. 5 | .DESCRIPTION 6 | Get the list of visits to invalid short URLs, the base URL or any other 404. 7 | .PARAMETER StartDate 8 | A datetime object to filter the visit data where the start date is equal or greater than this value. 9 | .PARAMETER EndDate 10 | A datetime object to filter the visit data where its end date is equal or less than this value. 11 | .PARAMETER ExcludeBots 12 | Exclude visits from bots or crawlers. 13 | .PARAMETER ShlinkServer 14 | The URL of your Shlink server (including schema). For example "https://example.com". 15 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 16 | .PARAMETER ShlinkApiKey 17 | A SecureString object of your Shlink server's API key. 18 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 19 | .EXAMPLE 20 | PS C:\> Get-ShlinkVisitsOrphan 21 | 22 | Get the list of visits to invalid short URLs, the base URL or any other 404. 23 | .EXAMPLE 24 | PS C:\> Get-ShlinkVisitsOrphan -StartDate (Get-Date "2020-11-01") -EndDate (Get-Date "2020-12-01") -ExcludeBots 25 | 26 | Get the list of visits to invalid short URLs, the base URL or any other 404, for the whole of November and excluding bots/crawlers. 27 | .INPUTS 28 | This function does not accept pipeline input. 29 | .OUTPUTS 30 | System.Management.Automation.PSObject 31 | #> 32 | [CmdletBinding()] 33 | param ( 34 | [Parameter()] 35 | [datetime]$StartDate, 36 | 37 | [Parameter()] 38 | [datetime]$EndDate, 39 | 40 | [Parameter()] 41 | [Switch]$ExcludeBots, 42 | 43 | [Parameter()] 44 | [String]$ShlinkServer, 45 | 46 | [Parameter()] 47 | [SecureString]$ShlinkApiKey 48 | ) 49 | 50 | try { 51 | GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey 52 | } 53 | catch { 54 | Write-Error -ErrorRecord $_ -ErrorAction "Stop" 55 | } 56 | 57 | $QueryString = [System.Web.HttpUtility]::ParseQueryString('') 58 | 59 | $Params = @{ 60 | Endpoint = "visits" 61 | Path = "orphan" 62 | PropertyTree = "visits", "data" 63 | } 64 | 65 | switch ($PSBoundParameters.Keys) { 66 | "StartDate" { 67 | $QueryString.Add("startDate", (Get-Date $StartDate -Format "yyyy-MM-ddTHH:mm:sszzzz")) 68 | } 69 | "EndDate" { 70 | $QueryString.Add("endDate", (Get-Date $EndDate -Format "yyyy-MM-ddTHH:mm:sszzzz")) 71 | } 72 | "ExcludeBots" { 73 | $QueryString.Add("excludeBots", "true") 74 | } 75 | } 76 | 77 | $Params["Query"] = $QueryString 78 | 79 | try { 80 | InvokeShlinkRestMethod @Params 81 | } 82 | catch { 83 | Write-Error -ErrorRecord $_ 84 | } 85 | } -------------------------------------------------------------------------------- /tests/Public/Get-ShlinkVisits.Tests.ps1: -------------------------------------------------------------------------------- 1 | BeforeAll { 2 | # Always use built code if running in a pipeline 3 | if ($env:USER -eq 'runner') { 4 | Import-Module "$PSScriptRoot/../../build/PSShlink/PSShlink.psd1" -Force 5 | } 6 | # Check if module is already imported, as it can be via VSCode task where you can choose what code base to test 7 | # and you might not want to cloober it with the non-built code 8 | elseif (-not (Get-Module PSShlink)) { 9 | Import-Module "$PSScriptRoot/../../src/PSShlink.psd1" -Force 10 | } 11 | } 12 | 13 | Describe "Get-ShlinkVisits" { 14 | It "Get summary of all the server's visits" { 15 | $Params = @{ 16 | ShlinkServer = $env:ShlinkServer 17 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 18 | ErrorAction = 'Stop' 19 | } 20 | $Object = Get-ShlinkVisits @Params 21 | $Object.Server | Should -Be $env:ShlinkServer 22 | [int]$Object.visitsCount | Should -BeOfType [int] 23 | } 24 | 25 | It "Get visit data for a specific domain" { 26 | $Params = @{ 27 | Domain = 'psshlink.codaamok' 28 | ShlinkServer = $env:ShlinkServer 29 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 30 | ErrorACtion = 'Stop' 31 | } 32 | $Object = Get-ShlinkVisits @Params 33 | $Count = $Object.count 34 | Invoke-WebRequest 'http://psshlink.codaamok/PSShlink-Test' -ErrorAction 'Stop' 35 | $Object = Get-ShlinkVisits @Params 36 | $Object.Count | Should -Be ($Count + 1) 37 | } 38 | 39 | It "Get visit data for a specific shortcode" { 40 | $Params = @{ 41 | ShortCode = 'PSShlink-Test' 42 | ShlinkServer = $env:ShlinkServer 43 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 44 | ErrorAction = 'Stop' 45 | } 46 | $Object = Get-ShlinkVisits @Params 47 | $Count = $Object.count 48 | Invoke-WebRequest 'http://psshlink.codaamok/PSShlink-Test' -ErrorAction 'Stop' 49 | $Object = Get-ShlinkVisits @Params 50 | $Object.Count | Should -Be ($Count + 1) 51 | } 52 | 53 | It "Get visit data for tag 'psshlinktag<_>'" -TestCases 1,2 { 54 | $Params = @{ 55 | Tag = 'psshlinktag{0}' -f $_ 56 | ShlinkServer = $env:ShlinkServer 57 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 58 | ErrorAction = 'Stop' 59 | } 60 | $Object = Get-ShlinkVisits @Params 61 | $Count = $Object.count 62 | Invoke-WebRequest 'http://psshlink.codaamok/PSShlink-Test' -ErrorAction 'Stop' 63 | $Object = Get-ShlinkVisits @Params 64 | $Object.Count | Should -Be ($Count + 1) 65 | } 66 | 67 | It "Get visits data after a specified date" { 68 | Start-Sleep -Seconds 1 69 | $Date = Get-Date 70 | $Params = @{ 71 | ShortCode = 'PSShlink-Test' 72 | StartDate = $Date 73 | ShlinkServer = $env:ShlinkServer 74 | ShlinkApiKey = $env:ShlinkAPIKey | ConvertTo-SecureString 75 | ErrorAction = 'Stop' 76 | } 77 | $Object = Get-ShlinkVisits @Params 78 | $Object | Should -BeNullOrEmpty 79 | Invoke-WebRequest 'http://psshlink.codaamok/PSShlink-Test' -ErrorAction 'Stop' 80 | $Object = Get-ShlinkVisits @Params 81 | $Object.Count | Should -Be 1 82 | } 83 | } -------------------------------------------------------------------------------- /docs/Get-ShlinkVisitsNonOrphan.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-ShlinkVisitsNonOrphan 9 | 10 | ## SYNOPSIS 11 | Get the list of visits to all valid short URLs. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Get-ShlinkVisitsNonOrphan [[-StartDate] ] [[-EndDate] ] [-ExcludeBots] 17 | [[-ShlinkServer] ] [[-ShlinkApiKey] ] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | Get the list of visits to all valid short URLs. 22 | 23 | ## EXAMPLES 24 | 25 | ### EXAMPLE 1 26 | ``` 27 | Get-ShlinkVisitsNonOrphan 28 | ``` 29 | 30 | Get the list of visits to all valid short URLs. 31 | 32 | ### EXAMPLE 2 33 | ``` 34 | Get-ShlinkVisitsNonOrphan -StartDate (Get-Date "2020-11-01") -EndDate (Get-Date "2020-12-01") -ExcludeBots 35 | ``` 36 | 37 | Get the list of visits to all valid short URLs for the whole of November and excluding bots/crawlers. 38 | 39 | ## PARAMETERS 40 | 41 | ### -StartDate 42 | A datetime object to filter the visit data where the start date is equal or greater than this value. 43 | 44 | ```yaml 45 | Type: DateTime 46 | Parameter Sets: (All) 47 | Aliases: 48 | 49 | Required: False 50 | Position: 1 51 | Default value: None 52 | Accept pipeline input: False 53 | Accept wildcard characters: False 54 | ``` 55 | 56 | ### -EndDate 57 | A datetime object to filter the visit data where its end date is equal or less than this value. 58 | 59 | ```yaml 60 | Type: DateTime 61 | Parameter Sets: (All) 62 | Aliases: 63 | 64 | Required: False 65 | Position: 2 66 | Default value: None 67 | Accept pipeline input: False 68 | Accept wildcard characters: False 69 | ``` 70 | 71 | ### -ExcludeBots 72 | Exclude visits from bots or crawlers. 73 | 74 | ```yaml 75 | Type: SwitchParameter 76 | Parameter Sets: (All) 77 | Aliases: 78 | 79 | Required: False 80 | Position: Named 81 | Default value: False 82 | Accept pipeline input: False 83 | Accept wildcard characters: False 84 | ``` 85 | 86 | ### -ShlinkServer 87 | The URL of your Shlink server (including schema). 88 | For example "https://example.com". 89 | It is not required to use this parameter for every use of this function. 90 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 91 | 92 | ```yaml 93 | Type: String 94 | Parameter Sets: (All) 95 | Aliases: 96 | 97 | Required: False 98 | Position: 3 99 | Default value: None 100 | Accept pipeline input: False 101 | Accept wildcard characters: False 102 | ``` 103 | 104 | ### -ShlinkApiKey 105 | A SecureString object of your Shlink server's API key. 106 | It is not required to use this parameter for every use of this function. 107 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 108 | 109 | ```yaml 110 | Type: SecureString 111 | Parameter Sets: (All) 112 | Aliases: 113 | 114 | Required: False 115 | Position: 4 116 | Default value: None 117 | Accept pipeline input: False 118 | Accept wildcard characters: False 119 | ``` 120 | 121 | ### CommonParameters 122 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 123 | 124 | ## INPUTS 125 | 126 | ### This function does not accept pipeline input. 127 | ## OUTPUTS 128 | 129 | ### System.Management.Automation.PSObject 130 | ## NOTES 131 | 132 | ## RELATED LINKS 133 | -------------------------------------------------------------------------------- /docs/Get-ShlinkVisitsOrphan.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-ShlinkVisitsOrphan 9 | 10 | ## SYNOPSIS 11 | Get the list of visits to invalid short URLs, the base URL or any other 404. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Get-ShlinkVisitsOrphan [[-StartDate] ] [[-EndDate] ] [-ExcludeBots] 17 | [[-ShlinkServer] ] [[-ShlinkApiKey] ] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | Get the list of visits to invalid short URLs, the base URL or any other 404. 22 | 23 | ## EXAMPLES 24 | 25 | ### EXAMPLE 1 26 | ``` 27 | Get-ShlinkVisitsOrphan 28 | ``` 29 | 30 | Get the list of visits to invalid short URLs, the base URL or any other 404. 31 | 32 | ### EXAMPLE 2 33 | ``` 34 | Get-ShlinkVisitsOrphan -StartDate (Get-Date "2020-11-01") -EndDate (Get-Date "2020-12-01") -ExcludeBots 35 | ``` 36 | 37 | Get the list of visits to invalid short URLs, the base URL or any other 404, for the whole of November and excluding bots/crawlers. 38 | 39 | ## PARAMETERS 40 | 41 | ### -StartDate 42 | A datetime object to filter the visit data where the start date is equal or greater than this value. 43 | 44 | ```yaml 45 | Type: DateTime 46 | Parameter Sets: (All) 47 | Aliases: 48 | 49 | Required: False 50 | Position: 1 51 | Default value: None 52 | Accept pipeline input: False 53 | Accept wildcard characters: False 54 | ``` 55 | 56 | ### -EndDate 57 | A datetime object to filter the visit data where its end date is equal or less than this value. 58 | 59 | ```yaml 60 | Type: DateTime 61 | Parameter Sets: (All) 62 | Aliases: 63 | 64 | Required: False 65 | Position: 2 66 | Default value: None 67 | Accept pipeline input: False 68 | Accept wildcard characters: False 69 | ``` 70 | 71 | ### -ExcludeBots 72 | Exclude visits from bots or crawlers. 73 | 74 | ```yaml 75 | Type: SwitchParameter 76 | Parameter Sets: (All) 77 | Aliases: 78 | 79 | Required: False 80 | Position: Named 81 | Default value: False 82 | Accept pipeline input: False 83 | Accept wildcard characters: False 84 | ``` 85 | 86 | ### -ShlinkServer 87 | The URL of your Shlink server (including schema). 88 | For example "https://example.com". 89 | It is not required to use this parameter for every use of this function. 90 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 91 | 92 | ```yaml 93 | Type: String 94 | Parameter Sets: (All) 95 | Aliases: 96 | 97 | Required: False 98 | Position: 3 99 | Default value: None 100 | Accept pipeline input: False 101 | Accept wildcard characters: False 102 | ``` 103 | 104 | ### -ShlinkApiKey 105 | A SecureString object of your Shlink server's API key. 106 | It is not required to use this parameter for every use of this function. 107 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 108 | 109 | ```yaml 110 | Type: SecureString 111 | Parameter Sets: (All) 112 | Aliases: 113 | 114 | Required: False 115 | Position: 4 116 | Default value: None 117 | Accept pipeline input: False 118 | Accept wildcard characters: False 119 | ``` 120 | 121 | ### CommonParameters 122 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 123 | 124 | ## INPUTS 125 | 126 | ### This function does not accept pipeline input. 127 | ## OUTPUTS 128 | 129 | ### System.Management.Automation.PSObject 130 | ## NOTES 131 | 132 | ## RELATED LINKS 133 | -------------------------------------------------------------------------------- /src/Public/Set-ShlinkDomainRedirects.ps1: -------------------------------------------------------------------------------- 1 | function Set-ShlinkDomainRedirects { 2 | <# 3 | .SYNOPSIS 4 | Sets the URLs that you want a visitor to get redirected to for "not found" URLs for a specific domain. 5 | .DESCRIPTION 6 | Sets the URLs that you want a visitor to get redirected to for "not found" URLs for a specific domain. 7 | .PARAMETER Domain 8 | The domain (excluding schema) in which you would like to modify the redirects of. For example, "example.com" is an acceptable value. 9 | .PARAMETER BaseUrlRedirect 10 | Modify the 'BaseUrlRedirect' redirect setting of the domain. 11 | .PARAMETER Regular404Redirect 12 | Modify the 'Regular404Redirect' redirect setting of the domain. 13 | .PARAMETER InvalidShortUrlRedirect 14 | Modify the 'InvalidShortUrlRedirect' redirect setting of the domain. 15 | .PARAMETER ShlinkServer 16 | The URL of your Shlink server (including schema). For example "https://example.com". 17 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 18 | .PARAMETER ShlinkApiKey 19 | A SecureString object of your Shlink server's API key. 20 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 21 | .EXAMPLE 22 | PS C:\> Set-ShlinkDomainRedirects -Domain "example.com" -BaseUrlRedirect "https://someotheraddress.com" 23 | 24 | Modifies the redirect setting 'BaseUrlRedirect' of example.com to redirect to "https://someotheraddress.com". 25 | .INPUTS 26 | This function does not accept pipeline input. 27 | .OUTPUTS 28 | System.Management.Automation.PSObject 29 | #> 30 | [CmdletBinding(DefaultParameterSetName="BaseUrlRedirect")] 31 | param ( 32 | [Parameter(Mandatory)] 33 | [String]$Domain, 34 | 35 | [Parameter(ParameterSetName="BaseUrlRedirect", Mandatory)] 36 | [Parameter(ParameterSetName="Regular404Redirect")] 37 | [Parameter(ParameterSetName="InvalidShortUrlRedirect")] 38 | [String]$BaseUrlRedirect, 39 | 40 | [Parameter(ParameterSetName="BaseUrlRedirect")] 41 | [Parameter(ParameterSetName="Regular404Redirect", Mandatory)] 42 | [Parameter(ParameterSetName="InvalidShortUrlRedirect")] 43 | [String]$Regular404Redirect, 44 | 45 | [Parameter(ParameterSetName="BaseUrlRedirect")] 46 | [Parameter(ParameterSetName="Regular404Redirect")] 47 | [Parameter(ParameterSetName="InvalidShortUrlRedirect", Mandatory)] 48 | [String]$InvalidShortUrlRedirect, 49 | 50 | [Parameter()] 51 | [String]$ShlinkServer, 52 | 53 | [Parameter()] 54 | [SecureString]$ShlinkApiKey 55 | ) 56 | 57 | try { 58 | GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey 59 | } 60 | catch { 61 | Write-Error -ErrorRecord $_ -ErrorAction "Stop" 62 | } 63 | 64 | $Body = @{ 65 | domain = $Domain 66 | } 67 | 68 | switch ($PSBoundParameters.Keys) { 69 | "BaseUrlRedirect" { 70 | $Body["baseUrlRedirect"] = $BaseUrlRedirect 71 | } 72 | "Regular404Redirect" { 73 | $Body["regular404Redirect"] = $Regular404Redirect 74 | } 75 | "InvalidShortUrlRedirect" { 76 | $Body["invalidShortUrlRedirect"] = $InvalidShortUrlRedirect 77 | } 78 | } 79 | 80 | $Params = @{ 81 | Endpoint = "domains" 82 | Path = "redirects" 83 | Method = "PATCH" 84 | Body = $Body 85 | ErrorAction = "Stop" 86 | } 87 | 88 | try { 89 | InvokeShlinkRestMethod @Params 90 | } 91 | catch { 92 | Write-Error -ErrorRecord $_ 93 | } 94 | } -------------------------------------------------------------------------------- /docs/Remove-ShlinkTag.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Remove-ShlinkTag 9 | 10 | ## SYNOPSIS 11 | Remove a tag from an existing Shlink server. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Remove-ShlinkTag [-Tag] [[-ShlinkServer] ] [[-ShlinkApiKey] ] [-WhatIf] 17 | [-Confirm] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | Remove a tag from an existing Shlink server. 22 | 23 | ## EXAMPLES 24 | 25 | ### EXAMPLE 1 26 | ``` 27 | Remove-ShlinkTag -Tags "oldwebsite" -WhatIf 28 | ``` 29 | 30 | Reports what would happen if the command was invoked, because the -WhatIf parameter is present. 31 | 32 | ### EXAMPLE 2 33 | ``` 34 | Remove-ShlinkTag -Tags "oldwebsite", "newwebsite" 35 | ``` 36 | 37 | Removes the following tags from the Shlink server: "oldwebsite", "newwebsite" 38 | 39 | ### EXAMPLE 3 40 | ``` 41 | "tag1","tag2" | Remove-ShlinkTag 42 | ``` 43 | 44 | Removes "tag1" and "tag2" from your Shlink instance. 45 | 46 | ### EXAMPLE 4 47 | ``` 48 | Get-ShlinkUrl -ShortCode "profile" | Remove-ShlinkTag 49 | ``` 50 | 51 | Removes all the tags which are associated with the short code "profile" from the Shlink instance. 52 | 53 | ## PARAMETERS 54 | 55 | ### -Tag 56 | Name(s) of the tag(s) you want to remove. 57 | 58 | ```yaml 59 | Type: String[] 60 | Parameter Sets: (All) 61 | Aliases: 62 | 63 | Required: True 64 | Position: 1 65 | Default value: None 66 | Accept pipeline input: True (ByPropertyName, ByValue) 67 | Accept wildcard characters: False 68 | ``` 69 | 70 | ### -ShlinkServer 71 | The URL of your Shlink server (including schema). 72 | For example "https://example.com". 73 | It is not required to use this parameter for every use of this function. 74 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 75 | 76 | ```yaml 77 | Type: String 78 | Parameter Sets: (All) 79 | Aliases: 80 | 81 | Required: False 82 | Position: 2 83 | Default value: None 84 | Accept pipeline input: False 85 | Accept wildcard characters: False 86 | ``` 87 | 88 | ### -ShlinkApiKey 89 | A SecureString object of your Shlink server's API key. 90 | It is not required to use this parameter for every use of this function. 91 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 92 | 93 | ```yaml 94 | Type: SecureString 95 | Parameter Sets: (All) 96 | Aliases: 97 | 98 | Required: False 99 | Position: 3 100 | Default value: None 101 | Accept pipeline input: False 102 | Accept wildcard characters: False 103 | ``` 104 | 105 | ### -WhatIf 106 | Shows what would happen if the cmdlet runs. 107 | The cmdlet is not run. 108 | 109 | ```yaml 110 | Type: SwitchParameter 111 | Parameter Sets: (All) 112 | Aliases: wi 113 | 114 | Required: False 115 | Position: Named 116 | Default value: None 117 | Accept pipeline input: False 118 | Accept wildcard characters: False 119 | ``` 120 | 121 | ### -Confirm 122 | Prompts you for confirmation before running the cmdlet. 123 | 124 | ```yaml 125 | Type: SwitchParameter 126 | Parameter Sets: (All) 127 | Aliases: cf 128 | 129 | Required: False 130 | Position: Named 131 | Default value: None 132 | Accept pipeline input: False 133 | Accept wildcard characters: False 134 | ``` 135 | 136 | ### CommonParameters 137 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 138 | 139 | ## INPUTS 140 | 141 | ### System.String[] 142 | ### Used for the -Tags parameter. 143 | ## OUTPUTS 144 | 145 | ### System.Management.Automation.PSObject 146 | ## NOTES 147 | 148 | ## RELATED LINKS 149 | -------------------------------------------------------------------------------- /src/Public/Remove-ShlinkUrl.ps1: -------------------------------------------------------------------------------- 1 | function Remove-ShlinkUrl { 2 | <# 3 | .SYNOPSIS 4 | Removes a short code from the Shlink server 5 | .DESCRIPTION 6 | Removes a short code from the Shlink server 7 | .PARAMETER ShortCode 8 | The name of the short code you wish to remove from the Shlink server. 9 | .PARAMETER Domain 10 | The domain associated with the short code you wish to remove from the Shlink server. 11 | This is useful if your Shlink instance is responding/creating short URLs for multiple domains. 12 | .PARAMETER ShlinkServer 13 | The URL of your Shlink server (including schema). For example "https://example.com". 14 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 15 | .PARAMETER ShlinkApiKey 16 | A SecureString object of your Shlink server's API key. 17 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 18 | .EXAMPLE 19 | PS C:\> Remove-ShlinkUrl -ShortCode "profile" -WhatIf 20 | 21 | Reports what would happen if the command was invoked, because the -WhatIf parameter is present. 22 | .EXAMPLE 23 | PS C:\> Remove-ShlinkUrl -ShortCode "profile" -Domain "example.com" 24 | 25 | Removes the short code "profile" associated with the domain "example.com" from the Shlink server. 26 | .EXAMPLE 27 | PS C:\> Get-ShlinkUrl -SearchTerm "oldwebsite" | Remove-ShlinkUrl 28 | 29 | Removes all existing short codes which match the search term "oldwebsite". 30 | .EXAMPLE 31 | PS C:\> "profile", "house" | Remove-ShlinkUrl 32 | 33 | Removes the short codes "profile" and "house" from the Shlink instance. 34 | .INPUTS 35 | System.String[] 36 | 37 | Used for the -ShortCode parameter. 38 | .OUTPUTS 39 | System.Management.Automation.PSObject 40 | #> 41 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "High")] 42 | param ( 43 | [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] 44 | [String[]]$ShortCode, 45 | 46 | [Parameter()] 47 | [String]$Domain, 48 | 49 | [Parameter()] 50 | [String]$ShlinkServer, 51 | 52 | [Parameter()] 53 | [SecureString]$ShlinkApiKey 54 | ) 55 | begin { 56 | try { 57 | GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey 58 | } 59 | catch { 60 | Write-Error -ErrorRecord $_ -ErrorAction "Stop" 61 | } 62 | } 63 | process { 64 | foreach ($Code in $ShortCode) { 65 | $Params = @{ 66 | Endpoint = "short-urls" 67 | Path = $Code 68 | Method = "DELETE" 69 | ErrorAction = "Stop" 70 | } 71 | 72 | $WouldMessage = "Would delete short code '{0}' from Shlink server '{1}'" -f $Code, $Script:ShlinkServer 73 | $RemovingMessage = "Removing short code '{0}' from Shlink server '{1}'" -f $Code, $Script:ShlinkServer 74 | 75 | if ($PSBoundParameters.ContainsKey("Domain")) { 76 | $QueryString = [System.Web.HttpUtility]::ParseQueryString('') 77 | $QueryString.Add("domain", $Domain) 78 | $Params["Query"] = $QueryString 79 | 80 | $WouldMessage = $WouldMessage -replace "from Shlink server", ("for domain '{0}'" -f $Domain) 81 | $RemovingMessage = $RemovingMessage -replace "from Shlink server", ("for domain '{0}'" -f $Domain) 82 | } 83 | 84 | if ($PSCmdlet.ShouldProcess( 85 | $WouldMessage, 86 | "Are you sure you want to continue?", 87 | $RemovingMessage)) { 88 | try { 89 | $null = InvokeShlinkRestMethod @Params 90 | } 91 | catch { 92 | Write-Error -ErrorRecord $_ 93 | } 94 | } 95 | } 96 | } 97 | end { 98 | } 99 | } -------------------------------------------------------------------------------- /src/Public/Remove-ShlinkTag.ps1: -------------------------------------------------------------------------------- 1 | function Remove-ShlinkTag { 2 | <# 3 | .SYNOPSIS 4 | Remove a tag from an existing Shlink server. 5 | .DESCRIPTION 6 | Remove a tag from an existing Shlink server. 7 | .PARAMETER Tag 8 | Name(s) of the tag(s) you want to remove. 9 | .PARAMETER ShlinkServer 10 | The URL of your Shlink server (including schema). For example "https://example.com". 11 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 12 | .PARAMETER ShlinkApiKey 13 | A SecureString object of your Shlink server's API key. 14 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 15 | .EXAMPLE 16 | PS C:\> Remove-ShlinkTag -Tags "oldwebsite" -WhatIf 17 | 18 | Reports what would happen if the command was invoked, because the -WhatIf parameter is present. 19 | .EXAMPLE 20 | PS C:\> Remove-ShlinkTag -Tags "oldwebsite", "newwebsite" 21 | 22 | Removes the following tags from the Shlink server: "oldwebsite", "newwebsite" 23 | .EXAMPLE 24 | PS C:\> "tag1","tag2" | Remove-ShlinkTag 25 | 26 | Removes "tag1" and "tag2" from your Shlink instance. 27 | .EXAMPLE 28 | PS C:\> Get-ShlinkUrl -ShortCode "profile" | Remove-ShlinkTag 29 | 30 | Removes all the tags which are associated with the short code "profile" from the Shlink instance. 31 | .INPUTS 32 | System.String[] 33 | 34 | Used for the -Tags parameter. 35 | .OUTPUTS 36 | System.Management.Automation.PSObject 37 | #> 38 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "High")] 39 | param ( 40 | [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] 41 | [String[]]$Tag, 42 | 43 | [Parameter()] 44 | [String]$ShlinkServer, 45 | 46 | [Parameter()] 47 | [SecureString]$ShlinkApiKey 48 | ) 49 | begin { 50 | try { 51 | GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey 52 | } 53 | catch { 54 | Write-Error -ErrorRecord $_ -ErrorAction "Stop" 55 | } 56 | 57 | # Gather all tags and check if any of the user's desired tag(s) to delete 58 | # are currently an existing tag within the process / for loop later. 59 | # This is because the REST API does not produce any kind of feedback if the 60 | # user attempts to delete a tag which does not exist. 61 | $AllTags = Get-ShlinkTags 62 | } 63 | process { 64 | $QueryString = [System.Web.HttpUtility]::ParseQueryString('') 65 | 66 | foreach ($_Tag in $Tag) { 67 | if ($AllTags.tag -notcontains $_Tag) { 68 | $WriteErrorSplat = @{ 69 | Message = "Tag '{0}' does not exist on Shlink server '{1}'" -f $_Tag, $Script:ShlinkServer 70 | Category = "ObjectNotFound" 71 | TargetObject = $_Tag 72 | } 73 | Write-Error @WriteErrorSplat 74 | continue 75 | } 76 | else { 77 | $QueryString.Add("tags[]", $_Tag) 78 | } 79 | 80 | $Params = @{ 81 | Endpoint = "tags" 82 | Method = "DELETE" 83 | Query = $QueryString 84 | ErrorAction = "Stop" 85 | } 86 | 87 | if ($PSCmdlet.ShouldProcess( 88 | ("Would delete tag '{0}' from Shlink server '{1}'" -f $_Tag, $Script:ShlinkServer), 89 | "Are you sure you want to continue?", 90 | ("Removing tag '{0}' from Shlink server '{1}'" -f $_Tag, $Script:ShlinkServer))) { 91 | try { 92 | InvokeShlinkRestMethod @Params 93 | } 94 | catch { 95 | Write-Error -ErrorRecord $_ 96 | } 97 | } 98 | } 99 | } 100 | end { 101 | } 102 | } -------------------------------------------------------------------------------- /src/Private/GetShlinkConnection.ps1: -------------------------------------------------------------------------------- 1 | function GetShlinkConnection { 2 | param ( 3 | [Parameter()] 4 | [String]$Server, 5 | 6 | [Parameter()] 7 | [SecureString]$ApiKey, 8 | 9 | [Parameter()] 10 | [Switch]$ServerOnly 11 | ) 12 | 13 | function SetShlinkServer { 14 | param ( 15 | [Parameter()] 16 | [String]$Server 17 | ) 18 | if ($Server -notmatch '^http[s]?:\/\/') { 19 | Write-Warning ("Rewriting Shlink server address to be 'https://{0}' instead of using http://. To use HTTP, instead of HTTPS, specify 'http://' in your -ShlinkServer." -f $Server) -Verbose 20 | $Script:ShlinkServer = "https://{0}" -f $Server 21 | } 22 | else { 23 | $Script:ShlinkServer = $Server 24 | } 25 | } 26 | 27 | $Script:MinSupportedShlinkVersion = [Version]"3.5.0" 28 | 29 | if (-not ("System.Web.HttpUtility" -as [Type])) { 30 | Add-Type -AssemblyName "System.Web" -ErrorAction "Stop" 31 | } 32 | 33 | if ([String]::IsNullOrWhiteSpace($Server) -And -not $Script:ShlinkServer) { 34 | # User has not yet used use a -ShlinkServer paramater from any of the functions, therefore prompt 35 | SetShlinkServer -Server (Read-Host -Prompt "Enter your Shlink server URL (e.g. https://example.com)") 36 | } 37 | elseif (-not [String]::IsNullOrWhiteSpace($Server) -And $Script:ShlinkServer -ne $Server) { 38 | # User has previously used a -ShlinkServer parameter and is using it right now, and its value is different to what was used last in any of the functions 39 | # In other words, it has changed and they wish to use a different server, and that new server will be used for subsequent calls unless they specify a different server again. 40 | SetShlinkServer -Server $Server 41 | # Set this to false so we can go through the motions again of checking the new Shlink server's version number 42 | $Script:GetShlinkConnectionHasRun = $false 43 | # We no longer know if the new server's Shlink version is supported for PSShlink 44 | Clear-Variable -Name "ShlinkVersionIsSupported" -Scope "Script" -ErrorAction "SilentlyContinue" 45 | } 46 | 47 | if ([String]::IsNullOrWhitespace($ApiKey) -And -not $Script:ShlinkApiKey -And -not $ServerOnly) { 48 | # User has not yet used use a -ShlinkApiKey paramater from any of the functions, therefore prompt 49 | $Script:ShlinkApiKey = Read-Host -Prompt "Enter your Shlink server API key" -AsSecureString 50 | } 51 | elseif (-not [String]::IsNullOrWhiteSpace($ApiKey) -And $Script:ShlinkApiKey -ne $ApiKey) { 52 | # User has previously used a -ShlinkApiKey parameter and is using it right now, and its value is different to what was used last in any of the functions 53 | # In other words, it has changed - they wish to use a different API key, and that new API key will be used for subsequent calls unless they specify a different API key again. 54 | $Script:ShlinkApiKey = $ApiKey 55 | } 56 | 57 | # Query the Shlink server for version, only on the first run of GetShlinkConnection, otherwise it 58 | # will enter an infinite loop of recursion and hit the PowerShell recursion limit. I want a user 59 | # experience of being warned each time they use a function on an unsupported Shlink server version. 60 | if (-not $Script:GetShlinkConnectionHasRun) { 61 | $Script:GetShlinkConnectionHasRun = $true 62 | $Script:ShlinkVersion = Get-ShlinkServer -ShlinkServer $Script:ShlinkServer -ErrorAction "SilentlyContinue" | Select-Object -ExpandProperty Version 63 | 64 | if (-not $Script:ShlinkVersion) { 65 | $Script:GetShlinkConnectionHasRun = $false 66 | Write-Error -Message ("Could not determine the version of Shlink on '{0}'" -f $Script:ShlinkServer) -Category "InvalidData" -TargetObject $Script:ShlinkServer -ErrorAction "Stop" 67 | } 68 | elseif ([Version]$Script:ShlinkVersion -lt [Version]$Script:MinSupportedShlinkVersion) { 69 | $Script:ShlinkVersionIsSupported = $false 70 | } 71 | else { 72 | $Script:ShlinkVersionIsSupported = $true 73 | } 74 | } 75 | 76 | if ($Script:ShlinkVersionIsSupported -eq $false -And $Script:ShlinkVersion) { 77 | Write-Warning -Message ("PSShlink supports Shlink {0} or newer, your Shlink server is {1}. Some functions may not work as intended. Consider upgrading your Shlink instance." -f $Script:MinSupportedShlinkVersion, $Script:ShlinkVersion) 78 | } 79 | } -------------------------------------------------------------------------------- /docs/Remove-ShlinkUrl.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Remove-ShlinkUrl 9 | 10 | ## SYNOPSIS 11 | Removes a short code from the Shlink server 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Remove-ShlinkUrl [-ShortCode] [[-Domain] ] [[-ShlinkServer] ] 17 | [[-ShlinkApiKey] ] [-WhatIf] [-Confirm] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | Removes a short code from the Shlink server 22 | 23 | ## EXAMPLES 24 | 25 | ### EXAMPLE 1 26 | ``` 27 | Remove-ShlinkUrl -ShortCode "profile" -WhatIf 28 | ``` 29 | 30 | Reports what would happen if the command was invoked, because the -WhatIf parameter is present. 31 | 32 | ### EXAMPLE 2 33 | ``` 34 | Remove-ShlinkUrl -ShortCode "profile" -Domain "example.com" 35 | ``` 36 | 37 | Removes the short code "profile" associated with the domain "example.com" from the Shlink server. 38 | 39 | ### EXAMPLE 3 40 | ``` 41 | Get-ShlinkUrl -SearchTerm "oldwebsite" | Remove-ShlinkUrl 42 | ``` 43 | 44 | Removes all existing short codes which match the search term "oldwebsite". 45 | 46 | ### EXAMPLE 4 47 | ``` 48 | "profile", "house" | Remove-ShlinkUrl 49 | ``` 50 | 51 | Removes the short codes "profile" and "house" from the Shlink instance. 52 | 53 | ## PARAMETERS 54 | 55 | ### -ShortCode 56 | The name of the short code you wish to remove from the Shlink server. 57 | 58 | ```yaml 59 | Type: String[] 60 | Parameter Sets: (All) 61 | Aliases: 62 | 63 | Required: True 64 | Position: 1 65 | Default value: None 66 | Accept pipeline input: True (ByPropertyName, ByValue) 67 | Accept wildcard characters: False 68 | ``` 69 | 70 | ### -Domain 71 | The domain associated with the short code you wish to remove from the Shlink server. 72 | This is useful if your Shlink instance is responding/creating short URLs for multiple domains. 73 | 74 | ```yaml 75 | Type: String 76 | Parameter Sets: (All) 77 | Aliases: 78 | 79 | Required: False 80 | Position: 2 81 | Default value: None 82 | Accept pipeline input: False 83 | Accept wildcard characters: False 84 | ``` 85 | 86 | ### -ShlinkServer 87 | The URL of your Shlink server (including schema). 88 | For example "https://example.com". 89 | It is not required to use this parameter for every use of this function. 90 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 91 | 92 | ```yaml 93 | Type: String 94 | Parameter Sets: (All) 95 | Aliases: 96 | 97 | Required: False 98 | Position: 3 99 | Default value: None 100 | Accept pipeline input: False 101 | Accept wildcard characters: False 102 | ``` 103 | 104 | ### -ShlinkApiKey 105 | A SecureString object of your Shlink server's API key. 106 | It is not required to use this parameter for every use of this function. 107 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 108 | 109 | ```yaml 110 | Type: SecureString 111 | Parameter Sets: (All) 112 | Aliases: 113 | 114 | Required: False 115 | Position: 4 116 | Default value: None 117 | Accept pipeline input: False 118 | Accept wildcard characters: False 119 | ``` 120 | 121 | ### -WhatIf 122 | Shows what would happen if the cmdlet runs. 123 | The cmdlet is not run. 124 | 125 | ```yaml 126 | Type: SwitchParameter 127 | Parameter Sets: (All) 128 | Aliases: wi 129 | 130 | Required: False 131 | Position: Named 132 | Default value: None 133 | Accept pipeline input: False 134 | Accept wildcard characters: False 135 | ``` 136 | 137 | ### -Confirm 138 | Prompts you for confirmation before running the cmdlet. 139 | 140 | ```yaml 141 | Type: SwitchParameter 142 | Parameter Sets: (All) 143 | Aliases: cf 144 | 145 | Required: False 146 | Position: Named 147 | Default value: None 148 | Accept pipeline input: False 149 | Accept wildcard characters: False 150 | ``` 151 | 152 | ### CommonParameters 153 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 154 | 155 | ## INPUTS 156 | 157 | ### System.String[] 158 | ### Used for the -ShortCode parameter. 159 | ## OUTPUTS 160 | 161 | ### System.Management.Automation.PSObject 162 | ## NOTES 163 | 164 | ## RELATED LINKS 165 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Build", 8 | "type": "process", 9 | "command": "pwsh", 10 | "args": ["-noprofile","-command","Invoke-Build","-File","./invoke.build.ps1","-Author","'codaamok'","-ModuleName","'PSShlink'"], 11 | "group": "build", 12 | "presentation": { 13 | "echo": true, 14 | "reveal": "always", 15 | "focus": false, 16 | "panel": "shared", 17 | "showReuseMessage": true, 18 | "clear": false 19 | }, 20 | "problemMatcher": [] 21 | }, 22 | { 23 | "label": "Build (with docs)", 24 | "type": "process", 25 | "command": "pwsh", 26 | "args": ["-noprofile","-command","Invoke-Build","-File","./invoke.build.ps1","-Author","'codaamok'","-ModuleName","'PSShlink'","-UpdateDocs","$true"], 27 | "group": { 28 | "kind": "build", 29 | "isDefault": true 30 | }, 31 | "presentation": { 32 | "echo": true, 33 | "reveal": "always", 34 | "focus": false, 35 | "panel": "shared", 36 | "showReuseMessage": true, 37 | "clear": false 38 | }, 39 | "problemMatcher": [] 40 | }, 41 | { 42 | "label": "Build Docker container (Windows)", 43 | "type": "process", 44 | "command": "cmd.exe", 45 | "args": ["/C", "docker", "run", "--name", "my_shlink_psshlink", "-p", "80:8080", "-e", "DEFAULT_DOMAIN=${input:ShlinkServer}", "-e", "IS_HTTPS_ENABLED=false", "-e", "INITIAL_API_KEY=${input:ShlinkAPIKey}","shlinkio/shlink:stable"], 46 | "group": { 47 | "kind": "build", 48 | "isDefault": true 49 | }, 50 | "presentation": { 51 | "echo": true, 52 | "reveal": "always", 53 | "focus": false, 54 | "panel": "shared", 55 | "showReuseMessage": true, 56 | "clear": false 57 | }, 58 | "problemMatcher": [] 59 | }, 60 | { 61 | "label": "Build Docker container (UNIX)", 62 | "type": "process", 63 | "command": "docker", 64 | "args": ["run", "--name", "my_shlink_psshlink", "-p", "80:8080", "-e", "DEFAULT_DOMAIN=${input:ShlinkServer}", "-e", "IS_HTTPS_ENABLED=false", "-e", "INITIAL_API_KEY=${input:ShlinkAPIKey}","shlinkio/shlink:stable"], 65 | "group": { 66 | "kind": "build", 67 | "isDefault": true 68 | }, 69 | "presentation": { 70 | "echo": true, 71 | "reveal": "always", 72 | "focus": false, 73 | "panel": "shared", 74 | "showReuseMessage": true, 75 | "clear": false 76 | }, 77 | "problemMatcher": [] 78 | }, 79 | { 80 | "label": "Tests", 81 | "type": "process", 82 | "command": "pwsh", 83 | "args": ["-noprofile", "-command", "$env:ShlinkServer = 'http://${input:ShlinkServer}'; $env:ShlinkAPIKey = '${input:ShlinkAPIKey}' | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString; ./tests/invoke.tests.ps1"], 84 | "group": { 85 | "kind": "test", 86 | "isDefault": true 87 | }, 88 | "presentation": { 89 | "echo": true, 90 | "reveal": "always", 91 | "focus": false, 92 | "panel": "shared", 93 | "showReuseMessage": true, 94 | "clear": false 95 | }, 96 | "problemMatcher": [] 97 | }, 98 | ], 99 | "inputs": [ 100 | { 101 | "description": "Please enter Shlink server name", 102 | "id": "ShlinkServer", 103 | "type": "promptString", 104 | "default": "psshlink.codaamok" 105 | }, 106 | { 107 | "description": "Please enter Shlink API key", 108 | "id": "ShlinkAPIKey", 109 | "type": "promptString", 110 | "default": "18c65bc9-e4fb-449d-b3e0-c6427cbac735", 111 | "password": true, 112 | }, 113 | { 114 | "type": "pickString", 115 | "id": "CodeType", 116 | "description": "Would you like use built, or development code?", 117 | "options": [ 118 | "./src/PSShlink.psd1", 119 | "./build/PSShlink/PSShlink.psd1" 120 | ], 121 | "default": "./build/PSShlink/PSShlink.psd1" 122 | }, 123 | ] 124 | } -------------------------------------------------------------------------------- /src/PSShlink.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'PSShlink' 3 | # 4 | # Generated by: Adam Cook (@codaamok) 5 | # 6 | # Generated on: 03/06/2023 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'PSShlink.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '0.12.2' 16 | 17 | # Supported PSEditions 18 | CompatiblePSEditions = 'Core', 'Desktop' 19 | 20 | # ID used to uniquely identify this module 21 | GUID = 'c9acdd6c-96d0-4a8a-9cce-df8fdeabc25d' 22 | 23 | # Author of this module 24 | Author = 'Adam Cook (@codaamok)' 25 | 26 | # Company or vendor of this module 27 | CompanyName = '' 28 | 29 | # Copyright statement for this module 30 | Copyright = '(c) Adam Cook (@codaamok). All rights reserved.' 31 | 32 | # Description of the functionality provided by this module 33 | Description = 'An unofficial PowerShell module for Shlink (https://shlink.io), an open-source self-hosted and PHP-based URL shortener application' 34 | 35 | # Minimum version of the PowerShell engine required by this module 36 | PowerShellVersion = '5.1' 37 | 38 | # Name of the PowerShell host required by this module 39 | # PowerShellHostName = '' 40 | 41 | # Minimum version of the PowerShell host required by this module 42 | # PowerShellHostVersion = '' 43 | 44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 45 | # DotNetFrameworkVersion = '' 46 | 47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 48 | # ClrVersion = '' 49 | 50 | # Processor architecture (None, X86, Amd64) required by this module 51 | # ProcessorArchitecture = '' 52 | 53 | # Modules that must be imported into the global environment prior to importing this module 54 | # RequiredModules = @() 55 | 56 | # Assemblies that must be loaded prior to importing this module 57 | # RequiredAssemblies = @() 58 | 59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 60 | # ScriptsToProcess = @() 61 | 62 | # Type files (.ps1xml) to be loaded when importing this module 63 | # TypesToProcess = @() 64 | 65 | # Format files (.ps1xml) to be loaded when importing this module 66 | FormatsToProcess = 'PSShlink.Format.ps1xml' 67 | 68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 69 | # NestedModules = @() 70 | 71 | # 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. 72 | FunctionsToExport = '*' 73 | 74 | # 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. 75 | CmdletsToExport = @() 76 | 77 | # Variables to export from this module 78 | VariablesToExport = '*' 79 | 80 | # 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. 81 | AliasesToExport = @() 82 | 83 | # DSC resources to export from this module 84 | # DscResourcesToExport = @() 85 | 86 | # List of all modules packaged with this module 87 | # ModuleList = @() 88 | 89 | # List of all files packaged with this module 90 | # FileList = @() 91 | 92 | # 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. 93 | PrivateData = @{ 94 | 95 | PSData = @{ 96 | 97 | # Tags applied to this module. These help with module discovery in online galleries. 98 | Tags = 'Shlink','url-shortener' 99 | 100 | # A URL to the license for this module. 101 | LicenseUri = 'https://github.com/codaamok/PSShlink/blob/main/LICENSE' 102 | 103 | # A URL to the main website for this project. 104 | ProjectUri = 'https://github.com/codaamok/PSShlink' 105 | 106 | # A URL to an icon representing this module. 107 | # IconUri = '' 108 | 109 | # ReleaseNotes of this module 110 | ReleaseNotes = '# Fixed 111 | - Show comment based help correctly for Invoke-ShlinkRestMethod, mostly for PlatyPS and in-repository help markdown files' 112 | 113 | # Prerelease string of this module 114 | # Prerelease = '' 115 | 116 | # Flag to indicate whether the module requires explicit user acceptance for install/update/save 117 | # RequireLicenseAcceptance = $false 118 | 119 | # External dependent modules of this module 120 | # ExternalModuleDependencies = @() 121 | 122 | } # End of PSData hashtable 123 | 124 | } # End of PrivateData hashtable 125 | 126 | # HelpInfo URI of this module 127 | # HelpInfoURI = '' 128 | 129 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 130 | # DefaultCommandPrefix = '' 131 | 132 | } 133 | 134 | -------------------------------------------------------------------------------- /src/Public/Invoke-ShlinkRestMethod.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-ShlinkRestMethod { 2 | <# 3 | .SYNOPSIS 4 | Query a Shlink server's REST API 5 | .DESCRIPTION 6 | This function provides flexibility to query a Shlink's server how you want to. 7 | 8 | Specify all the parameters, endpoint, and path details you need. 9 | 10 | All data from all pages are returned. 11 | 12 | See Shlink's REST API documentation: https://shlink.io/documentation/api-docs/ and https://api-spec.shlink.io/ 13 | .PARAMETER Endpoint 14 | The endpoint to use in the request. This is before the -Path. See the examples for example usage. 15 | .PARAMETER Path 16 | The path to use in the request. This is after the -Endpoint. See the examples for example usage. 17 | .PARAMETER Query 18 | The query to use in the request. Must be an instance of System.Web.HttpUtility. See the examples for example usage. 19 | 20 | Note (it's not obvious), you can add more query params to an instance of HttpUtility like you can any dictionary by using the .Add() method on the object. 21 | .PARAMETER ApiVersion 22 | The API version of Shlink to use in the request. 23 | .PARAMETER Method 24 | The HTTP method to use in the request. 25 | .PARAMETER PropertyTree 26 | Data returned by Shlink's rest API is usually embedded within one or two properties. 27 | 28 | Here you can specify the embedded properties as a string array in the order you need to select them to access the data. 29 | 30 | For example, the "short-urls" endpoint includes the data within the "shortUrls.data" properties. Therefore, for this parameter you specify a string array of @("shortUrls", "data"). 31 | 32 | In other words, using this function for the short-urls endpoint results in the below object if there are two pages worth of data returned: 33 | 34 | Invoke-ShlinkRestMethod -Endpoint 'short-urls' 35 | 36 | shortUrls 37 | --------- 38 | @{data=System.Object[]; pagination=} 39 | @{data=System.Object[]; pagination=} 40 | .PARAMETER ShlinkServer 41 | The URL of your Shlink server (including schema). For example "https://example.com". 42 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 43 | .PARAMETER ShlinkApiKey 44 | A SecureString object of your Shlink server's API key. 45 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 46 | .EXAMPLE 47 | Invoke-ShlinkRestMethod -Endpoint "short-urls" -PropertyTree "shortUrls", "Data" -Query [System.Web.HttpUtility]::ParseQueryString("searchTerm", "abc") 48 | 49 | Gets all short codes from Shlink matching the search term "abc". 50 | 51 | Note (it's not obvious), you can add more query params to an instance of HttpUtility like you can any dictionary by using the .Add() method on the object. 52 | .EXAMPLE 53 | Invoke-ShlinkRestMethod -Endpoint "short-urls" -Path "abc" -METHOD "DELETE" 54 | 55 | Deletes the shortcode "abc" from Shlink. 56 | .EXAMPLE 57 | Invoke-ShlinkRestMethod -Endpoint "tags" -Path "stats" 58 | 59 | Gets all tags with statistics. 60 | .INPUTS 61 | This function does not accept pipeline input. 62 | .OUTPUTS 63 | System.Management.Automation.PSObject 64 | #> 65 | [CmdletBinding()] 66 | param ( 67 | [Parameter(Mandatory)] 68 | [String]$Endpoint, 69 | 70 | [Parameter()] 71 | [String]$Path, 72 | 73 | # Default value set where no Query parameter is passed because we still need the object for pagination later 74 | [Parameter()] 75 | [System.Web.HttpUtility]$Query, 76 | 77 | [Parameter()] 78 | [ValidateSet(1, 2, 3)] 79 | [Int]$ApiVersion = 3, 80 | 81 | [Parameter()] 82 | [Microsoft.PowerShell.Commands.WebRequestMethod]$Method = 'GET', 83 | 84 | [Parameter()] 85 | [String[]]$PropertyTree, 86 | 87 | [Parameter()] 88 | [String]$ShlinkServer, 89 | 90 | [Parameter()] 91 | [SecureString]$ShlinkApiKey 92 | ) 93 | 94 | # TODO this function needs tests 95 | 96 | try { 97 | GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey 98 | } 99 | catch { 100 | Write-Error -ErrorRecord $_ -ErrorAction "Stop" 101 | } 102 | 103 | $Params = @{ 104 | Endpoint = $Endpoint 105 | Method = $Method 106 | } 107 | 108 | switch ($PSBoundParameters.Keys) { 109 | "Path" { 110 | $Params["Path"] = $Path 111 | } 112 | "Query" { 113 | $Params["Query"] = $Query 114 | } 115 | "ApiVersion" { 116 | $Params["ApiVersion"] = $ApiVersion 117 | } 118 | "PropertyTree" { 119 | $Params["PropertyTree"] = $PropertyTree 120 | } 121 | } 122 | 123 | try { 124 | InvokeShlinkRestMethod @Params 125 | } 126 | catch { 127 | Write-Error -ErrorRecord $_ 128 | } 129 | } -------------------------------------------------------------------------------- /docs/Set-ShlinkDomainRedirects.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Set-ShlinkDomainRedirects 9 | 10 | ## SYNOPSIS 11 | Sets the URLs that you want a visitor to get redirected to for "not found" URLs for a specific domain. 12 | 13 | ## SYNTAX 14 | 15 | ### BaseUrlRedirect (Default) 16 | ``` 17 | Set-ShlinkDomainRedirects -Domain -BaseUrlRedirect [-Regular404Redirect ] 18 | [-InvalidShortUrlRedirect ] [-ShlinkServer ] [-ShlinkApiKey ] 19 | [] 20 | ``` 21 | 22 | ### InvalidShortUrlRedirect 23 | ``` 24 | Set-ShlinkDomainRedirects -Domain [-BaseUrlRedirect ] [-Regular404Redirect ] 25 | -InvalidShortUrlRedirect [-ShlinkServer ] [-ShlinkApiKey ] [] 26 | ``` 27 | 28 | ### Regular404Redirect 29 | ``` 30 | Set-ShlinkDomainRedirects -Domain [-BaseUrlRedirect ] -Regular404Redirect 31 | [-InvalidShortUrlRedirect ] [-ShlinkServer ] [-ShlinkApiKey ] 32 | [] 33 | ``` 34 | 35 | ## DESCRIPTION 36 | Sets the URLs that you want a visitor to get redirected to for "not found" URLs for a specific domain. 37 | 38 | ## EXAMPLES 39 | 40 | ### EXAMPLE 1 41 | ``` 42 | Set-ShlinkDomainRedirects -Domain "example.com" -BaseUrlRedirect "https://someotheraddress.com" 43 | ``` 44 | 45 | Modifies the redirect setting 'BaseUrlRedirect' of example.com to redirect to "https://someotheraddress.com". 46 | 47 | ## PARAMETERS 48 | 49 | ### -Domain 50 | The domain (excluding schema) in which you would like to modify the redirects of. 51 | For example, "example.com" is an acceptable value. 52 | 53 | ```yaml 54 | Type: String 55 | Parameter Sets: (All) 56 | Aliases: 57 | 58 | Required: True 59 | Position: Named 60 | Default value: None 61 | Accept pipeline input: False 62 | Accept wildcard characters: False 63 | ``` 64 | 65 | ### -BaseUrlRedirect 66 | Modify the 'BaseUrlRedirect' redirect setting of the domain. 67 | 68 | ```yaml 69 | Type: String 70 | Parameter Sets: BaseUrlRedirect 71 | Aliases: 72 | 73 | Required: True 74 | Position: Named 75 | Default value: None 76 | Accept pipeline input: False 77 | Accept wildcard characters: False 78 | ``` 79 | 80 | ```yaml 81 | Type: String 82 | Parameter Sets: InvalidShortUrlRedirect, Regular404Redirect 83 | Aliases: 84 | 85 | Required: False 86 | Position: Named 87 | Default value: None 88 | Accept pipeline input: False 89 | Accept wildcard characters: False 90 | ``` 91 | 92 | ### -Regular404Redirect 93 | Modify the 'Regular404Redirect' redirect setting of the domain. 94 | 95 | ```yaml 96 | Type: String 97 | Parameter Sets: BaseUrlRedirect, InvalidShortUrlRedirect 98 | Aliases: 99 | 100 | Required: False 101 | Position: Named 102 | Default value: None 103 | Accept pipeline input: False 104 | Accept wildcard characters: False 105 | ``` 106 | 107 | ```yaml 108 | Type: String 109 | Parameter Sets: Regular404Redirect 110 | Aliases: 111 | 112 | Required: True 113 | Position: Named 114 | Default value: None 115 | Accept pipeline input: False 116 | Accept wildcard characters: False 117 | ``` 118 | 119 | ### -InvalidShortUrlRedirect 120 | Modify the 'InvalidShortUrlRedirect' redirect setting of the domain. 121 | 122 | ```yaml 123 | Type: String 124 | Parameter Sets: BaseUrlRedirect, Regular404Redirect 125 | Aliases: 126 | 127 | Required: False 128 | Position: Named 129 | Default value: None 130 | Accept pipeline input: False 131 | Accept wildcard characters: False 132 | ``` 133 | 134 | ```yaml 135 | Type: String 136 | Parameter Sets: InvalidShortUrlRedirect 137 | Aliases: 138 | 139 | Required: True 140 | Position: Named 141 | Default value: None 142 | Accept pipeline input: False 143 | Accept wildcard characters: False 144 | ``` 145 | 146 | ### -ShlinkServer 147 | The URL of your Shlink server (including schema). 148 | For example "https://example.com". 149 | It is not required to use this parameter for every use of this function. 150 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 151 | 152 | ```yaml 153 | Type: String 154 | Parameter Sets: (All) 155 | Aliases: 156 | 157 | Required: False 158 | Position: Named 159 | Default value: None 160 | Accept pipeline input: False 161 | Accept wildcard characters: False 162 | ``` 163 | 164 | ### -ShlinkApiKey 165 | A SecureString object of your Shlink server's API key. 166 | It is not required to use this parameter for every use of this function. 167 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 168 | 169 | ```yaml 170 | Type: SecureString 171 | Parameter Sets: (All) 172 | Aliases: 173 | 174 | Required: False 175 | Position: Named 176 | Default value: None 177 | Accept pipeline input: False 178 | Accept wildcard characters: False 179 | ``` 180 | 181 | ### CommonParameters 182 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 183 | 184 | ## INPUTS 185 | 186 | ### This function does not accept pipeline input. 187 | ## OUTPUTS 188 | 189 | ### System.Management.Automation.PSObject 190 | ## NOTES 191 | 192 | ## RELATED LINKS 193 | -------------------------------------------------------------------------------- /.github/workflows/pipeline.yml: -------------------------------------------------------------------------------- 1 | # This workflow has been modified from the default supplied in codaamok.build 2 | name: "Pipeline" 3 | 4 | on: 5 | push: 6 | paths: 7 | - 'src/**' 8 | branches: 9 | - main 10 | - master 11 | schedule: 12 | - cron: '30 7 * * *' 13 | workflow_dispatch: 14 | 15 | jobs: 16 | job-main: 17 | name: main 18 | runs-on: ubuntu-latest 19 | services: 20 | shlink: 21 | image: shlinkio/shlink:stable 22 | ports: 23 | - 80:8080 24 | env: 25 | IS_HTTPS_ENABLED: false 26 | DEFAULT_DOMAIN: psshlink.codaamok 27 | options: --name shlink 28 | steps: 29 | - name: Checkout repository 30 | uses: actions/checkout@v2.3.1 31 | with: 32 | fetch-depth: 0 33 | 34 | - name: Install GitVersion 35 | uses: gittools/actions/gitversion/setup@v0.9.10 36 | with: 37 | versionSpec: '5.x' 38 | 39 | - name: Determine Version 40 | id: gitversion 41 | uses: gittools/actions/gitversion/execute@v0.9.10 42 | with: 43 | useConfigFile: true 44 | 45 | - name: Install codaamok.build and dependent modules, and set environment variables 46 | run: | 47 | Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted 48 | Install-Module "InvokeBuild" -Force 49 | $Username, $ProjectName = $env:GITHUB_REPOSITORY -split "/" 50 | Invoke-Build -File "invoke.build.ps1" -ModuleName $ProjectName -Author $Username -Task "InstallDependencies","ImportBuildModule","SetGitHubActionEnvironmentVariables" 51 | shell: pwsh 52 | 53 | - name: Build 54 | run: | 55 | $Params = @{ 56 | ModuleName = $env:GH_PROJECTNAME 57 | Author = $env:GH_USERNAME 58 | Version = $env:GitVersion_SemVer 59 | NewRelease = ('push','workflow_dispatch' -contains $env:EVENT_NAME) 60 | } 61 | Invoke-Build -File "custom.build.ps1" @Params -Task PreBuild 62 | Invoke-Build -File "invoke.build.ps1" @Params 63 | Invoke-Build -File "custom.build.ps1" @Params -Task PostBuild 64 | shell: pwsh 65 | env: 66 | EVENT_NAME: ${{ github.event_name }} 67 | 68 | - name: Modify DNS 69 | run: echo "127.0.0.1 psshlink.codaamok" | sudo tee -a /etc/hosts 70 | 71 | - name: Generate Shlink API key 72 | run: | 73 | New-BuildEnvironmentVariable -Platform "GitHubActions" -Variable @{ 74 | "ShlinkAPIKey" = [Regex]::Match((docker exec -t shlink shlink api-key:generate --no-ansi), '([0-9A-Fa-f]{8}(?:-[0-9A-Fa-f]{4}){3}-[0-9A-Fa-f]{12})') | 75 | Select-Object -ExpandProperty Value | 76 | ConvertTo-SecureString -AsPlainText -Force | 77 | ConvertFrom-SecureString 78 | "ShlinkServer" = "http://psshlink.codaamok" 79 | } 80 | shell: pwsh 81 | 82 | - name: Pester Tests 83 | if: hashFiles('tests/invoke.tests.ps1') != '' 84 | run: pwsh -File "tests/invoke.tests.ps1" 85 | 86 | - name: Pester Tests Report 87 | if: hashFiles('testResults.xml') != '' 88 | uses: zyborg/pester-tests-report@v1 89 | with: 90 | test_results_path: 'testResults.xml' 91 | report_name: Pester Tests Report 92 | report_title: Pester Tests Report 93 | github_token: ${{ secrets.GITHUB_TOKEN }} 94 | 95 | - name: Custom pre-release tasks 96 | if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} 97 | run: Invoke-Build -File "custom.build.ps1" -ModuleName $env:GH_PROJECTNAME -Author $env:GH_USERNAME -Version $env:GitVersion_SemVer -NewRelease $true -Task PreRelease 98 | shell: pwsh 99 | 100 | - name: Publish to PowerShell Gallery 101 | if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} 102 | run: Invoke-Build -File "invoke.build.ps1" -ModuleName $env:GH_PROJECTNAME -Task "PublishModule" 103 | shell: pwsh 104 | env: 105 | PSGALLERY_API_KEY: ${{ secrets.PSGALLERY_API_KEY }} 106 | 107 | - name: Create release 108 | if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} 109 | id: create_release 110 | uses: actions/create-release@v1 111 | env: 112 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 113 | with: 114 | tag_name: v${{ env.GitVersion_SemVer }} 115 | release_name: v${{ env.GitVersion_SemVer }} 116 | body_path: release/releasenotes.txt 117 | draft: false 118 | prerelease: false 119 | 120 | - name: Upload release asset 121 | if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} 122 | id: upload_release_asset 123 | uses: actions/upload-release-asset@v1 124 | env: 125 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 126 | with: 127 | upload_url: ${{ steps.create_release.outputs.upload_url }} 128 | asset_path: release/${{ env.GH_PROJECTNAME }}_${{ env.GitVersion_SemVer }}.zip 129 | asset_name: ${{ env.GH_PROJECTNAME }}_${{ env.GitVersion_SemVer }}.zip 130 | asset_content_type: application/zip 131 | 132 | - name: Commit CHANGELOG.md and module manifest 133 | if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} 134 | run: | 135 | git config --global user.email "action@github.com" 136 | git config --global user.name "GitHub Action" 137 | git add CHANGELOG.md src/${GH_PROJECTNAME}.psd1 docs 138 | git commit -m "Released ${{ env.GitVersion_SemVer }}" 139 | 140 | - name: Push commit 141 | if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} 142 | uses: ad-m/github-push-action@master 143 | with: 144 | github_token: ${{ secrets.GITHUB_TOKEN }} 145 | 146 | - name: Custom post-release tasks 147 | if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} 148 | run: Invoke-Build -File "custom.build.ps1" -ModuleName $env:GH_PROJECTNAME -Author $env:GH_USERNAME -Version $env:GitVersion_SemVer -NewRelease $true -Task PostRelease 149 | shell: pwsh 150 | -------------------------------------------------------------------------------- /docs/Invoke-ShlinkRestMethod.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Invoke-ShlinkRestMethod 9 | 10 | ## SYNOPSIS 11 | Query a Shlink server's REST API 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Invoke-ShlinkRestMethod [-Endpoint] [[-Path] ] [[-Query] ] 17 | [[-ApiVersion] ] [[-Method] ] [[-PropertyTree] ] [[-ShlinkServer] ] 18 | [[-ShlinkApiKey] ] [] 19 | ``` 20 | 21 | ## DESCRIPTION 22 | This function provides flexibility to query a Shlink's server how you want to. 23 | 24 | Specify all the parameters, endpoint, and path details you need. 25 | 26 | All data from all pages are returned. 27 | 28 | See Shlink's REST API documentation: https://shlink.io/documentation/api-docs/ and https://api-spec.shlink.io/ 29 | 30 | ## EXAMPLES 31 | 32 | ### EXAMPLE 1 33 | ``` 34 | Invoke-ShlinkRestMethod -Endpoint "short-urls" -PropertyTree "shortUrls", "Data" -Query [System.Web.HttpUtility]::ParseQueryString("searchTerm", "abc") 35 | ``` 36 | 37 | Gets all short codes from Shlink matching the search term "abc". 38 | 39 | Note (it's not obvious), you can add more query params to an instance of HttpUtility like you can any dictionary by using the .Add() method on the object. 40 | 41 | ### EXAMPLE 2 42 | ``` 43 | Invoke-ShlinkRestMethod -Endpoint "short-urls" -Path "abc" -METHOD "DELETE" 44 | ``` 45 | 46 | Deletes the shortcode "abc" from Shlink. 47 | 48 | ### EXAMPLE 3 49 | ``` 50 | Invoke-ShlinkRestMethod -Endpoint "tags" -Path "stats" 51 | ``` 52 | 53 | Gets all tags with statistics. 54 | 55 | ## PARAMETERS 56 | 57 | ### -Endpoint 58 | The endpoint to use in the request. 59 | This is before the -Path. 60 | See the examples for example usage. 61 | 62 | ```yaml 63 | Type: String 64 | Parameter Sets: (All) 65 | Aliases: 66 | 67 | Required: True 68 | Position: 1 69 | Default value: None 70 | Accept pipeline input: False 71 | Accept wildcard characters: False 72 | ``` 73 | 74 | ### -Path 75 | The path to use in the request. 76 | This is after the -Endpoint. 77 | See the examples for example usage. 78 | 79 | ```yaml 80 | Type: String 81 | Parameter Sets: (All) 82 | Aliases: 83 | 84 | Required: False 85 | Position: 2 86 | Default value: None 87 | Accept pipeline input: False 88 | Accept wildcard characters: False 89 | ``` 90 | 91 | ### -Query 92 | The query to use in the request. 93 | Must be an instance of System.Web.HttpUtility. 94 | See the examples for example usage. 95 | 96 | Note (it's not obvious), you can add more query params to an instance of HttpUtility like you can any dictionary by using the .Add() method on the object. 97 | 98 | ```yaml 99 | Type: HttpUtility 100 | Parameter Sets: (All) 101 | Aliases: 102 | 103 | Required: False 104 | Position: 3 105 | Default value: None 106 | Accept pipeline input: False 107 | Accept wildcard characters: False 108 | ``` 109 | 110 | ### -ApiVersion 111 | The API version of Shlink to use in the request. 112 | 113 | ```yaml 114 | Type: Int32 115 | Parameter Sets: (All) 116 | Aliases: 117 | 118 | Required: False 119 | Position: 4 120 | Default value: 3 121 | Accept pipeline input: False 122 | Accept wildcard characters: False 123 | ``` 124 | 125 | ### -Method 126 | The HTTP method to use in the request. 127 | 128 | ```yaml 129 | Type: WebRequestMethod 130 | Parameter Sets: (All) 131 | Aliases: 132 | Accepted values: Default, Get, Head, Post, Put, Delete, Trace, Options, Merge, Patch 133 | 134 | Required: False 135 | Position: 5 136 | Default value: GET 137 | Accept pipeline input: False 138 | Accept wildcard characters: False 139 | ``` 140 | 141 | ### -PropertyTree 142 | Data returned by Shlink's rest API is usually embedded within one or two properties. 143 | 144 | Here you can specify the embedded properties as a string array in the order you need to select them to access the data. 145 | 146 | For example, the "short-urls" endpoint includes the data within the "shortUrls.data" properties. 147 | Therefore, for this parameter you specify a string array of @("shortUrls", "data"). 148 | 149 | In other words, using this function for the short-urls endpoint results in the below object if there are two pages worth of data returned: 150 | 151 | Invoke-ShlinkRestMethod -Endpoint 'short-urls' 152 | 153 | shortUrls 154 | --------- 155 | @{data=System.Object\[\]; pagination=} 156 | @{data=System.Object\[\]; pagination=} 157 | 158 | ```yaml 159 | Type: String[] 160 | Parameter Sets: (All) 161 | Aliases: 162 | 163 | Required: False 164 | Position: 6 165 | Default value: None 166 | Accept pipeline input: False 167 | Accept wildcard characters: False 168 | ``` 169 | 170 | ### -ShlinkServer 171 | The URL of your Shlink server (including schema). 172 | For example "https://example.com". 173 | It is not required to use this parameter for every use of this function. 174 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 175 | 176 | ```yaml 177 | Type: String 178 | Parameter Sets: (All) 179 | Aliases: 180 | 181 | Required: False 182 | Position: 7 183 | Default value: None 184 | Accept pipeline input: False 185 | Accept wildcard characters: False 186 | ``` 187 | 188 | ### -ShlinkApiKey 189 | A SecureString object of your Shlink server's API key. 190 | It is not required to use this parameter for every use of this function. 191 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 192 | 193 | ```yaml 194 | Type: SecureString 195 | Parameter Sets: (All) 196 | Aliases: 197 | 198 | Required: False 199 | Position: 8 200 | Default value: None 201 | Accept pipeline input: False 202 | Accept wildcard characters: False 203 | ``` 204 | 205 | ### CommonParameters 206 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 207 | 208 | ## INPUTS 209 | 210 | ### This function does not accept pipeline input. 211 | ## OUTPUTS 212 | 213 | ### System.Management.Automation.PSObject 214 | ## NOTES 215 | 216 | ## RELATED LINKS 217 | -------------------------------------------------------------------------------- /src/Public/Get-ShlinkVisits.ps1: -------------------------------------------------------------------------------- 1 | function Get-ShlinkVisits { 2 | <# 3 | .SYNOPSIS 4 | Get details of visits for a Shlink server, short codes or tags. 5 | .DESCRIPTION 6 | Get details of visits for a Shlink server, short codes or tags. 7 | .PARAMETER ShortCode 8 | The name of the short code you wish to return the visits data for. For example, if the short URL is "https://example.com/new-url" then the short code is "new-url". 9 | .PARAMETER Tag 10 | The name of the tag you wish to return the visits data for. 11 | .PARAMETER Domain 12 | The domain (excluding schema) associated with the short code you wish to search for. For example, "example.com" is an acceptable value. 13 | This is useful if your Shlink instance is responding/creating short URLs for multiple domains. 14 | .PARAMETER StartDate 15 | A datetime object to filter the visit data where the start date is equal or greater than this value. 16 | .PARAMETER EndDate 17 | A datetime object to filter the visit data where its end date is equal or less than this value. 18 | .PARAMETER ExcludeBots 19 | Exclude visits from bots or crawlers. 20 | .PARAMETER ShlinkServer 21 | The URL of your Shlink server (including schema). For example "https://example.com". 22 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 23 | .PARAMETER ShlinkApiKey 24 | A SecureString object of your Shlink server's API key. 25 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 26 | .EXAMPLE 27 | PS C:\> Get-ShlinkVists 28 | 29 | Returns the overall visit count for your Shlink server 30 | .EXAMPLE 31 | PS C:\> Get-ShlinkVisits -ShortCode "profile" 32 | 33 | Returns all visit data associated with the short code "profile" 34 | .EXAMPLE 35 | PS C:\> Get-ShlinkVisits -Tag "oldwebsite" 36 | 37 | Returns all the visit data for all short codes asociated with the tag "oldwebsite" 38 | .EXAMPLE 39 | PS C:\> Get-ShlinkVisits -ShortCode "profile" -StartDate (Get-Date "2020-11-01") -EndDate (Get-Date "2020-12-01") 40 | 41 | Returns all visit data associated with the short code "profile" for the whole of November 2020 42 | .EXAMPLE 43 | PS C:\> Get-ShlinkVisits -Domain "contoso.com" 44 | 45 | Returns all visit data associated with the domain "contoso.com" 46 | .INPUTS 47 | This function does not accept pipeline input. 48 | .OUTPUTS 49 | System.Management.Automation.PSObject 50 | #> 51 | [CmdletBinding(DefaultParameterSetName="Server")] 52 | param ( 53 | [Parameter(Mandatory, ParameterSetName="ShortCode")] 54 | [String]$ShortCode, 55 | 56 | [Parameter(Mandatory, ParameterSetName="Tag")] 57 | [String]$Tag, 58 | 59 | [Parameter(ParameterSetName="ShortCode")] 60 | [Parameter(ParameterSetName="Tag")] 61 | [Parameter(Mandatory, ParameterSetName="Domain")] 62 | [String]$Domain, 63 | 64 | [Parameter(ParameterSetName="ShortCode")] 65 | [Parameter(ParameterSetName="Tag")] 66 | [Parameter(ParameterSetName="Domain")] 67 | [datetime]$StartDate, 68 | 69 | [Parameter(ParameterSetName="ShortCode")] 70 | [Parameter(ParameterSetName="Tag")] 71 | [Parameter(ParameterSetName="Domain")] 72 | [datetime]$EndDate, 73 | 74 | [Parameter(ParameterSetName="ShortCode")] 75 | [Parameter(ParameterSetName="Tag")] 76 | [Parameter(ParameterSetName="Domain")] 77 | [Switch]$ExcludeBots, 78 | 79 | [Parameter()] 80 | [String]$ShlinkServer, 81 | 82 | [Parameter()] 83 | [SecureString]$ShlinkApiKey 84 | ) 85 | 86 | try { 87 | GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey 88 | } 89 | catch { 90 | Write-Error -ErrorRecord $_ -ErrorAction "Stop" 91 | } 92 | 93 | $QueryString = [System.Web.HttpUtility]::ParseQueryString('') 94 | 95 | $Params = @{ 96 | PropertyTree = @("visits") 97 | } 98 | 99 | switch -Regex ($PSCmdlet.ParameterSetName) { 100 | "Server" { 101 | $Params["Endpoint"] = "visits" 102 | } 103 | "ShortCode|Tag|Domain" { 104 | $Params["PropertyTree"] += "data" 105 | $Params["PSTypeName"] = "PSShlinkVisits" 106 | 107 | switch ($PSBoundParameters.Keys) { 108 | "StartDate" { 109 | $QueryString.Add("startDate", (Get-Date $StartDate -Format "yyyy-MM-ddTHH:mm:sszzzz")) 110 | } 111 | "EndDate" { 112 | $QueryString.Add("endDate", (Get-Date $EndDate -Format "yyyy-MM-ddTHH:mm:sszzzz")) 113 | } 114 | "ExcludeBots" { 115 | $QueryString.Add("excludeBots", "true") 116 | } 117 | } 118 | } 119 | "ShortCode" { 120 | $Params["Endpoint"] = "short-urls/{0}/visits" -f $ShortCode 121 | 122 | if ($PSBoundParameters.Keys -contains "Domain") { 123 | $QueryString.Add("domain", $Domain) 124 | } 125 | } 126 | "Tag" { 127 | $Params["Endpoint"] = "tags/{0}/visits" -f $Tag 128 | 129 | if ($PSBoundParameters.Keys -contains "Domain") { 130 | $QueryString.Add("domain", $Domain) 131 | } 132 | } 133 | "Domain" { 134 | $Params["Endpoint"] = "domains/{0}/visits" -f $Domain 135 | } 136 | } 137 | 138 | $Params["Query"] = $QueryString 139 | 140 | try { 141 | $Result = InvokeShlinkRestMethod @Params 142 | 143 | # I figured it would be nice to add the Server property so it is immediately clear 144 | # the server's view count is returned when no parameters are used 145 | if ($PSCmdlet.ParameterSetName -eq "Server") { 146 | [PSCustomObject]@{ 147 | Server = $Script:ShlinkServer 148 | visitsCount = $Result.visitsCount 149 | } 150 | } 151 | else { 152 | $Result 153 | } 154 | } 155 | catch { 156 | Write-Error -ErrorRecord $_ 157 | } 158 | } -------------------------------------------------------------------------------- /docs/Get-ShlinkVisits.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-ShlinkVisits 9 | 10 | ## SYNOPSIS 11 | Get details of visits for a Shlink server, short codes or tags. 12 | 13 | ## SYNTAX 14 | 15 | ### Server (Default) 16 | ``` 17 | Get-ShlinkVisits [-ShlinkServer ] [-ShlinkApiKey ] [] 18 | ``` 19 | 20 | ### ShortCode 21 | ``` 22 | Get-ShlinkVisits -ShortCode [-Domain ] [-StartDate ] [-EndDate ] 23 | [-ExcludeBots] [-ShlinkServer ] [-ShlinkApiKey ] [] 24 | ``` 25 | 26 | ### Tag 27 | ``` 28 | Get-ShlinkVisits -Tag [-Domain ] [-StartDate ] [-EndDate ] [-ExcludeBots] 29 | [-ShlinkServer ] [-ShlinkApiKey ] [] 30 | ``` 31 | 32 | ### Domain 33 | ``` 34 | Get-ShlinkVisits -Domain [-StartDate ] [-EndDate ] [-ExcludeBots] 35 | [-ShlinkServer ] [-ShlinkApiKey ] [] 36 | ``` 37 | 38 | ## DESCRIPTION 39 | Get details of visits for a Shlink server, short codes or tags. 40 | 41 | ## EXAMPLES 42 | 43 | ### EXAMPLE 1 44 | ``` 45 | Get-ShlinkVists 46 | ``` 47 | 48 | Returns the overall visit count for your Shlink server 49 | 50 | ### EXAMPLE 2 51 | ``` 52 | Get-ShlinkVisits -ShortCode "profile" 53 | ``` 54 | 55 | Returns all visit data associated with the short code "profile" 56 | 57 | ### EXAMPLE 3 58 | ``` 59 | Get-ShlinkVisits -Tag "oldwebsite" 60 | ``` 61 | 62 | Returns all the visit data for all short codes asociated with the tag "oldwebsite" 63 | 64 | ### EXAMPLE 4 65 | ``` 66 | Get-ShlinkVisits -ShortCode "profile" -StartDate (Get-Date "2020-11-01") -EndDate (Get-Date "2020-12-01") 67 | ``` 68 | 69 | Returns all visit data associated with the short code "profile" for the whole of November 2020 70 | 71 | ### EXAMPLE 5 72 | ``` 73 | Get-ShlinkVisits -Domain "contoso.com" 74 | ``` 75 | 76 | Returns all visit data associated with the domain "contoso.com" 77 | 78 | ## PARAMETERS 79 | 80 | ### -ShortCode 81 | The name of the short code you wish to return the visits data for. 82 | For example, if the short URL is "https://example.com/new-url" then the short code is "new-url". 83 | 84 | ```yaml 85 | Type: String 86 | Parameter Sets: ShortCode 87 | Aliases: 88 | 89 | Required: True 90 | Position: Named 91 | Default value: None 92 | Accept pipeline input: False 93 | Accept wildcard characters: False 94 | ``` 95 | 96 | ### -Tag 97 | The name of the tag you wish to return the visits data for. 98 | 99 | ```yaml 100 | Type: String 101 | Parameter Sets: Tag 102 | Aliases: 103 | 104 | Required: True 105 | Position: Named 106 | Default value: None 107 | Accept pipeline input: False 108 | Accept wildcard characters: False 109 | ``` 110 | 111 | ### -Domain 112 | The domain (excluding schema) associated with the short code you wish to search for. 113 | For example, "example.com" is an acceptable value. 114 | This is useful if your Shlink instance is responding/creating short URLs for multiple domains. 115 | 116 | ```yaml 117 | Type: String 118 | Parameter Sets: ShortCode, Tag 119 | Aliases: 120 | 121 | Required: False 122 | Position: Named 123 | Default value: None 124 | Accept pipeline input: False 125 | Accept wildcard characters: False 126 | ``` 127 | 128 | ```yaml 129 | Type: String 130 | Parameter Sets: Domain 131 | Aliases: 132 | 133 | Required: True 134 | Position: Named 135 | Default value: None 136 | Accept pipeline input: False 137 | Accept wildcard characters: False 138 | ``` 139 | 140 | ### -StartDate 141 | A datetime object to filter the visit data where the start date is equal or greater than this value. 142 | 143 | ```yaml 144 | Type: DateTime 145 | Parameter Sets: ShortCode, Tag, Domain 146 | Aliases: 147 | 148 | Required: False 149 | Position: Named 150 | Default value: None 151 | Accept pipeline input: False 152 | Accept wildcard characters: False 153 | ``` 154 | 155 | ### -EndDate 156 | A datetime object to filter the visit data where its end date is equal or less than this value. 157 | 158 | ```yaml 159 | Type: DateTime 160 | Parameter Sets: ShortCode, Tag, Domain 161 | Aliases: 162 | 163 | Required: False 164 | Position: Named 165 | Default value: None 166 | Accept pipeline input: False 167 | Accept wildcard characters: False 168 | ``` 169 | 170 | ### -ExcludeBots 171 | Exclude visits from bots or crawlers. 172 | 173 | ```yaml 174 | Type: SwitchParameter 175 | Parameter Sets: ShortCode, Tag, Domain 176 | Aliases: 177 | 178 | Required: False 179 | Position: Named 180 | Default value: False 181 | Accept pipeline input: False 182 | Accept wildcard characters: False 183 | ``` 184 | 185 | ### -ShlinkServer 186 | The URL of your Shlink server (including schema). 187 | For example "https://example.com". 188 | It is not required to use this parameter for every use of this function. 189 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 190 | 191 | ```yaml 192 | Type: String 193 | Parameter Sets: (All) 194 | Aliases: 195 | 196 | Required: False 197 | Position: Named 198 | Default value: None 199 | Accept pipeline input: False 200 | Accept wildcard characters: False 201 | ``` 202 | 203 | ### -ShlinkApiKey 204 | A SecureString object of your Shlink server's API key. 205 | It is not required to use this parameter for every use of this function. 206 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 207 | 208 | ```yaml 209 | Type: SecureString 210 | Parameter Sets: (All) 211 | Aliases: 212 | 213 | Required: False 214 | Position: Named 215 | Default value: None 216 | Accept pipeline input: False 217 | Accept wildcard characters: False 218 | ``` 219 | 220 | ### CommonParameters 221 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 222 | 223 | ## INPUTS 224 | 225 | ### This function does not accept pipeline input. 226 | ## OUTPUTS 227 | 228 | ### System.Management.Automation.PSObject 229 | ## NOTES 230 | 231 | ## RELATED LINKS 232 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PSShlink 2 | | Branch | Build status | Last commit | Latest release | PowerShell Gallery | GitHub | 3 | |-|-|-|-|-|-| 4 | | `main` | [![GitHub Workflow Status (branch)](https://img.shields.io/github/actions/workflow/status/codaamok/PSShlink/pipeline.yml?branch=main)](https://github.com/codaamok/PSShlink/actions) | [![GitHub last commit (branch)](https://img.shields.io/github/last-commit/codaamok/PSShlink/main?color=blue)](https://github.com/codaamok/PSShlink/commits/main) | [![GitHub release (latest by date)](https://img.shields.io/github/v/release/codaamok/PSShlink?color=blue)](https://github.com/codaamok/PSShlink/releases/latest) [![GitHub Release Date](https://img.shields.io/github/release-date/codaamok/PSShlink?color=blue)](https://github.com/codaamok/PSShlink/releases/latest) | [![PowerShell Gallery](https://img.shields.io/powershellgallery/dt/PSShlink?color=blue)](https://www.powershellgallery.com/packages/PSShlink) | [![GitHub all releases](https://img.shields.io/github/downloads/codaamok/PSShlink/total?color=blue)](https://github.com/codaamok/PSShlink/releases) | 5 | 6 | 7 | An unofficial PowerShell module for Shlink (https://shlink.io), an open-source self-hosted and PHP-based URL shortener application. 8 | 9 | ## Functions 10 | 11 | - [Get-ShlinkDomains](docs/Get-ShlinkDomains.md) 12 | - [Get-ShlinkServer](docs/Get-ShlinkServer.md) 13 | - [Get-ShlinkTags](docs/Get-ShlinkTags.md) 14 | - [Get-ShlinkUrl](docs/Get-ShlinkUrl.md) 15 | - [Get-ShlinkVisits](docs/Get-ShlinkVisits.md) 16 | - [Get-ShlinkVisitsNonOrphan](docs/Get-ShlinkVisitsNonOrphan.md) 17 | - [Get-ShlinkVisitsOrphan](docs/Get-ShlinkVisitsOrphan.md) 18 | - [Invoke-ShlinkRestMethod](docs/Invoke-ShlinkRestMethod.md) 19 | - [New-ShlinkUrl](docs/New-ShlinkUrl.md) 20 | - [Remove-ShlinkTag](docs/Remove-ShlinkTag.md) 21 | - [Remove-ShlinkUrl](docs/Remove-ShlinkUrl.md) 22 | - [Save-ShlinkUrlQrCode](docs/Save-ShlinkUrlQrCode.md) 23 | - [Set-ShlinkDomainRedirects](docs/Set-ShlinkDomainRedirects.md) 24 | - [Set-ShlinkTag](docs/Set-ShlinkTag.md) 25 | - [Set-ShlinkUrl](docs/Set-ShlinkUrl.md) 26 | 27 | ## Requirements 28 | 29 | - PowerShell 5.1 or newer (including PowerShell Core, 7.0 or newer) 30 | - Shlink 3.5.0 or newer 31 | - If you need support for older versions of Shlink, you can still source older versions of PSShlink [here](https://github.com/codaamok/PSShlink/releases) or use the `-RequiredVersion` parameter of `Install-Module` when installed from the PowerShell Gallery 32 | 33 | ## Getting started 34 | 35 | Install and import: 36 | 37 | ```powershell 38 | Install-Module PSShlink -Scope CurrentUser 39 | Import-Module PSShlink 40 | ``` 41 | 42 | Be sure to check out the examples below. 43 | 44 | ## Authentication 45 | 46 | Each function will have two parameters for authentication to your Shlink instance: 47 | 48 | - `-ShlinkServer`: a string value of the Shlink server address e.g. `https://example.com` 49 | - `-ShlinkApiKey`: a SecureString value for the Shlink server's API key 50 | 51 | After using any function of PSShlink for the first time after importing the module - which have both parameters `-ShlinkServer` and `-ShlinkApiKey` * - it is not necessary to use the parameters again in subsequent uses for other functions of PSShlink. These values are held in memory for as long as the PowerShell session exists. 52 | 53 | \* Some functions do not require both `-ShlinkServer` and `-ShlinkApiKey`, e.g. `Get-ShlinkServer`. Therefore if the first function you use after importing PSShlink accepts only `-ShlinkServer`, you will not be asked again for this value by other functions of PSShlink. You will however be prompted for the API key. Again, subsequent uses of other functions will no longer require `-ShlinkServer` and `-ShlinkApiKey`. 54 | 55 | If the first function you use after importing PSShlink requires `-ShlinkServer` and/or `-ShlinkApiKey` and you have not passed the parameter(s), you will be prompted for them. 56 | 57 | ## Examples 58 | 59 | All functions come with complete comment based help, so it is possible to find examples for each function using `Get-Help`. For example, use the following to see detailed help including examples for `Save-ShlinkUrlQrCode`: 60 | 61 | ```powershell 62 | Get-Help Save-ShlinkUrlQrCode 63 | ``` 64 | 65 | ___ 66 | 67 | ```powershell 68 | $Key = "ba6c52ed-flk5-4e84-9fc7-9c7e34825da0" | ConvertTo-SecureString -AsPlainText -Force 69 | Get-ShlinkUrl -SearchTerm "oldWebsite" -ShlinkServer "https://myshlinkserver.com" -ShlinkApiKey $Key 70 | ``` 71 | 72 | Returns all short codes which match the search term `oldWebsite`. 73 | 74 | ___ 75 | 76 | ```powershell 77 | Get-ShlinkUrl -SearchTerm "oldWebsite" | Remove-ShlinkUrl 78 | ``` 79 | 80 | Deletes all short codes from the Shlink server which match the search term `oldWebsite`. 81 | 82 | ___ 83 | 84 | ```powershell 85 | Get-ShlinkUrl -SearchTerm "newWebsite" | Save-ShlinkUrlQrCode 86 | ``` 87 | 88 | Saves QR codes for all short URLs which match the search term `newWebsite`. All files will be saved as the default values for size (300x300) and type (png). All files by default are saved in your Downloads directory using the naming convention: `ShlinkQRCode___.`. e.g. `ShlinkQRCode_asFk2_example-com_300.png`. 89 | 90 | ___ 91 | 92 | ```powershell 93 | Get-ShlinkUrl -SearchTerm "newWebsite" | Set-ShlinkUrl -Tags "newWebsite" -MaxVisits 100 94 | ``` 95 | 96 | Sets the tag `newWebsite` on all short codes matching the search term `newWebsite`. Also sets all matching short codes with a max visits value of 100. 97 | ___ 98 | 99 | ```powershell 100 | New-ShlinkUrl -LongUrl "https://tools.ietf.org/html/rfc2549" -CustomSlug "rfc2549" -Domain "cookadam.co.uk" -DoNotValidateUrl 101 | ``` 102 | 103 | Creates a new short code named `rfc2549` under the non-default domain `cookadam.co.uk`. The short code will redirect to `https://tools.ietf.org/html/rfc2549`. URL validation is not enforced. 104 | 105 | ## Known issues 106 | 107 | - If you specify a URL for `-ShlinkServer` where the web server responds with a redirect (e.g. to convert the URL from `http://` to `https://`), you will experience odd behaviour. The symptoms you might observe, for example, `New-ShlinkUrl` will respond with the first 10 short codes on your Shlink instance instead of creating a new short URL. The root cause stems from `Invoke-RestMethod` not persisting HTTP methods through redirects; it persistently uses HTTP GET in subsequent calls after receiving a redirect status code from the server. In other words, `New-ShlinkUrl` will make a POST request and when it receives a redirect response, it will re-process the same request with the same parameters and body but through a HTTP GET request. 108 | - See [Feature Request: create switch to persist HTTP method when following a redirect for Invoke-RestMethod or Invoke-WebRequest](https://github.com/PowerShell/PowerShell/issues/14531) 109 | 110 | ## Support 111 | 112 | If you experience any issues with PSShlink, please raise an issue on GitHub. 113 | -------------------------------------------------------------------------------- /src/Private/InvokeShlinkRestMethod.ps1: -------------------------------------------------------------------------------- 1 | function InvokeShlinkRestMethod { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter()] 5 | [String]$Server = $Script:ShlinkServer, 6 | 7 | [Parameter()] 8 | [SecureString]$ApiKey = $Script:ShlinkApiKey, 9 | 10 | [Parameter()] 11 | [ValidateSet(1, 2, 3)] 12 | [Int]$ApiVersion = 3, 13 | 14 | [Parameter()] 15 | [Microsoft.PowerShell.Commands.WebRequestMethod]$Method = 'GET', 16 | 17 | [Parameter(Mandatory)] 18 | [String]$Endpoint, 19 | 20 | [Parameter()] 21 | [String]$Path, 22 | 23 | # Default value set where no Query parameter is passed because we still need the object for pagination later 24 | [Parameter()] 25 | [System.Collections.Specialized.NameValueCollection]$Query = [System.Web.HttpUtility]::ParseQueryString(''), 26 | 27 | [Parameter()] 28 | [hashtable]$Body, 29 | 30 | [Parameter()] 31 | [String[]]$PropertyTree, 32 | 33 | [Parameter()] 34 | [String]$PSTypeName 35 | ) 36 | 37 | $Params = @{ 38 | Method = $Method 39 | Uri = "{0}/rest/v{1}/{2}" -f $Server, $ApiVersion, $Endpoint 40 | ContentType = "application/json" 41 | Headers = @{"X-Api-Key" = [PSCredential]::new("none", $ApiKey).GetNetworkCredential().Password} 42 | ErrorAction = "Stop" 43 | ErrorVariable = "InvokeRestMethodError" 44 | } 45 | 46 | if ($PSBoundParameters.ContainsKey("Path")) { 47 | $Params["Uri"] = "{0}/{1}" -f $Params["Uri"], $Path 48 | } 49 | 50 | # Preserve the URI which does not contain any query parameters for the pagination URI building later 51 | $QuerylessUri = $Params["Uri"] 52 | 53 | if ($PSBoundParameters.ContainsKey("Query")) { 54 | $Params["Uri"] = "{0}?{1}" -f $Params["Uri"], $Query.ToString() 55 | } 56 | 57 | if ($PSBoundParameters.ContainsKey("Body")) { 58 | $Params["Body"] = $Body | ConvertTo-Json 59 | } 60 | 61 | $Result = do { 62 | try { 63 | Write-Verbose ("Body: {0}" -f $Params["Body"]) 64 | $Data = Invoke-RestMethod @Params 65 | } 66 | catch { 67 | # The web exception class is different for Core vs Windows 68 | if ($InvokeRestMethodError.ErrorRecord.Exception.GetType().FullName -match "HttpResponseException|WebException") { 69 | $ExceptionMessage = $InvokeRestMethodError.Message | ConvertFrom-Json | Select-Object -ExpandProperty detail 70 | $ErrorId = "{0}{1}" -f 71 | [Int][System.Net.HttpStatusCode]$InvokeRestMethodError.ErrorRecord.Exception.Response.StatusCode, 72 | [String][System.Net.HttpStatusCode]$InvokeRestMethodError.ErrorRecord.Exception.Response.StatusCode 73 | 74 | switch -Regex ($InvokeRestMethodError.ErrorRecord.Exception.Response.StatusCode) { 75 | "Unauthorized" { 76 | $Exception = [System.UnauthorizedAccessException]::new($ExceptionMessage) 77 | $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( 78 | $Exception, 79 | $ErrorId, 80 | [System.Management.Automation.ErrorCategory]::AuthenticationError, 81 | $Params['Uri'] 82 | ) 83 | } 84 | "BadRequest|Conflict" { 85 | $Exception = [System.ArgumentException]::new($ExceptionMessage) 86 | $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( 87 | $Exception, 88 | $ErrorId, 89 | [System.Management.Automation.ErrorCategory]::InvalidArgument, 90 | $Params['Uri'] 91 | ) 92 | } 93 | "NotFound" { 94 | $Exception = [System.Management.Automation.ItemNotFoundException]::new($ExceptionMessage) 95 | $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( 96 | $Exception, 97 | $ErrorId, 98 | [System.Management.Automation.ErrorCategory]::ObjectNotFound, 99 | $Params['Uri'] 100 | ) 101 | } 102 | "ServiceUnavailable" { 103 | $Exception = [System.InvalidOperationException]::new($ExceptionMessage) 104 | $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( 105 | $Exception, 106 | $ErrorId, 107 | [System.Management.Automation.ErrorCategory]::ResourceUnavailable, 108 | $Params['Uri'] 109 | ) 110 | } 111 | default { 112 | $Exception = [System.InvalidOperationException]::new($ExceptionMessage) 113 | $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( 114 | $Exception, 115 | $ErrorId, 116 | [System.Management.Automation.ErrorCategory]::InvalidOperation, 117 | $Params['Uri'] 118 | ) 119 | } 120 | } 121 | 122 | $PSCmdlet.ThrowTerminatingError($ErrorRecord) 123 | } 124 | else { 125 | $PSCmdlet.ThrowTerminatingError($_) 126 | } 127 | } 128 | 129 | # Pagination data typically lives within the immediate property, or 1 more level deep 130 | $PaginationData = foreach ($Property in $Data.PSObject.Properties.Name) { 131 | if ($Property -eq 'pagination') { 132 | $Data.$Property 133 | break 134 | } 135 | elseif (-not [String]::IsNullOrWhiteSpace($Data.$Property.pagination)) { 136 | $Data.$Property.pagination 137 | break 138 | } 139 | } 140 | 141 | if ($PaginationData) { 142 | $Query["page"] = $PaginationData.currentPage + 1 143 | $Params["Uri"] = "{0}?{1}" -f $QuerylessUri, $Query.ToString() 144 | } 145 | 146 | Write-Output $Data 147 | } while ($PaginationData.currentPage -ne $PaginationData.pagesCount -And $PaginationData.pagesCount -ne 0) 148 | 149 | # Walk down the object's properties to return the desired property 150 | # e.g. sometimes the data is burried in tags.data or shortUrls.data etc 151 | foreach ($Property in $PropertyTree) { 152 | $Result = $Result.$Property 153 | } 154 | 155 | if ($PSBoundParameters.ContainsKey("PSTypeName")) { 156 | foreach ($item in $Result) { 157 | $item.PSTypeNames.Insert(0, $PSTypeName) 158 | } 159 | } 160 | 161 | Write-Output $Result 162 | } 163 | -------------------------------------------------------------------------------- /src/Public/New-ShlinkUrl.ps1: -------------------------------------------------------------------------------- 1 | function New-ShlinkUrl { 2 | <# 3 | .SYNOPSIS 4 | Creates a new Shlink short code on your Shlink server. 5 | .DESCRIPTION 6 | Creates a new Shlink short code on your Shlink server. 7 | .PARAMETER LongUrl 8 | Define the long URL for the new short code. 9 | .PARAMETER AndroidLongUrl 10 | The long URL to redirect to when the short URL is visited from a device running Android. 11 | .PARAMETER IOSLongUrl 12 | The long URL to redirect to when the short URL is visited from a device running iOS. 13 | .PARAMETER DesktopLongUrl 14 | The long URL to redirect to when the short URL is visited from a desktop browser. 15 | .PARAMETER CustomSlug 16 | Define a custom slug for the new short code. 17 | .PARAMETER Tags 18 | Associate tag(s) with the new short code. 19 | .PARAMETER ValidSince 20 | Define a "valid since" date with the new short code. 21 | .PARAMETER ValidUntil 22 | Define a "valid until" date with the new short code. 23 | .PARAMETER MaxVisits 24 | Set the maximum number of visits allowed for the new short code. 25 | .PARAMETER Title 26 | Define a title with the new short code. 27 | .PARAMETER Domain 28 | Associate a domain with the new short code to be something other than the default domain. 29 | This is useful if your Shlink instance is responding/creating short URLs for multiple domains. 30 | .PARAMETER ShortCodeLength 31 | Set the length of your new short code other than the default. 32 | .PARAMETER FindIfExists 33 | Specify this switch to first search and return the data about an existing short code that uses the same long URL if one exists. 34 | .PARAMETER ValidateUrl 35 | Control long URL validation while creating the short code. 36 | .PARAMETER ForwardQuery 37 | Forwards UTM query parameters to the long URL if any were passed to the short URL. 38 | .PARAMETER Crawlable 39 | Set short URLs as crawlable, making them be listed in the robots.txt as Allowed. 40 | .PARAMETER ShlinkServer 41 | The URL of your Shlink server (including schema). For example "https://example.com". 42 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 43 | .PARAMETER ShlinkApiKey 44 | A SecureString object of your Shlink server's API key. 45 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 46 | .EXAMPLE 47 | PS C:\> New-ShlinkUrl -LongUrl "https://google.com" 48 | 49 | Will generate a new short code with the long URL of "https://google.com", using your Shlink server's default for creating new short codes, and return all the information about the new short code. 50 | .EXAMPLE 51 | PS C:\> New-ShlinkUrl -LongUrl "https://google.com" -CustomSlug "mygoogle" -Tags "search-engine" -ValidSince (Get-Date "2020-11-01") -ValidUntil (Get-Date "2020-11-30") -MaxVisits 99 -FindIfExists 52 | 53 | Will generate a new short code with the long URL of "https://google.com" using the custom slug "search-engine". The default domain for the Shlink server will be used. The link will only be valid for November 2020. The link will only work for 99 visits. If a duplicate short code is found using the same long URL, another is not made and instead data about the existing short code is returned. 54 | .INPUTS 55 | This function does not accept pipeline input. 56 | .OUTPUTS 57 | System.Management.Automation.PSObject 58 | #> 59 | [CmdletBinding()] 60 | param ( 61 | [Parameter(Mandatory)] 62 | [String]$LongUrl, 63 | 64 | [Parameter()] 65 | [String]$AndroidLongUrl, 66 | 67 | [Parameter()] 68 | [String]$IOSLongUrl, 69 | 70 | [Parameter()] 71 | [String]$DesktopLongUrl, 72 | 73 | [Parameter()] 74 | [String]$CustomSlug, 75 | 76 | [Parameter()] 77 | [String[]]$Tags, 78 | 79 | [Parameter()] 80 | [datetime]$ValidSince, 81 | 82 | [Parameter()] 83 | [datetime]$ValidUntil, 84 | 85 | [Parameter()] 86 | [Int]$MaxVisits, 87 | 88 | [Parameter()] 89 | [String]$Title, 90 | 91 | [Parameter()] 92 | [String]$Domain, 93 | 94 | [Parameter()] 95 | [Int]$ShortCodeLength, 96 | 97 | [Parameter()] 98 | [Bool]$FindIfExists, 99 | 100 | [Parameter()] 101 | [Bool]$ValidateUrl, 102 | 103 | [Parameter()] 104 | [Bool]$ForwardQuery, 105 | 106 | [Parameter()] 107 | [Bool]$Crawlable, 108 | 109 | [Parameter()] 110 | [String]$ShlinkServer, 111 | 112 | [Parameter()] 113 | [SecureString]$ShlinkApiKey 114 | ) 115 | 116 | try { 117 | GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey 118 | } 119 | catch { 120 | Write-Error -ErrorRecord $_ -ErrorAction "Stop" 121 | } 122 | 123 | $Params = @{ 124 | Endpoint = "short-urls" 125 | Method = "POST" 126 | Body = @{ 127 | longUrl = $LongUrl 128 | } 129 | ErrorAction = "Stop" 130 | } 131 | 132 | $deviceLongUrls = @{} 133 | 134 | switch ($PSBoundParameters.Keys) { 135 | "AndroidLongUrl" { 136 | $deviceLongUrls["android"] = $AndroidLongUrl 137 | $Params["Body"]["deviceLongUrls"] = $deviceLongUrls 138 | } 139 | "IOSLongUrl" { 140 | $deviceLongUrls["ios"] = $IOSLongUrl 141 | $Params["Body"]["deviceLongUrls"] = $deviceLongUrls 142 | } 143 | "DesktopLongUrl" { 144 | $deviceLongUrls["desktop"] = $DesktopLongUrl 145 | $Params["Body"]["deviceLongUrls"] = $deviceLongUrls 146 | } 147 | "CustomSlug" { 148 | $Params["Body"]["customSlug"] = $CustomSlug 149 | } 150 | "Tags" { 151 | $Params["Body"]["tags"] = @($Tags) 152 | } 153 | "ValidSince" { 154 | $Params["Body"]["validSince"] = (Get-Date $ValidSince -Format "yyyy-MM-ddTHH:mm:sszzzz") 155 | } 156 | "ValidUntil" { 157 | $Params["Body"]["validUntil"] = (Get-Date $ValidUntil -Format "yyyy-MM-ddTHH:mm:sszzzz") 158 | } 159 | "MaxVisits" { 160 | $Params["Body"]["maxVisits"] = $MaxVisits 161 | } 162 | "Domain" { 163 | $Params["Body"]["domain"] = $Domain 164 | } 165 | "Title" { 166 | $Params["Body"]["title"] = $Title 167 | } 168 | "ShortCodeLength" { 169 | $Params["Body"]["shortCodeLength"] = $ShortCodeLength 170 | } 171 | "FindIfExists" { 172 | $Params["Body"]["findIfExists"] = $FindIfExists 173 | } 174 | "ValidateUrl" { 175 | Write-Warning 'validateUrl is deprecated since Shlink 3.5.0' 176 | $Params["Body"]["validateUrl"] = $ValidateUrl 177 | } 178 | "ForwardQuery" { 179 | $Params["Body"]["forwardQuery"] = $ForwardQuery 180 | } 181 | "Crawlable" { 182 | $Params["Body"]["crawlable"] = $Crawlable 183 | } 184 | } 185 | 186 | try { 187 | InvokeShlinkRestMethod @Params 188 | } 189 | catch { 190 | Write-Error -ErrorRecord $_ 191 | } 192 | } -------------------------------------------------------------------------------- /docs/Save-ShlinkUrlQrCode.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Save-ShlinkUrlQrCode 9 | 10 | ## SYNOPSIS 11 | Save a QR code to disk for a short code. 12 | 13 | ## SYNTAX 14 | 15 | ### InputObject 16 | ``` 17 | Save-ShlinkUrlQrCode -InputObject [-Path ] [-Size ] [-Format ] 18 | [-Margin ] [-ErrorCorrection ] [-RoundBlockSize ] [-PassThru] [] 19 | ``` 20 | 21 | ### SpecifyProperties 22 | ``` 23 | Save-ShlinkUrlQrCode -ShortCode [-Domain ] [-Path ] [-Size ] [-Format ] 24 | [-Margin ] [-ErrorCorrection ] [-RoundBlockSize ] [-ShlinkServer ] 25 | [-ShlinkApiKey ] [-PassThru] [] 26 | ``` 27 | 28 | ## DESCRIPTION 29 | Save a QR code to disk for a short code. 30 | The default size of images is 300x300 and the default file type is png. 31 | The default folder for files to be saved to is $HOME\Downloads. 32 | The naming convention for the saved files is as follows: ShlinkQRCode_\_\_\.\ 33 | 34 | ## EXAMPLES 35 | 36 | ### EXAMPLE 1 37 | ``` 38 | Save-ShlinkUrlQrCode -ShortCode "profile" -Domain "example.com" -Size 1000 -Format svg -Path "C:\temp" 39 | ``` 40 | 41 | Saves a QR code to disk in C:\temp named "ShlinkQRCode_profile_example-com_1000.svg". 42 | It will be saved as 1000x1000 pixels and of SVG type. 43 | 44 | ### EXAMPLE 2 45 | ``` 46 | Get-ShlinkUrl -SearchTerm "someword" | Save-ShlinkUrlQrCode -Path "C:\temp" 47 | ``` 48 | 49 | Saves QR codes for all short URLs returned by the Get-ShlinkUrl call. 50 | All files will be saved as the default values for size (300x300) and type (png). 51 | All files will be saved in "C:\temp" using the normal naming convention for file names, as detailed in the description. 52 | 53 | ## PARAMETERS 54 | 55 | ### -InputObject 56 | {{ Fill InputObject Description }} 57 | 58 | ```yaml 59 | Type: PSObject[] 60 | Parameter Sets: InputObject 61 | Aliases: 62 | 63 | Required: True 64 | Position: Named 65 | Default value: None 66 | Accept pipeline input: True (ByValue) 67 | Accept wildcard characters: False 68 | ``` 69 | 70 | ### -ShortCode 71 | The name of the short code you wish to create a QR code with. 72 | 73 | ```yaml 74 | Type: String 75 | Parameter Sets: SpecifyProperties 76 | Aliases: 77 | 78 | Required: True 79 | Position: Named 80 | Default value: None 81 | Accept pipeline input: False 82 | Accept wildcard characters: False 83 | ``` 84 | 85 | ### -Domain 86 | The domain which is associated with the short code you wish to create a QR code with. 87 | This is useful if your Shlink instance is responding/creating short URLs for multiple domains. 88 | 89 | ```yaml 90 | Type: String 91 | Parameter Sets: SpecifyProperties 92 | Aliases: 93 | 94 | Required: False 95 | Position: Named 96 | Default value: None 97 | Accept pipeline input: False 98 | Accept wildcard characters: False 99 | ``` 100 | 101 | ### -Path 102 | The path where you would like the save the QR code. 103 | If omitted, the default is the Downloads directory of the runner user's $Home environment variable. 104 | If the directory doesn't exist, it will be created. 105 | 106 | ```yaml 107 | Type: String 108 | Parameter Sets: (All) 109 | Aliases: 110 | 111 | Required: False 112 | Position: Named 113 | Default value: "{0}\Downloads" -f $home 114 | Accept pipeline input: False 115 | Accept wildcard characters: False 116 | ``` 117 | 118 | ### -Size 119 | Specify the pixel width you want for your generated shortcodes. 120 | The same value will be applied to the height. 121 | If omitted, the default configuration of your Shlink server is used. 122 | 123 | ```yaml 124 | Type: Int32 125 | Parameter Sets: (All) 126 | Aliases: 127 | 128 | Required: False 129 | Position: Named 130 | Default value: 0 131 | Accept pipeline input: False 132 | Accept wildcard characters: False 133 | ``` 134 | 135 | ### -Format 136 | Specify whether you would like your QR codes to save as .png or .svg files. 137 | If omitted, the default configuration of your Shlink server is used. 138 | 139 | ```yaml 140 | Type: String 141 | Parameter Sets: (All) 142 | Aliases: 143 | 144 | Required: False 145 | Position: Named 146 | Default value: None 147 | Accept pipeline input: False 148 | Accept wildcard characters: False 149 | ``` 150 | 151 | ### -Margin 152 | Specify the margin/whitespace around the QR code image in pixels. 153 | If omitted, the default configuration of your Shlink server is used. 154 | 155 | ```yaml 156 | Type: Int32 157 | Parameter Sets: (All) 158 | Aliases: 159 | 160 | Required: False 161 | Position: Named 162 | Default value: 0 163 | Accept pipeline input: False 164 | Accept wildcard characters: False 165 | ``` 166 | 167 | ### -ErrorCorrection 168 | Specify the level of error correction you would like in the QR code. 169 | Choose from L for low, M for medium, Q for quartile, or H for high. 170 | If omitted, the default configuration of your Shlink server is used. 171 | 172 | ```yaml 173 | Type: String 174 | Parameter Sets: (All) 175 | Aliases: 176 | 177 | Required: False 178 | Position: Named 179 | Default value: None 180 | Accept pipeline input: False 181 | Accept wildcard characters: False 182 | ``` 183 | 184 | ### -RoundBlockSize 185 | Allows to disable block size rounding, which might reduce the readability of the QR code, but ensures no extra margin is added. 186 | Possible values are true or false boolean types. 187 | If omitted, the default configuration of your Shlink server is used. 188 | 189 | ```yaml 190 | Type: Boolean 191 | Parameter Sets: (All) 192 | Aliases: 193 | 194 | Required: False 195 | Position: Named 196 | Default value: False 197 | Accept pipeline input: False 198 | Accept wildcard characters: False 199 | ``` 200 | 201 | ### -ShlinkServer 202 | The URL of your Shlink server (including schema). 203 | For example "https://example.com". 204 | It is not required to use this parameter for every use of this function. 205 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 206 | 207 | ```yaml 208 | Type: String 209 | Parameter Sets: SpecifyProperties 210 | Aliases: 211 | 212 | Required: False 213 | Position: Named 214 | Default value: None 215 | Accept pipeline input: False 216 | Accept wildcard characters: False 217 | ``` 218 | 219 | ### -ShlinkApiKey 220 | A SecureString object of your Shlink server's API key. 221 | It is not required to use this parameter for every use of this function. 222 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 223 | 224 | ```yaml 225 | Type: SecureString 226 | Parameter Sets: SpecifyProperties 227 | Aliases: 228 | 229 | Required: False 230 | Position: Named 231 | Default value: None 232 | Accept pipeline input: False 233 | Accept wildcard characters: False 234 | ``` 235 | 236 | ### -PassThru 237 | Returns a System.IO.FileSystemInfo object of each QR image file it creates 238 | 239 | ```yaml 240 | Type: SwitchParameter 241 | Parameter Sets: (All) 242 | Aliases: 243 | 244 | Required: False 245 | Position: Named 246 | Default value: False 247 | Accept pipeline input: False 248 | Accept wildcard characters: False 249 | ``` 250 | 251 | ### CommonParameters 252 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 253 | 254 | ## INPUTS 255 | 256 | ### System.Management.Automation.PSObject[] 257 | ### Expects PSObjects with PSTypeName of 'PSTypeName', typically from Get-ShlinkUrl. 258 | ## OUTPUTS 259 | 260 | ### System.IO.FileSystemInfo 261 | ## NOTES 262 | 263 | ## RELATED LINKS 264 | -------------------------------------------------------------------------------- /docs/Get-ShlinkUrl.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-ShlinkUrl 9 | 10 | ## SYNOPSIS 11 | Get details of all short codes, or just one. 12 | 13 | ## SYNTAX 14 | 15 | ### ListShortUrls (Default) 16 | ``` 17 | Get-ShlinkUrl [-SearchTerm ] [-Tags ] [-TagsMode ] [-OrderBy ] 18 | [-StartDate ] [-EndDate ] [-ExcludeMaxVisitsReached] [-ExcludePastValidUntil] 19 | [-ShlinkServer ] [-ShlinkApiKey ] [] 20 | ``` 21 | 22 | ### ParseShortCode 23 | ``` 24 | Get-ShlinkUrl -ShortCode [-Domain ] [-ShlinkServer ] [-ShlinkApiKey ] 25 | [] 26 | ``` 27 | 28 | ## DESCRIPTION 29 | Get details of all short codes, or just one. 30 | Various filtering options are available from the API to ambigiously search for short codes. 31 | 32 | ## EXAMPLES 33 | 34 | ### EXAMPLE 1 35 | ``` 36 | Get-ShlinkUrl 37 | ``` 38 | 39 | Returns all short codes with no filtering applied. 40 | 41 | ### EXAMPLE 2 42 | ``` 43 | Get-ShlinkUrl -ShortCode "profile" 44 | ``` 45 | 46 | Returns the short code "profile". 47 | 48 | ### EXAMPLE 3 49 | ``` 50 | Get-ShlinkUrl -ShortCode "profile" -Domain "example.com" 51 | ``` 52 | 53 | Returns the short code "profile" using the domain "example.com". 54 | This is useful if your Shlink instance is responding/creating short URLs for multiple domains. 55 | 56 | ### EXAMPLE 4 57 | ``` 58 | Get-ShlinkUrl -Tags "oldwebsite", "evenolderwebsite" -TagsMode "any" -OrderBy "dateCreated-ASC" 59 | ``` 60 | 61 | Returns short codes which are associated with the tags "oldwebsite" or "evenolderwebsite". 62 | Ordered by the dateCreated property in ascending order. 63 | 64 | ### EXAMPLE 5 65 | ``` 66 | Get-ShlinkUrl -StartDate (Get-Date "2020-10-25 11:00:00") 67 | ``` 68 | 69 | Returns short codes which have a start date of 25th October 2020 11:00:00 AM or newer. 70 | If a start date was not configured for the short code(s), this filters on the dateCreated property. 71 | 72 | ### EXAMPLE 6 73 | ``` 74 | Get-ShlinkUrl -SearchTerm "microsoft" 75 | ``` 76 | 77 | Returns the short codes which match the search term "microsoft". 78 | 79 | ## PARAMETERS 80 | 81 | ### -ShortCode 82 | The name of the short code you wish to search for. 83 | For example, if the short URL is "https://example.com/new-url" then the short code is "new-url". 84 | 85 | ```yaml 86 | Type: String 87 | Parameter Sets: ParseShortCode 88 | Aliases: 89 | 90 | Required: True 91 | Position: Named 92 | Default value: None 93 | Accept pipeline input: False 94 | Accept wildcard characters: False 95 | ``` 96 | 97 | ### -Domain 98 | The domain (excluding schema) associated with the short code you wish to search for. 99 | For example, "example.com" is an acceptable value. 100 | This is useful if your Shlink instance is responding/creating short URLs for multiple domains. 101 | 102 | ```yaml 103 | Type: String 104 | Parameter Sets: ParseShortCode 105 | Aliases: 106 | 107 | Required: False 108 | Position: Named 109 | Default value: None 110 | Accept pipeline input: False 111 | Accept wildcard characters: False 112 | ``` 113 | 114 | ### -SearchTerm 115 | The search term to search for a short code with. 116 | 117 | ```yaml 118 | Type: String 119 | Parameter Sets: ListShortUrls 120 | Aliases: 121 | 122 | Required: False 123 | Position: Named 124 | Default value: None 125 | Accept pipeline input: False 126 | Accept wildcard characters: False 127 | ``` 128 | 129 | ### -Tags 130 | One or more tags can be passed to find short codes using said tag(s). 131 | 132 | ```yaml 133 | Type: String[] 134 | Parameter Sets: ListShortUrls 135 | Aliases: 136 | 137 | Required: False 138 | Position: Named 139 | Default value: None 140 | Accept pipeline input: False 141 | Accept wildcard characters: False 142 | ``` 143 | 144 | ### -TagsMode 145 | Tells how the filtering by tags should work, returning short URLs containing "any" of the tags, or "all" the tags. 146 | It's ignored if no tags are provided, and defaults to "any" if not provided. 147 | 148 | ```yaml 149 | Type: String 150 | Parameter Sets: ListShortUrls 151 | Aliases: 152 | 153 | Required: False 154 | Position: Named 155 | Default value: None 156 | Accept pipeline input: False 157 | Accept wildcard characters: False 158 | ``` 159 | 160 | ### -OrderBy 161 | Order the results returned by "longUrl-ASC", "longUrl-DESC", "shortCode-ASC", "shortCode-DESC", "dateCreated-ASC", "dateCreated-DESC", "visits-ASC", "visits-DESC", "title-ASC", "title-DESC". 162 | 163 | ```yaml 164 | Type: String 165 | Parameter Sets: ListShortUrls 166 | Aliases: 167 | 168 | Required: False 169 | Position: Named 170 | Default value: None 171 | Accept pipeline input: False 172 | Accept wildcard characters: False 173 | ``` 174 | 175 | ### -StartDate 176 | A datetime object to search for short codes where its start date is equal or greater than this value. 177 | If a start date is not configured for the short code(s), this filters on the dateCreated property. 178 | 179 | ```yaml 180 | Type: DateTime 181 | Parameter Sets: ListShortUrls 182 | Aliases: 183 | 184 | Required: False 185 | Position: Named 186 | Default value: None 187 | Accept pipeline input: False 188 | Accept wildcard characters: False 189 | ``` 190 | 191 | ### -EndDate 192 | A datetime object to search for short codes where its end date is equal or less than this value. 193 | 194 | ```yaml 195 | Type: DateTime 196 | Parameter Sets: ListShortUrls 197 | Aliases: 198 | 199 | Required: False 200 | Position: Named 201 | Default value: None 202 | Accept pipeline input: False 203 | Accept wildcard characters: False 204 | ``` 205 | 206 | ### -ExcludeMaxVisitsReached 207 | Short URLs which already reached their maximum amount of visits will be excluded. 208 | 209 | ```yaml 210 | Type: SwitchParameter 211 | Parameter Sets: ListShortUrls 212 | Aliases: 213 | 214 | Required: False 215 | Position: Named 216 | Default value: False 217 | Accept pipeline input: False 218 | Accept wildcard characters: False 219 | ``` 220 | 221 | ### -ExcludePastValidUntil 222 | Short URLs which validUntil date is on the past will be excluded. 223 | 224 | ```yaml 225 | Type: SwitchParameter 226 | Parameter Sets: ListShortUrls 227 | Aliases: 228 | 229 | Required: False 230 | Position: Named 231 | Default value: False 232 | Accept pipeline input: False 233 | Accept wildcard characters: False 234 | ``` 235 | 236 | ### -ShlinkServer 237 | The URL of your Shlink server (including schema). 238 | For example "https://example.com". 239 | It is not required to use this parameter for every use of this function. 240 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 241 | 242 | ```yaml 243 | Type: String 244 | Parameter Sets: (All) 245 | Aliases: 246 | 247 | Required: False 248 | Position: Named 249 | Default value: None 250 | Accept pipeline input: False 251 | Accept wildcard characters: False 252 | ``` 253 | 254 | ### -ShlinkApiKey 255 | A SecureString object of your Shlink server's API key. 256 | It is not required to use this parameter for every use of this function. 257 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 258 | 259 | ```yaml 260 | Type: SecureString 261 | Parameter Sets: (All) 262 | Aliases: 263 | 264 | Required: False 265 | Position: Named 266 | Default value: None 267 | Accept pipeline input: False 268 | Accept wildcard characters: False 269 | ``` 270 | 271 | ### CommonParameters 272 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 273 | 274 | ## INPUTS 275 | 276 | ### This function does not accept pipeline input. 277 | ## OUTPUTS 278 | 279 | ### System.Management.Automation.PSObject 280 | ### Objects have a PSTypeName of 'PSShlink'. 281 | ## NOTES 282 | 283 | ## RELATED LINKS 284 | -------------------------------------------------------------------------------- /src/Public/Set-ShlinkUrl.ps1: -------------------------------------------------------------------------------- 1 | function Set-ShlinkUrl { 2 | <# 3 | .SYNOPSIS 4 | Update an existing short code on the Shlink server. 5 | .DESCRIPTION 6 | Update an existing short code on the Shlink server. 7 | .PARAMETER ShortCode 8 | The name of the short code you wish to update. 9 | .PARAMETER LongUrl 10 | The new long URL to associate with the existing short code. 11 | .PARAMETER AndroidLongUrl 12 | The long URL to redirect to when the short URL is visited from a device running Android. 13 | .PARAMETER IOSLongUrl 14 | The long URL to redirect to when the short URL is visited from a device running iOS. 15 | .PARAMETER DesktopLongUrl 16 | The long URL to redirect to when the short URL is visited from a desktop browser. 17 | .PARAMETER Tags 18 | The name of one or more tags to associate with the existing short code. 19 | Due to the architecture of Shlink's REST API, this parameter can only be used in its own parameter set. 20 | .PARAMETER ValidSince 21 | Define a new "valid since" date with the existing short code. 22 | .PARAMETER ValidUntil 23 | Define a new "valid until" date with the existing short code. 24 | .PARAMETER MaxVisits 25 | Set a new maximum visits threshold for the existing short code. 26 | .PARAMETER Domain 27 | The domain which is associated with the short code you wish to update. 28 | This is useful if your Shlink instance is responding/creating short URLs for multiple domains. 29 | .PARAMETER Title 30 | Define a title with the new short code. 31 | .PARAMETER ValidateUrl 32 | Control long URL validation while creating the short code. 33 | .PARAMETER ForwardQuery 34 | Forwards UTM query parameters to the long URL if any were passed to the short URL. 35 | .PARAMETER Crawlable 36 | Set short URLs as crawlable, making them be listed in the robots.txt as Allowed. 37 | .PARAMETER ShlinkServer 38 | The URL of your Shlink server (including schema). For example "https://example.com". 39 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 40 | .PARAMETER ShlinkApiKey 41 | A SecureString object of your Shlink server's API key. 42 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 43 | .EXAMPLE 44 | PS C:\> Set-ShlinkUrl -ShortCode "profile" -LongUrl "https://github.com/codaamok" -ValidSince (Get-Date "2020-11-01") -ValidUntil (Get-Date "2020-11-30") -MaxVisits 99 45 | 46 | Update the existing short code "profile", associated with the default domain of the Shlink server, to point to URL "https://github.com/codaamok". The link will only be valid for November 2020. The link will only work for 99 visits. 47 | .EXAMPLE 48 | PS C:\> Set-ShlinkUrl -ShortCode "profile" -Tags "powershell","pwsh" 49 | 50 | Update the existing short code "profile" to have the tags "powershell" and "pwsh" associated with it. 51 | .EXAMPLE 52 | PS C:\> Get-ShlinkUrl -SearchTerm "preview" | Set-ShlinkUrl -Tags "preview" 53 | 54 | Updates all existing short codes which match the search term "preview" to have the tag "preview". 55 | .INPUTS 56 | System.String[] 57 | 58 | Used for the -ShortCode parameter. 59 | .OUTPUTS 60 | System.Management.Automation.PSObject 61 | #> 62 | [CmdletBinding()] 63 | param ( 64 | [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] 65 | [String[]]$ShortCode, 66 | 67 | [Parameter()] 68 | [String]$LongUrl, 69 | 70 | [Parameter()] 71 | [String]$AndroidLongUrl, 72 | 73 | [Parameter()] 74 | [String]$IOSLongUrl, 75 | 76 | [Parameter()] 77 | [String]$DesktopLongUrl, 78 | 79 | [Parameter()] 80 | [String[]]$Tags, 81 | 82 | [Parameter()] 83 | [datetime]$ValidSince, 84 | 85 | [Parameter()] 86 | [datetime]$ValidUntil, 87 | 88 | [Parameter()] 89 | [Int]$MaxVisits, 90 | 91 | [Parameter()] 92 | [String]$Title, 93 | 94 | [Parameter(ValueFromPipelineByPropertyName)] 95 | [String]$Domain, 96 | 97 | [Parameter()] 98 | [Bool]$ValidateUrl, 99 | 100 | [Parameter()] 101 | [Bool]$ForwardQuery, 102 | 103 | [Parameter()] 104 | [Bool]$Crawlable, 105 | 106 | [Parameter()] 107 | [String]$ShlinkServer, 108 | 109 | [Parameter()] 110 | [SecureString]$ShlinkApiKey 111 | ) 112 | begin { 113 | try { 114 | GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey 115 | } 116 | catch { 117 | Write-Error -ErrorRecord $_ -ErrorAction "Stop" 118 | } 119 | } 120 | process { 121 | $QueryString = [System.Web.HttpUtility]::ParseQueryString('') 122 | 123 | $Params = @{ 124 | Endpoint = "short-urls" 125 | Method = "PATCH" 126 | Body = @{} 127 | } 128 | 129 | foreach ($Code in $ShortCode) { 130 | $Params["Path"] = $Code 131 | 132 | $deviceLongUrls = @{} 133 | 134 | switch($PSBoundParameters.Keys) { 135 | "AndroidLongUrl" { 136 | $deviceLongUrls["android"] = $AndroidLongUrl 137 | $Params["Body"]["deviceLongUrls"] = $deviceLongUrls 138 | } 139 | "IOSLongUrl" { 140 | $deviceLongUrls["ios"] = $IOSLongUrl 141 | $Params["Body"]["deviceLongUrls"] = $deviceLongUrls 142 | } 143 | "DesktopLongUrl" { 144 | $deviceLongUrls["desktop"] = $DesktopLongUrl 145 | $Params["Body"]["deviceLongUrls"] = $deviceLongUrls 146 | } 147 | "LongUrl" { 148 | $Params["Body"]["longUrl"] = $LongUrl 149 | } 150 | "Tags" { 151 | $Params["Body"]["tags"] = @($Tags) 152 | } 153 | "ValidSince" { 154 | $Params["Body"]["validSince"] = Get-Date $ValidSince -Format "yyyy-MM-ddTHH:mm:sszzzz" 155 | } 156 | "ValidUntil" { 157 | $Params["Body"]["validUntil"] = Get-Date $ValidUntil -Format "yyyy-MM-ddTHH:mm:sszzzz" 158 | } 159 | "MaxVisits" { 160 | $Params["Body"]["maxVisits"] = $MaxVisits 161 | } 162 | "Title" { 163 | $Params["Body"]["title"] = $Title 164 | } 165 | "Domain" { 166 | # An additional null check here, and not as a validate parameter attribute, because I wanted it to be simple 167 | # to pipe to Set-ShlinkUrl where some objects have a populated, or null, domain property. 168 | # The domain property is blank for short codes if they were created to use the Shlink instance's default domain. 169 | # They are also most commonly blank on Shlink instances where there are no additional domains responding / listening. 170 | if (-not [String]::IsNullOrWhiteSpace($Domain)) { 171 | $QueryString.Add("domain", $Domain) 172 | } 173 | } 174 | "ValidateUrl" { 175 | Write-Warning 'validateUrl is deprecated since Shlink 3.5.0' 176 | $Params["Body"]["validateUrl"] = $ValidateUrl 177 | } 178 | "ForwardQuery" { 179 | $Params["Body"]["forwardQuery"] = $ForwardQuery 180 | } 181 | "Crawlable" { 182 | $Params["Body"]["crawlable"] = $Crawlable 183 | } 184 | } 185 | 186 | $Params["Query"] = $QueryString 187 | 188 | try { 189 | InvokeShlinkRestMethod @Params 190 | } 191 | catch { 192 | Write-Error -ErrorRecord $_ 193 | } 194 | } 195 | } 196 | end { 197 | } 198 | } -------------------------------------------------------------------------------- /docs/Set-ShlinkUrl.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Set-ShlinkUrl 9 | 10 | ## SYNOPSIS 11 | Update an existing short code on the Shlink server. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Set-ShlinkUrl [-ShortCode] [[-LongUrl] ] [[-AndroidLongUrl] ] 17 | [[-IOSLongUrl] ] [[-DesktopLongUrl] ] [[-Tags] ] [[-ValidSince] ] 18 | [[-ValidUntil] ] [[-MaxVisits] ] [[-Title] ] [[-Domain] ] 19 | [[-ValidateUrl] ] [[-ForwardQuery] ] [[-Crawlable] ] [[-ShlinkServer] ] 20 | [[-ShlinkApiKey] ] [] 21 | ``` 22 | 23 | ## DESCRIPTION 24 | Update an existing short code on the Shlink server. 25 | 26 | ## EXAMPLES 27 | 28 | ### EXAMPLE 1 29 | ``` 30 | Set-ShlinkUrl -ShortCode "profile" -LongUrl "https://github.com/codaamok" -ValidSince (Get-Date "2020-11-01") -ValidUntil (Get-Date "2020-11-30") -MaxVisits 99 31 | ``` 32 | 33 | Update the existing short code "profile", associated with the default domain of the Shlink server, to point to URL "https://github.com/codaamok". 34 | The link will only be valid for November 2020. 35 | The link will only work for 99 visits. 36 | 37 | ### EXAMPLE 2 38 | ``` 39 | Set-ShlinkUrl -ShortCode "profile" -Tags "powershell","pwsh" 40 | ``` 41 | 42 | Update the existing short code "profile" to have the tags "powershell" and "pwsh" associated with it. 43 | 44 | ### EXAMPLE 3 45 | ``` 46 | Get-ShlinkUrl -SearchTerm "preview" | Set-ShlinkUrl -Tags "preview" 47 | ``` 48 | 49 | Updates all existing short codes which match the search term "preview" to have the tag "preview". 50 | 51 | ## PARAMETERS 52 | 53 | ### -ShortCode 54 | The name of the short code you wish to update. 55 | 56 | ```yaml 57 | Type: String[] 58 | Parameter Sets: (All) 59 | Aliases: 60 | 61 | Required: True 62 | Position: 1 63 | Default value: None 64 | Accept pipeline input: True (ByPropertyName, ByValue) 65 | Accept wildcard characters: False 66 | ``` 67 | 68 | ### -LongUrl 69 | The new long URL to associate with the existing short code. 70 | 71 | ```yaml 72 | Type: String 73 | Parameter Sets: (All) 74 | Aliases: 75 | 76 | Required: False 77 | Position: 2 78 | Default value: None 79 | Accept pipeline input: False 80 | Accept wildcard characters: False 81 | ``` 82 | 83 | ### -AndroidLongUrl 84 | The long URL to redirect to when the short URL is visited from a device running Android. 85 | 86 | ```yaml 87 | Type: String 88 | Parameter Sets: (All) 89 | Aliases: 90 | 91 | Required: False 92 | Position: 3 93 | Default value: None 94 | Accept pipeline input: False 95 | Accept wildcard characters: False 96 | ``` 97 | 98 | ### -IOSLongUrl 99 | The long URL to redirect to when the short URL is visited from a device running iOS. 100 | 101 | ```yaml 102 | Type: String 103 | Parameter Sets: (All) 104 | Aliases: 105 | 106 | Required: False 107 | Position: 4 108 | Default value: None 109 | Accept pipeline input: False 110 | Accept wildcard characters: False 111 | ``` 112 | 113 | ### -DesktopLongUrl 114 | The long URL to redirect to when the short URL is visited from a desktop browser. 115 | 116 | ```yaml 117 | Type: String 118 | Parameter Sets: (All) 119 | Aliases: 120 | 121 | Required: False 122 | Position: 5 123 | Default value: None 124 | Accept pipeline input: False 125 | Accept wildcard characters: False 126 | ``` 127 | 128 | ### -Tags 129 | The name of one or more tags to associate with the existing short code. 130 | Due to the architecture of Shlink's REST API, this parameter can only be used in its own parameter set. 131 | 132 | ```yaml 133 | Type: String[] 134 | Parameter Sets: (All) 135 | Aliases: 136 | 137 | Required: False 138 | Position: 6 139 | Default value: None 140 | Accept pipeline input: False 141 | Accept wildcard characters: False 142 | ``` 143 | 144 | ### -ValidSince 145 | Define a new "valid since" date with the existing short code. 146 | 147 | ```yaml 148 | Type: DateTime 149 | Parameter Sets: (All) 150 | Aliases: 151 | 152 | Required: False 153 | Position: 7 154 | Default value: None 155 | Accept pipeline input: False 156 | Accept wildcard characters: False 157 | ``` 158 | 159 | ### -ValidUntil 160 | Define a new "valid until" date with the existing short code. 161 | 162 | ```yaml 163 | Type: DateTime 164 | Parameter Sets: (All) 165 | Aliases: 166 | 167 | Required: False 168 | Position: 8 169 | Default value: None 170 | Accept pipeline input: False 171 | Accept wildcard characters: False 172 | ``` 173 | 174 | ### -MaxVisits 175 | Set a new maximum visits threshold for the existing short code. 176 | 177 | ```yaml 178 | Type: Int32 179 | Parameter Sets: (All) 180 | Aliases: 181 | 182 | Required: False 183 | Position: 9 184 | Default value: 0 185 | Accept pipeline input: False 186 | Accept wildcard characters: False 187 | ``` 188 | 189 | ### -Title 190 | Define a title with the new short code. 191 | 192 | ```yaml 193 | Type: String 194 | Parameter Sets: (All) 195 | Aliases: 196 | 197 | Required: False 198 | Position: 10 199 | Default value: None 200 | Accept pipeline input: False 201 | Accept wildcard characters: False 202 | ``` 203 | 204 | ### -Domain 205 | The domain which is associated with the short code you wish to update. 206 | This is useful if your Shlink instance is responding/creating short URLs for multiple domains. 207 | 208 | ```yaml 209 | Type: String 210 | Parameter Sets: (All) 211 | Aliases: 212 | 213 | Required: False 214 | Position: 11 215 | Default value: None 216 | Accept pipeline input: True (ByPropertyName) 217 | Accept wildcard characters: False 218 | ``` 219 | 220 | ### -ValidateUrl 221 | Control long URL validation while creating the short code. 222 | 223 | ```yaml 224 | Type: Boolean 225 | Parameter Sets: (All) 226 | Aliases: 227 | 228 | Required: False 229 | Position: 12 230 | Default value: False 231 | Accept pipeline input: False 232 | Accept wildcard characters: False 233 | ``` 234 | 235 | ### -ForwardQuery 236 | Forwards UTM query parameters to the long URL if any were passed to the short URL. 237 | 238 | ```yaml 239 | Type: Boolean 240 | Parameter Sets: (All) 241 | Aliases: 242 | 243 | Required: False 244 | Position: 13 245 | Default value: False 246 | Accept pipeline input: False 247 | Accept wildcard characters: False 248 | ``` 249 | 250 | ### -Crawlable 251 | Set short URLs as crawlable, making them be listed in the robots.txt as Allowed. 252 | 253 | ```yaml 254 | Type: Boolean 255 | Parameter Sets: (All) 256 | Aliases: 257 | 258 | Required: False 259 | Position: 14 260 | Default value: False 261 | Accept pipeline input: False 262 | Accept wildcard characters: False 263 | ``` 264 | 265 | ### -ShlinkServer 266 | The URL of your Shlink server (including schema). 267 | For example "https://example.com". 268 | It is not required to use this parameter for every use of this function. 269 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 270 | 271 | ```yaml 272 | Type: String 273 | Parameter Sets: (All) 274 | Aliases: 275 | 276 | Required: False 277 | Position: 15 278 | Default value: None 279 | Accept pipeline input: False 280 | Accept wildcard characters: False 281 | ``` 282 | 283 | ### -ShlinkApiKey 284 | A SecureString object of your Shlink server's API key. 285 | It is not required to use this parameter for every use of this function. 286 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 287 | 288 | ```yaml 289 | Type: SecureString 290 | Parameter Sets: (All) 291 | Aliases: 292 | 293 | Required: False 294 | Position: 16 295 | Default value: None 296 | Accept pipeline input: False 297 | Accept wildcard characters: False 298 | ``` 299 | 300 | ### CommonParameters 301 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 302 | 303 | ## INPUTS 304 | 305 | ### System.String[] 306 | ### Used for the -ShortCode parameter. 307 | ## OUTPUTS 308 | 309 | ### System.Management.Automation.PSObject 310 | ## NOTES 311 | 312 | ## RELATED LINKS 313 | -------------------------------------------------------------------------------- /src/Public/Get-ShlinkUrl.ps1: -------------------------------------------------------------------------------- 1 | function Get-ShlinkUrl { 2 | <# 3 | .SYNOPSIS 4 | Get details of all short codes, or just one. 5 | .DESCRIPTION 6 | Get details of all short codes, or just one. Various filtering options are available from the API to ambigiously search for short codes. 7 | .PARAMETER ShortCode 8 | The name of the short code you wish to search for. For example, if the short URL is "https://example.com/new-url" then the short code is "new-url". 9 | .PARAMETER Domain 10 | The domain (excluding schema) associated with the short code you wish to search for. For example, "example.com" is an acceptable value. 11 | This is useful if your Shlink instance is responding/creating short URLs for multiple domains. 12 | .PARAMETER SearchTerm 13 | The search term to search for a short code with. 14 | .PARAMETER Tags 15 | One or more tags can be passed to find short codes using said tag(s). 16 | .PARAMETER TagsMode 17 | Tells how the filtering by tags should work, returning short URLs containing "any" of the tags, or "all" the tags. It's ignored if no tags are provided, and defaults to "any" if not provided. 18 | .PARAMETER OrderBy 19 | Order the results returned by "longUrl-ASC", "longUrl-DESC", "shortCode-ASC", "shortCode-DESC", "dateCreated-ASC", "dateCreated-DESC", "visits-ASC", "visits-DESC", "title-ASC", "title-DESC". 20 | .PARAMETER StartDate 21 | A datetime object to search for short codes where its start date is equal or greater than this value. 22 | If a start date is not configured for the short code(s), this filters on the dateCreated property. 23 | .PARAMETER EndDate 24 | A datetime object to search for short codes where its end date is equal or less than this value. 25 | .PARAMETER ExcludeMaxVisitsReached 26 | Short URLs which already reached their maximum amount of visits will be excluded. 27 | .PARAMETER ExcludePastValidUntil 28 | Short URLs which validUntil date is on the past will be excluded. 29 | .PARAMETER ShlinkServer 30 | The URL of your Shlink server (including schema). For example "https://example.com". 31 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 32 | .PARAMETER ShlinkApiKey 33 | A SecureString object of your Shlink server's API key. 34 | It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 35 | .EXAMPLE 36 | PS C:\> Get-ShlinkUrl 37 | 38 | Returns all short codes with no filtering applied. 39 | .EXAMPLE 40 | PS C:\> Get-ShlinkUrl -ShortCode "profile" 41 | 42 | Returns the short code "profile". 43 | .EXAMPLE 44 | PS C:\> Get-ShlinkUrl -ShortCode "profile" -Domain "example.com" 45 | 46 | Returns the short code "profile" using the domain "example.com". This is useful if your Shlink instance is responding/creating short URLs for multiple domains. 47 | .EXAMPLE 48 | PS C:\> Get-ShlinkUrl -Tags "oldwebsite", "evenolderwebsite" -TagsMode "any" -OrderBy "dateCreated-ASC" 49 | 50 | Returns short codes which are associated with the tags "oldwebsite" or "evenolderwebsite". Ordered by the dateCreated property in ascending order. 51 | .EXAMPLE 52 | PS C:\> Get-ShlinkUrl -StartDate (Get-Date "2020-10-25 11:00:00") 53 | 54 | Returns short codes which have a start date of 25th October 2020 11:00:00 AM or newer. If a start date was not configured for the short code(s), this filters on the dateCreated property. 55 | .EXAMPLE 56 | PS C:\> Get-ShlinkUrl -SearchTerm "microsoft" 57 | 58 | Returns the short codes which match the search term "microsoft". 59 | .INPUTS 60 | This function does not accept pipeline input. 61 | .OUTPUTS 62 | System.Management.Automation.PSObject 63 | 64 | Objects have a PSTypeName of 'PSShlink'. 65 | #> 66 | [CmdletBinding(DefaultParameterSetName="ListShortUrls")] 67 | param ( 68 | [Parameter(Mandatory, ParameterSetName="ParseShortCode")] 69 | [String]$ShortCode, 70 | 71 | [Parameter(ParameterSetName="ParseShortCode")] 72 | [String]$Domain, 73 | 74 | [Parameter(ParameterSetName="ListShortUrls")] 75 | [String]$SearchTerm, 76 | 77 | [Parameter(ParameterSetName="ListShortUrls")] 78 | [String[]]$Tags, 79 | 80 | [Parameter(ParameterSetName="ListShortUrls")] 81 | [ValidateSet("any","all")] 82 | [String]$TagsMode, 83 | 84 | [Parameter(ParameterSetName="ListShortUrls")] 85 | [ValidateSet("longUrl-ASC", "longUrl-DESC", "shortCode-ASC", "shortCode-DESC", "dateCreated-ASC", "dateCreated-DESC", "visits-ASC", "visits-DESC", "title-ASC", "title-DESC", "nonBotVisits-ASC", "nonBotVisits-DESC")] 86 | [String]$OrderBy, 87 | 88 | [Parameter(ParameterSetName="ListShortUrls")] 89 | [datetime]$StartDate, 90 | 91 | [Parameter(ParameterSetName="ListShortUrls")] 92 | [datetime]$EndDate, 93 | 94 | [Parameter(ParameterSetName="ListShortUrls")] 95 | [Switch]$ExcludeMaxVisitsReached, 96 | 97 | [Parameter(ParameterSetName="ListShortUrls")] 98 | [Switch]$ExcludePastValidUntil, 99 | 100 | [Parameter()] 101 | [String]$ShlinkServer, 102 | 103 | [Parameter()] 104 | [SecureString]$ShlinkApiKey 105 | ) 106 | # Using begin / process / end blocks due to the way PowerShell processes all 107 | # begin blocks in the pipeline first before the process blocks. If user passed 108 | # -ShlinkServer and -ShlinkApiKey in this function and piped to something else, 109 | # e.g. Set-ShlinkUrl, and they omitted those parameters from the piped function, 110 | # they will be prompted for -ShlinkServer and -ShlinkApiKey. This is not my intended 111 | # user experience. Hence the decision to implement begin/process/end blocks here. 112 | begin { 113 | try { 114 | GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey 115 | } 116 | catch { 117 | Write-Error -ErrorRecord $_ -ErrorAction "Stop" 118 | } 119 | 120 | $QueryString = [System.Web.HttpUtility]::ParseQueryString('') 121 | } 122 | process { 123 | $Params = @{ 124 | Endpoint = "short-urls" 125 | PSTypeName = "PSShlink" 126 | ErrorACtion = "Stop" 127 | } 128 | 129 | switch ($PSCmdlet.ParameterSetName) { 130 | "ParseShortCode" { 131 | switch ($PSBoundParameters.Keys) { 132 | "ShortCode" { 133 | $Params["Path"] = $ShortCode 134 | } 135 | "Domain" { 136 | $QueryString.Add("domain", $Domain) 137 | } 138 | } 139 | } 140 | "ListShortUrls" { 141 | $Params["PropertyTree"] = "shortUrls", "data" 142 | 143 | switch ($PSBoundParameters.Keys) { 144 | "Tags" { 145 | foreach ($Tag in $Tags) { 146 | $QueryString.Add("tags[]", $Tag) 147 | } 148 | } 149 | "TagsMode" { 150 | $QueryString.Add("tagsMode", $TagsMode) 151 | } 152 | "SearchTerm" { 153 | $QueryString.Add("searchTerm", $SearchTerm) 154 | } 155 | "OrderBy" { 156 | $QueryString.Add("orderBy", $OrderBy) 157 | } 158 | "StartDate" { 159 | $QueryString.Add("startDate", (Get-Date $StartDate -Format "yyyy-MM-ddTHH:mm:sszzzz")) 160 | } 161 | "EndDate" { 162 | $QueryString.Add("endDate", (Get-Date $EndDate -Format "yyyy-MM-ddTHH:mm:sszzzz")) 163 | } 164 | "ExcludeMaxVisitsReached" { 165 | $QueryString.Add("excludeMaxVisitsReached", 'true') 166 | } 167 | "excludePastValidUntil" { 168 | $QueryString.Add("excludePastValidUntil", 'true') 169 | } 170 | } 171 | } 172 | } 173 | 174 | $Params["Query"] = $QueryString 175 | 176 | try { 177 | InvokeShlinkRestMethod @Params 178 | } 179 | catch { 180 | Write-Error -ErrorRecord $_ 181 | } 182 | } 183 | end { 184 | } 185 | } -------------------------------------------------------------------------------- /invoke.build.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Build script which leverages the InvokeBuild module. 4 | .DESCRIPTION 5 | Build script which leverages the InvokeBuild module. 6 | This build script is used in the build pipeline and local development for building this project. 7 | #> 8 | [CmdletBinding()] 9 | param ( 10 | [Parameter(Mandatory)] 11 | [ValidateNotNullOrEmpty()] 12 | [String]$ModuleName, 13 | 14 | [Parameter()] 15 | [ValidateNotNullOrEmpty()] 16 | [String]$Author, 17 | 18 | [Parameter()] 19 | [String]$Version, 20 | 21 | [Parameter()] 22 | [Bool]$NewRelease = $false, 23 | 24 | [Parameter()] 25 | [Bool]$UpdateDocs = $false 26 | ) 27 | 28 | # Synopsis: Initiate the build process 29 | task . ImportBuildModule, 30 | InitaliseBuildDirectory, 31 | CopyChangeLog, 32 | UpdateChangeLog, 33 | CreateRootModule, 34 | CreateProcessScript, 35 | UpdateModuleManifest, 36 | CreateArchive, 37 | UpdateDocs, 38 | UpdateProjectRepo 39 | 40 | # Synopsis: Install dependent build modules 41 | task InstallDependencies { 42 | $Modules = "PlatyPS","ChangelogManagement" 43 | if ($Script:ModuleName -ne "codaamok.build") { 44 | $Modules += "codaamok.build" 45 | } 46 | Install-Module -Name $Modules -Scope CurrentUser 47 | } 48 | 49 | # Synopsis: Set build platform specific environment variables 50 | task SetGitHubActionEnvironmentVariables { 51 | New-BuildEnvironmentVariable -Platform "GitHubActions" -Variable @{ 52 | "GH_USERNAME" = $Author 53 | "GH_PROJECTNAME" = $ModuleName 54 | } 55 | } 56 | 57 | # Synopsis: Publish module to the PowerShell Gallery 58 | task PublishModule { 59 | Publish-Module -Path $BuildRoot\build\$ModuleName -NuGetApiKey $env:PSGALLERY_API_KEY -ErrorAction "Stop" -Force 60 | } 61 | 62 | # Synopsis: Import the codaamok.build module 63 | task ImportBuildModule { 64 | if ($Script:ModuleName -eq "codaamok.build") { 65 | # This is to use module for building codaamok.build itself 66 | Import-Module .\src\codaamok.build.psd1 67 | } 68 | else { 69 | Import-Module "codaamok.build" 70 | } 71 | } 72 | 73 | # Synopsis: Create fresh build directories and initalise it with content from the project 74 | task InitaliseBuildDirectory { 75 | Invoke-BuildClean -Path @( 76 | "{0}\build" -f $BuildRoot 77 | "{0}\build\{1}" -f $BuildRoot, $Script:ModuleName 78 | "{0}\release" -f $BuildRoot 79 | ) 80 | 81 | if (Test-Path -Path $BuildRoot\src\* -Include "*format.ps1xml") { 82 | $Script:FormatFiles = Copy-Item -Path $BuildRoot\src\* -Destination $BuildRoot\build\$Script:ModuleName -Filter "*format.ps1xml" -PassThru 83 | } 84 | 85 | if (Test-Path -Path $BuildRoot\src\Files\*) { 86 | $Script:FileList = Copy-Item -Path $BuildRoot\src\Files\* -Destination $BuildRoot\build\$Script:ModuleName -Recurse -Force -PassThru 87 | } 88 | 89 | Copy-Item -Path $BuildRoot\LICENSE -Destination $BuildRoot\build\$Script:ModuleName\LICENSE 90 | Copy-Item -Path $BuildRoot\src\en-US -Destination $BuildRoot\build\$Script:ModuleName -Recurse 91 | $Script:ManifestFile = Copy-Item -Path $BuildRoot\src\$Script:ModuleName.psd1 -Destination $BuildRoot\build\$Script:ModuleName\$Script:ModuleName.psd1 -PassThru 92 | } 93 | 94 | # Synopsis: Get change log data, copy it to the build directory, and create releasenotes.txt 95 | task CopyChangeLog { 96 | Copy-Item -Path $BuildRoot\CHANGELOG.md -Destination $BuildRoot\build\$Script:ModuleName\CHANGELOG.md 97 | $Script:ChangeLogData = Get-ChangeLogData -Path $BuildRoot\CHANGELOG.md 98 | Export-UnreleasedNotes -Path $BuildRoot\release\releasenotes.txt -ChangeLogData $Script:ChangeLogData -NewRelease $Script:NewRelease 99 | } 100 | 101 | # Synopsis: Update CHANGELOG.md (if building a new release with -NewRelease) 102 | task UpdateChangeLog -If ($Script:NewRelease) { 103 | $LinkPattern = @{ 104 | FirstRelease = "https://github.com/{0}/{1}/tree/{{CUR}}" -f $Script:Author, $Script:ModuleName 105 | NormalRelease = "https://github.com/{0}/{1}/compare/{{PREV}}..{{CUR}}" -f $Script:Author, $Script:ModuleName 106 | Unreleased = "https://github.com/{0}/{1}/compare/{{CUR}}..HEAD" -f $Script:Author, $Script:ModuleName 107 | } 108 | 109 | Update-Changelog -Path $BuildRoot\build\$Script:ModuleName\CHANGELOG.md -ReleaseVersion $Script:Version -LinkMode Automatic -LinkPattern $LinkPattern 110 | } 111 | 112 | # Synopsis: Creates a single .psm1 file of all private and public functions of the to-be-built module 113 | task CreateRootModule { 114 | $Script:RootModule = "{0}\build\{1}\{1}.psm1" -f $BuildRoot, $Script:ModuleName 115 | $DevModulePath = "{0}\src" -f $BuildRoot 116 | Export-RootModule -DevModulePath $DevModulePath -RootModule $Script:RootModule 117 | } 118 | 119 | # Synopsis: Create a single Process.ps1 script file for all script files under ScriptsToProcess\* (if any) 120 | $Params = @{ 121 | Path = "{0}\src\ScriptsToProcess\*" -f $BuildRoot 122 | Include = "*.ps1" 123 | } 124 | 125 | task CreateProcessScript -If (Test-Path @Params) { 126 | $Path = "{0}\build\{1}\Process.ps1" -f $BuildRoot, $Script:ModuleName 127 | Export-ScriptsToProcess -File (Get-ChildItem @Params) -Path $Path 128 | $Script:ProcessScript = $true 129 | } 130 | 131 | # Synopsis: Update the module manifest in the build directory 132 | task UpdateModuleManifest { 133 | $UpdateModuleManifestSplat = @{ 134 | Path = $Script:ManifestFile 135 | RootModule = (Split-Path $Script:RootModule -Leaf) 136 | FunctionsToExport = Get-PublicFunctions -Path $BuildRoot\src\Public 137 | ReleaseNotes = (Get-Content $BuildRoot\release\releasenotes.txt) -replace '`' 138 | } 139 | 140 | # Build with pre-release data from the branch if the -Version parameter is not passed (for local development and testing) 141 | if ($Script:Version) { 142 | $UpdateModuleManifestSplat["ModuleVersion"] = $Script:Version 143 | } 144 | else { 145 | $GitVersion = (gitversion | ConvertFrom-Json) 146 | $UpdateModuleManifestSplat["ModuleVersion"] = $GitVersion.MajorMinorPatch 147 | $UpdateModuleManifestSplat["Prerelease"] = $GitVersion.NuGetPreReleaseTag 148 | } 149 | 150 | if ($Script:FormatFiles) { 151 | $UpdateModuleManifestSplat["FormatsToProcess"] = $Script:FormatFiles.Name 152 | } 153 | 154 | if ($Script:FileList) { 155 | # Use this instead of Updatet-ModuleManifest due to https://github.com/PowerShell/PowerShellGet/issues/196 156 | $Regex = '^# FileList = @\(\)$' 157 | $ReplaceStr = 'FileList = "{0}"' -f [String]::Join('", "', $Script:FileList.Name) 158 | (Get-Content -Path $Script:ManifestFile.FullName) -replace $Regex, $ReplaceStr | Set-Content -Path $Script:ManifestFile 159 | } 160 | 161 | if ($Script:ProcessScript) { 162 | # Use this instead of Updatet-ModuleManifest due to https://github.com/PowerShell/PowerShellGet/issues/196 163 | $Regex = '(#? ?ScriptsToProcess.+)' 164 | $ReplaceStr = 'ScriptsToProcess = "Process.ps1"' 165 | (Get-Content -Path $Script:ManifestFile.FullName) -replace $Regex, $ReplaceStr | Set-Content -Path $Script:ManifestFile 166 | } 167 | 168 | Update-ModuleManifest @UpdateModuleManifestSplat 169 | 170 | # Arguably a moot point as Update-MooduleManifest obviously does some testing to ensure a valid manifest is there first before updating it 171 | # However with the regex replace for ScriptsToProcess, I want to be sure 172 | $null = Test-ModuleManifest -Path $Script:ManifestFile 173 | } 174 | 175 | # Synopsis: Create archive of the module 176 | task CreateArchive { 177 | $ReleaseAsset = "{0}_{1}.zip" -f $Script:ModuleName, $Script:Version 178 | Compress-Archive -Path $BuildRoot\build\$Script:ModuleName\* -DestinationPath $BuildRoot\release\$ReleaseAsset -Force 179 | } 180 | 181 | # Synopsis: Update documentation (-NewRelease or -UpdateDocs switch parameter) 182 | task UpdateDocs -If ($NewRelease -Or $UpdateDocs) { 183 | Import-Module -Name $BuildRoot\build\$Script:ModuleName -Force 184 | New-MarkdownHelp -Module $Script:ModuleName -OutputFolder $BuildRoot\docs -Force 185 | } 186 | 187 | # Synopsis: Update the project's repository with files updated by the pipeline e.g. module manifest 188 | task UpdateProjectRepo -If ($NewRelease) { 189 | Copy-Item -Path $BuildRoot\build\$Script:ModuleName\CHANGELOG.md -Destination $BuildRoot\CHANGELOG.md 190 | 191 | $ManifestData = Import-PowerShellDataFile -Path $Script:ManifestFile 192 | 193 | # Instead of copying the manifest from the .\build directory, update it in place 194 | # This enables me to keep FunctionsToExport = '*' for development. Therefore instead only update the important bits e.g. version and release notes 195 | $UpdateModuleManifestSplat = @{ 196 | Path = "{0}\src\{1}.psd1" -f $BuildRoot, $Script:ModuleName 197 | ModuleVersion = $ManifestData.ModuleVersion 198 | ReleaseNotes = $ManifestData.PrivateData.PSData.ReleaseNotes 199 | } 200 | Update-ModuleManifest @UpdateModuleManifestSplat 201 | 202 | $null = Test-ModuleManifest -Path ("{0}\src\{1}.psd1" -f $BuildRoot, $Script:ModuleName) 203 | } 204 | -------------------------------------------------------------------------------- /docs/New-ShlinkUrl.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSShlink-help.xml 3 | Module Name: PSShlink 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # New-ShlinkUrl 9 | 10 | ## SYNOPSIS 11 | Creates a new Shlink short code on your Shlink server. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | New-ShlinkUrl [-LongUrl] [[-AndroidLongUrl] ] [[-IOSLongUrl] ] 17 | [[-DesktopLongUrl] ] [[-CustomSlug] ] [[-Tags] ] [[-ValidSince] ] 18 | [[-ValidUntil] ] [[-MaxVisits] ] [[-Title] ] [[-Domain] ] 19 | [[-ShortCodeLength] ] [[-FindIfExists] ] [[-ValidateUrl] ] 20 | [[-ForwardQuery] ] [[-Crawlable] ] [[-ShlinkServer] ] 21 | [[-ShlinkApiKey] ] [] 22 | ``` 23 | 24 | ## DESCRIPTION 25 | Creates a new Shlink short code on your Shlink server. 26 | 27 | ## EXAMPLES 28 | 29 | ### EXAMPLE 1 30 | ``` 31 | New-ShlinkUrl -LongUrl "https://google.com" 32 | ``` 33 | 34 | Will generate a new short code with the long URL of "https://google.com", using your Shlink server's default for creating new short codes, and return all the information about the new short code. 35 | 36 | ### EXAMPLE 2 37 | ``` 38 | New-ShlinkUrl -LongUrl "https://google.com" -CustomSlug "mygoogle" -Tags "search-engine" -ValidSince (Get-Date "2020-11-01") -ValidUntil (Get-Date "2020-11-30") -MaxVisits 99 -FindIfExists 39 | ``` 40 | 41 | Will generate a new short code with the long URL of "https://google.com" using the custom slug "search-engine". 42 | The default domain for the Shlink server will be used. 43 | The link will only be valid for November 2020. 44 | The link will only work for 99 visits. 45 | If a duplicate short code is found using the same long URL, another is not made and instead data about the existing short code is returned. 46 | 47 | ## PARAMETERS 48 | 49 | ### -LongUrl 50 | Define the long URL for the new short code. 51 | 52 | ```yaml 53 | Type: String 54 | Parameter Sets: (All) 55 | Aliases: 56 | 57 | Required: True 58 | Position: 1 59 | Default value: None 60 | Accept pipeline input: False 61 | Accept wildcard characters: False 62 | ``` 63 | 64 | ### -AndroidLongUrl 65 | The long URL to redirect to when the short URL is visited from a device running Android. 66 | 67 | ```yaml 68 | Type: String 69 | Parameter Sets: (All) 70 | Aliases: 71 | 72 | Required: False 73 | Position: 2 74 | Default value: None 75 | Accept pipeline input: False 76 | Accept wildcard characters: False 77 | ``` 78 | 79 | ### -IOSLongUrl 80 | The long URL to redirect to when the short URL is visited from a device running iOS. 81 | 82 | ```yaml 83 | Type: String 84 | Parameter Sets: (All) 85 | Aliases: 86 | 87 | Required: False 88 | Position: 3 89 | Default value: None 90 | Accept pipeline input: False 91 | Accept wildcard characters: False 92 | ``` 93 | 94 | ### -DesktopLongUrl 95 | The long URL to redirect to when the short URL is visited from a desktop browser. 96 | 97 | ```yaml 98 | Type: String 99 | Parameter Sets: (All) 100 | Aliases: 101 | 102 | Required: False 103 | Position: 4 104 | Default value: None 105 | Accept pipeline input: False 106 | Accept wildcard characters: False 107 | ``` 108 | 109 | ### -CustomSlug 110 | Define a custom slug for the new short code. 111 | 112 | ```yaml 113 | Type: String 114 | Parameter Sets: (All) 115 | Aliases: 116 | 117 | Required: False 118 | Position: 5 119 | Default value: None 120 | Accept pipeline input: False 121 | Accept wildcard characters: False 122 | ``` 123 | 124 | ### -Tags 125 | Associate tag(s) with the new short code. 126 | 127 | ```yaml 128 | Type: String[] 129 | Parameter Sets: (All) 130 | Aliases: 131 | 132 | Required: False 133 | Position: 6 134 | Default value: None 135 | Accept pipeline input: False 136 | Accept wildcard characters: False 137 | ``` 138 | 139 | ### -ValidSince 140 | Define a "valid since" date with the new short code. 141 | 142 | ```yaml 143 | Type: DateTime 144 | Parameter Sets: (All) 145 | Aliases: 146 | 147 | Required: False 148 | Position: 7 149 | Default value: None 150 | Accept pipeline input: False 151 | Accept wildcard characters: False 152 | ``` 153 | 154 | ### -ValidUntil 155 | Define a "valid until" date with the new short code. 156 | 157 | ```yaml 158 | Type: DateTime 159 | Parameter Sets: (All) 160 | Aliases: 161 | 162 | Required: False 163 | Position: 8 164 | Default value: None 165 | Accept pipeline input: False 166 | Accept wildcard characters: False 167 | ``` 168 | 169 | ### -MaxVisits 170 | Set the maximum number of visits allowed for the new short code. 171 | 172 | ```yaml 173 | Type: Int32 174 | Parameter Sets: (All) 175 | Aliases: 176 | 177 | Required: False 178 | Position: 9 179 | Default value: 0 180 | Accept pipeline input: False 181 | Accept wildcard characters: False 182 | ``` 183 | 184 | ### -Title 185 | Define a title with the new short code. 186 | 187 | ```yaml 188 | Type: String 189 | Parameter Sets: (All) 190 | Aliases: 191 | 192 | Required: False 193 | Position: 10 194 | Default value: None 195 | Accept pipeline input: False 196 | Accept wildcard characters: False 197 | ``` 198 | 199 | ### -Domain 200 | Associate a domain with the new short code to be something other than the default domain. 201 | This is useful if your Shlink instance is responding/creating short URLs for multiple domains. 202 | 203 | ```yaml 204 | Type: String 205 | Parameter Sets: (All) 206 | Aliases: 207 | 208 | Required: False 209 | Position: 11 210 | Default value: None 211 | Accept pipeline input: False 212 | Accept wildcard characters: False 213 | ``` 214 | 215 | ### -ShortCodeLength 216 | Set the length of your new short code other than the default. 217 | 218 | ```yaml 219 | Type: Int32 220 | Parameter Sets: (All) 221 | Aliases: 222 | 223 | Required: False 224 | Position: 12 225 | Default value: 0 226 | Accept pipeline input: False 227 | Accept wildcard characters: False 228 | ``` 229 | 230 | ### -FindIfExists 231 | Specify this switch to first search and return the data about an existing short code that uses the same long URL if one exists. 232 | 233 | ```yaml 234 | Type: Boolean 235 | Parameter Sets: (All) 236 | Aliases: 237 | 238 | Required: False 239 | Position: 13 240 | Default value: False 241 | Accept pipeline input: False 242 | Accept wildcard characters: False 243 | ``` 244 | 245 | ### -ValidateUrl 246 | Control long URL validation while creating the short code. 247 | 248 | ```yaml 249 | Type: Boolean 250 | Parameter Sets: (All) 251 | Aliases: 252 | 253 | Required: False 254 | Position: 14 255 | Default value: False 256 | Accept pipeline input: False 257 | Accept wildcard characters: False 258 | ``` 259 | 260 | ### -ForwardQuery 261 | Forwards UTM query parameters to the long URL if any were passed to the short URL. 262 | 263 | ```yaml 264 | Type: Boolean 265 | Parameter Sets: (All) 266 | Aliases: 267 | 268 | Required: False 269 | Position: 15 270 | Default value: False 271 | Accept pipeline input: False 272 | Accept wildcard characters: False 273 | ``` 274 | 275 | ### -Crawlable 276 | Set short URLs as crawlable, making them be listed in the robots.txt as Allowed. 277 | 278 | ```yaml 279 | Type: Boolean 280 | Parameter Sets: (All) 281 | Aliases: 282 | 283 | Required: False 284 | Position: 16 285 | Default value: False 286 | Accept pipeline input: False 287 | Accept wildcard characters: False 288 | ``` 289 | 290 | ### -ShlinkServer 291 | The URL of your Shlink server (including schema). 292 | For example "https://example.com". 293 | It is not required to use this parameter for every use of this function. 294 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 295 | 296 | ```yaml 297 | Type: String 298 | Parameter Sets: (All) 299 | Aliases: 300 | 301 | Required: False 302 | Position: 17 303 | Default value: None 304 | Accept pipeline input: False 305 | Accept wildcard characters: False 306 | ``` 307 | 308 | ### -ShlinkApiKey 309 | A SecureString object of your Shlink server's API key. 310 | It is not required to use this parameter for every use of this function. 311 | When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. 312 | 313 | ```yaml 314 | Type: SecureString 315 | Parameter Sets: (All) 316 | Aliases: 317 | 318 | Required: False 319 | Position: 18 320 | Default value: None 321 | Accept pipeline input: False 322 | Accept wildcard characters: False 323 | ``` 324 | 325 | ### CommonParameters 326 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 327 | 328 | ## INPUTS 329 | 330 | ### This function does not accept pipeline input. 331 | ## OUTPUTS 332 | 333 | ### System.Management.Automation.PSObject 334 | ## NOTES 335 | 336 | ## RELATED LINKS 337 | --------------------------------------------------------------------------------