├── .github └── FUNDING.yml ├── Examples ├── WaitUnifiStockModern.ps1 ├── WaitUnifiStockLegacy.ps1 ├── GetUnifiStockModern.ps1 └── GetUnifiStockLegacy.ps1 ├── Docs ├── Readme.md ├── Get-UnifiStockLegacy.md ├── Get-UnifiStock.md ├── Wait-UnifiStockLegacy.md └── Wait-UnifiStock.md ├── License ├── CHANGELOG.MD ├── UnifiStockTracker.psd1 ├── UnifiStockTracker.psm1 ├── Build └── Manage-UnifiStockTracker.ps1 ├── Public ├── Wait-UnifiStockLegacy.ps1 ├── Wait-UnifiStock.ps1 ├── Get-UnifiStockLegacy.ps1 └── Get-UnifiStock.ps1 └── README.MD /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: PrzemyslawKlys 4 | custom: https://paypal.me/PrzemyslawKlys -------------------------------------------------------------------------------- /Examples/WaitUnifiStockModern.ps1: -------------------------------------------------------------------------------- 1 | Import-Module .\UnifiStockTracker.psd1 -Force 2 | 3 | Wait-UnifiStock -ProductName 'UniFi6 Mesh', 'G4 Doorbell Pro', 'Camera G4 Pro', 'Test' -Seconds 60 -Store UK 4 | Wait-UnifiStock -ProductSKU 'UDR-EU' -ProductName 'Switch Flex XG' -Seconds 60 -Store Europe 5 | Wait-UnifiStock -ProductName 'Access Point AC Lite' -Seconds 60 -Store Europe -------------------------------------------------------------------------------- /Examples/WaitUnifiStockLegacy.ps1: -------------------------------------------------------------------------------- 1 | Import-Module .\UnifiStockTracker.psd1 -Force 2 | 3 | Wait-UnifiStockLegacy -ProductName 'UniFi6 Mesh', 'G4 Doorbell Pro', 'Camera G4 Pro', 'Test' -Seconds 60 -Store Brazil 4 | Wait-UnifiStockLegacy -ProductSKU 'UDR-EU' -ProductName 'Switch Flex XG' -Seconds 60 -Store Brazil 5 | Wait-UnifiStockLegacy -ProductName 'Access Point AC Lite' -Seconds 60 -Store Brazil -------------------------------------------------------------------------------- /Docs/Readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | Module Name: UnifiStockTracker 3 | Module Guid: e3d09753-16be-4535-b74f-d9a4c6927a54 4 | Download Help Link: {{ Update Download Link }} 5 | Help Version: {{ Please enter version of help manually (X.X.X.X) format }} 6 | Locale: en-US 7 | --- 8 | 9 | # UnifiStockTracker Module 10 | ## Description 11 | {{ Fill in the Description }} 12 | 13 | ## UnifiStockTracker Cmdlets 14 | ### [Get-UnifiStock](Get-UnifiStock.md) 15 | Get the stock status of Ubiquiti products from their online store. 16 | 17 | ### [Get-UnifiStockLegacy](Get-UnifiStockLegacy.md) 18 | Get the stock status of Ubiquiti products from their online store. 19 | 20 | ### [Wait-UnifiStock](Wait-UnifiStock.md) 21 | When run waits for the specified SKU or Product to be in stock in Ubiquiti's online store. 22 | 23 | ### [Wait-UnifiStockLegacy](Wait-UnifiStockLegacy.md) 24 | When run waits for the specified SKU or Product to be in stock in Ubiquiti's online store. 25 | 26 | -------------------------------------------------------------------------------- /Examples/GetUnifiStockModern.ps1: -------------------------------------------------------------------------------- 1 | Import-Module .\UnifiStockTracker.psd1 -Force 2 | 3 | Get-UnifiStock -Store UK | Sort-Object -Property Name | Format-Table 4 | Get-UnifiStock -Store USA -Verbose | Sort-Object -Property Name | Format-Table 5 | 6 | Get-UnifiStock -Store USA -Collection AccessoriesCabling, CableBox | Sort-Object -Property Name | Format-Table 7 | Get-UnifiStock -Store Europe -Collection CameraSecurityDome360, CameraSecurityCompactPoEWired | Sort-Object -Property Name | Format-Table 8 | Get-UnifiStock -Store USA -Collection HostingAndGatewaysCloud,DreamMachine, DreamRouter | Sort-Object -Property Name | Format-Table 9 | Get-UnifiStock -Store Europe -Collection InternetBackup | Sort-Object -Property Name | Format-Table 10 | Get-UnifiStock -Store Europe -Collection SwitchingProEthernet | Sort-Object -Property Name | Format-Table 11 | Get-UnifiStock -Verbose -Store Europe -Collection NewIntegrationsPhoneATA, NewIntegrationsPhoneCompact, NewIntegrationsPhoneExecutive | Sort-Object -Property Name | Format-Table -------------------------------------------------------------------------------- /Examples/GetUnifiStockLegacy.ps1: -------------------------------------------------------------------------------- 1 | Import-Module .\UnifiStockTracker.psd1 -Force 2 | 3 | # following examples will only work for non-eu, non-us shops that are not yet converted to the new shop 4 | Get-UnifiStockLegacy -Store Brazil -Collection Protect, ProtectAccessories, ProtectNVR | Sort-Object -Property Name | Format-Table 5 | Get-UnifiStockLegacy -Store Brazil -Collection Protect, NetworkWifi | Sort-Object -Property Name | Format-Table 6 | Get-UnifiStockLegacy -Store Brazil | Sort-Object -Property Name | Format-Table 7 | Get-UnifiStockLegacy -Store Brazil -Collection UnifiAccessories | Sort-Object -Property Name | Format-Table 8 | Get-UnifiStockLegacy -Store Brazil -Collection UnifiAccessories | Sort-Object -Property Name | Format-Table 9 | Get-UnifiStockLegacy -Store Brazil -Collection UnifiAccessories | Sort-Object -Property Name | Format-Table 10 | Get-UnifiStockLegacy -Store Brazil -Collection EarlyAccess | Sort-Object -Property Name | Format-Table 11 | Get-UnifiStockLegacy -Verbose -Store Brazil -Collection UnifiPhoneSystem, EarlyAccessConnect, EarlyAccessDoorAccess | Sort-Object -Property Name | Format-Table -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Evotec 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CHANGELOG.MD: -------------------------------------------------------------------------------- 1 | ### 2.2.0 - 2024.08.11 2 | - Fixes paging that was missing few items from the store 3 | 4 | ### 2.1.0 - 2023.07.24 5 | - Added UK store 6 | 7 | ### 2.0.0 - 2023.06.04 8 | This Release resolves: 9 | - https://github.com/EvotecIT/UnifiStockTracker/issues/2 10 | 11 | It has breaking changes: 12 | - New function `Get-UnifiStockLegacy/Wait-UnifiStockLegacy` work with non EU/US stores to provide backwards compatibility 13 | - `Get-UnifiStock/WaitUnifiStock` now support only EU/US stores until legacy stores will also be migrated (if it ever happens) 14 | 15 | ### 1.0.3 - 2023.04.17 16 | - Add multiple new collections. Currently supported collections are: 17 | - EarlyAccess 18 | - EarlyAccessConnect 19 | - EarlyAccessDoorAccess 20 | - EarlyAccessSmartpower 21 | - EarlyAccessUispFiber 22 | - EarlyAccessUispWired 23 | - EarlyAccessUispWireless 24 | - EarlyAccessUnifiNetworkHost 25 | - NetworkHost 26 | - NetworkOS 27 | - NetworkRoutingOffload 28 | - NetworkRoutingSwitching 29 | - NetworkSmartPower 30 | - NetworkSwitching 31 | - NetworkWifi 32 | - OperatorAirmaxAndLtu 33 | - OperatorIspInfrastructure 34 | - Protect 35 | - ProtectAccessories 36 | - ProtectNVR 37 | - UnifiAccessories 38 | - UnifiConnect 39 | - UnifiDoorAccess 40 | - UnifiPhoneSystem 41 | ### 1.0.2 - 2023.04.17 42 | - Adds error handling if date parsing fails 43 | 44 | ### 1.0.1 - 2023.04.15 45 | - Small improvement in error handling 46 | - 47 | ### 1.0.0 - 2023.04.15 48 | - First release -------------------------------------------------------------------------------- /UnifiStockTracker.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | AliasesToExport = @() 3 | Author = 'Przemyslaw Klys' 4 | CmdletsToExport = @() 5 | CompanyName = 'Evotec' 6 | CompatiblePSEditions = @('Desktop', 'Core') 7 | Copyright = '(c) 2011 - 2024 Przemyslaw Klys @ Evotec. All rights reserved.' 8 | Description = 'PowerShell module to get current stock in Ubiquiti Unifi store' 9 | FunctionsToExport = @('Get-UnifiStock', 'Get-UnifiStockLegacy', 'Wait-UnifiStock', 'Wait-UnifiStockLegacy') 10 | GUID = 'e3d09753-16be-4535-b74f-d9a4c6927a54' 11 | ModuleVersion = '2.2.0' 12 | PowerShellVersion = '5.1' 13 | PrivateData = @{ 14 | PSData = @{ 15 | ExternalModuleDependencies = @('Microsoft.PowerShell.Management', 'Microsoft.PowerShell.Utility') 16 | IconUri = 'https://help.ui.com/hc/article_attachments/360010605813/ubiquiti_logo.png' 17 | ProjectUri = 'https://github.com/EvotecIT/UnifiStockTracker' 18 | Tags = @('Windows', 'macOS', 'Linux', 'Ubiquiti', 'Unifi', 'Stock', 'Tracker') 19 | } 20 | } 21 | RequiredModules = @(@{ 22 | Guid = '0b0ba5c5-ec85-4c2b-a718-874e55a8bc3f' 23 | ModuleName = 'PSWriteColor' 24 | ModuleVersion = '1.0.1' 25 | }, 'Microsoft.PowerShell.Management', 'Microsoft.PowerShell.Utility') 26 | RootModule = 'UnifiStockTracker.psm1' 27 | } -------------------------------------------------------------------------------- /Docs/Get-UnifiStockLegacy.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: UnifiStockTracker-help.xml 3 | Module Name: UnifiStockTracker 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-UnifiStockLegacy 9 | 10 | ## SYNOPSIS 11 | Get the stock status of Ubiquiti products from their online store. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Get-UnifiStockLegacy [-Store] [[-Collection] ] [] 17 | ``` 18 | 19 | ## DESCRIPTION 20 | Get the stock status of Ubiquiti products from their online store. 21 | 22 | ## EXAMPLES 23 | 24 | ### EXAMPLE 1 25 | ``` 26 | Get-UnifiStock -Store USA -Collection Protect, ProtectAccessories, ProtectNVR | Sort-Object -Property Name | Format-Table 27 | ``` 28 | 29 | ### EXAMPLE 2 30 | ``` 31 | Get-UnifiStock -Store Europe -Collection Protect, NetworkWifi | Sort-Object -Property Name | Format-Table 32 | ``` 33 | 34 | ### EXAMPLE 3 35 | ``` 36 | Get-UnifiStock -Store Europe | Sort-Object -Property Name | Format-Table 37 | ``` 38 | 39 | ## PARAMETERS 40 | 41 | ### -Store 42 | The store to check for stock. 43 | Valid values are: Europe, USA, Brazil, India, Japan, Taiwan, Signapore, Mexico, China 44 | 45 | ```yaml 46 | Type: String 47 | Parameter Sets: (All) 48 | Aliases: 49 | 50 | Required: True 51 | Position: 1 52 | Default value: None 53 | Accept pipeline input: False 54 | Accept wildcard characters: False 55 | ``` 56 | 57 | ### -Collection 58 | Which collection to list. 59 | 60 | ```yaml 61 | Type: String[] 62 | Parameter Sets: (All) 63 | Aliases: 64 | 65 | Required: False 66 | Position: 2 67 | Default value: None 68 | Accept pipeline input: False 69 | Accept wildcard characters: False 70 | ``` 71 | 72 | ### CommonParameters 73 | 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). 74 | 75 | ## INPUTS 76 | 77 | ## OUTPUTS 78 | 79 | ## NOTES 80 | General notes 81 | 82 | ## RELATED LINKS 83 | -------------------------------------------------------------------------------- /Docs/Get-UnifiStock.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: UnifiStockTracker-help.xml 3 | Module Name: UnifiStockTracker 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-UnifiStock 9 | 10 | ## SYNOPSIS 11 | Get the stock status of Ubiquiti products from their online store. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Get-UnifiStock [-Store] [[-Collection] ] [] 17 | ``` 18 | 19 | ## DESCRIPTION 20 | Get the stock status of Ubiquiti products from their online store. 21 | 22 | ## EXAMPLES 23 | 24 | ### EXAMPLE 1 25 | ``` 26 | Get-UnifiStock -Store USA -Collection AccessoriesCabling, CableBox | Sort-Object -Property Name | Format-Table 27 | ``` 28 | 29 | ### EXAMPLE 2 30 | ``` 31 | Get-UnifiStock -Store Europe -Collection HostingAndGatewaysCloud,DreamMachine, DreamRouter | Sort-Object -Property Name | Format-Table 32 | ``` 33 | 34 | ### EXAMPLE 3 35 | ``` 36 | Get-UnifiStock -Store Europe | Sort-Object -Property Name | Format-Table 37 | ``` 38 | 39 | ## PARAMETERS 40 | 41 | ### -Store 42 | The store to check for stock. 43 | Valid values are: Europe, USA, UK 44 | If you want to use a different store you can use Get-UnifiStockLegacy for other countries. 45 | This is because the legacy store has a different format for the JSON data, and are not yet migrated to new "look" 46 | 47 | ```yaml 48 | Type: String 49 | Parameter Sets: (All) 50 | Aliases: 51 | 52 | Required: True 53 | Position: 1 54 | Default value: None 55 | Accept pipeline input: False 56 | Accept wildcard characters: False 57 | ``` 58 | 59 | ### -Collection 60 | Which collection to list. 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 | ### CommonParameters 75 | 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). 76 | 77 | ## INPUTS 78 | 79 | ## OUTPUTS 80 | 81 | ## NOTES 82 | General notes 83 | 84 | ## RELATED LINKS 85 | -------------------------------------------------------------------------------- /UnifiStockTracker.psm1: -------------------------------------------------------------------------------- 1 | #Get public and private function definition files. 2 | $Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue -Recurse ) 3 | $Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue -Recurse ) 4 | $Classes = @( Get-ChildItem -Path $PSScriptRoot\Classes\*.ps1 -ErrorAction SilentlyContinue -Recurse ) 5 | $Enums = @( Get-ChildItem -Path $PSScriptRoot\Enums\*.ps1 -ErrorAction SilentlyContinue -Recurse ) 6 | 7 | $AssemblyFolders = Get-ChildItem -Path $PSScriptRoot\Lib -Directory -ErrorAction SilentlyContinue 8 | $Assembly = @( 9 | if ($AssemblyFolders.BaseName -contains 'Standard') { 10 | @( Get-ChildItem -Path $PSScriptRoot\Lib\Standard\*.dll -ErrorAction SilentlyContinue -Recurse) 11 | } 12 | if ($PSEdition -eq 'Core') { 13 | @( Get-ChildItem -Path $PSScriptRoot\Lib\Core\*.dll -ErrorAction SilentlyContinue -Recurse ) 14 | } else { 15 | @( Get-ChildItem -Path $PSScriptRoot\Lib\Default\*.dll -ErrorAction SilentlyContinue -Recurse ) 16 | } 17 | ) 18 | $FoundErrors = @( 19 | Foreach ($Import in @($Assembly)) { 20 | try { 21 | Write-Verbose -Message $Import.FullName 22 | Add-Type -Path $Import.Fullname -ErrorAction Stop 23 | # } 24 | } catch [System.Reflection.ReflectionTypeLoadException] { 25 | Write-Warning "Processing $($Import.Name) Exception: $($_.Exception.Message)" 26 | $LoaderExceptions = $($_.Exception.LoaderExceptions) | Sort-Object -Unique 27 | foreach ($E in $LoaderExceptions) { 28 | Write-Warning "Processing $($Import.Name) LoaderExceptions: $($E.Message)" 29 | } 30 | $true 31 | #Write-Error -Message "StackTrace: $($_.Exception.StackTrace)" 32 | } catch { 33 | Write-Warning "Processing $($Import.Name) Exception: $($_.Exception.Message)" 34 | $LoaderExceptions = $($_.Exception.LoaderExceptions) | Sort-Object -Unique 35 | foreach ($E in $LoaderExceptions) { 36 | Write-Warning "Processing $($Import.Name) LoaderExceptions: $($E.Message)" 37 | } 38 | $true 39 | #Write-Error -Message "StackTrace: $($_.Exception.StackTrace)" 40 | } 41 | } 42 | #Dot source the files 43 | Foreach ($Import in @($Private + $Public + $Classes + $Enums)) { 44 | Try { 45 | . $Import.Fullname 46 | } Catch { 47 | Write-Error -Message "Failed to import functions from $($import.Fullname): $_" 48 | $true 49 | } 50 | } 51 | ) 52 | 53 | if ($FoundErrors.Count -gt 0) { 54 | $ModuleName = (Get-ChildItem $PSScriptRoot\*.psd1).BaseName 55 | Write-Warning "Importing module $ModuleName failed. Fix errors before continuing." 56 | break 57 | } 58 | 59 | Export-ModuleMember -Function '*' -Alias '*' -------------------------------------------------------------------------------- /Docs/Wait-UnifiStockLegacy.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: UnifiStockTracker-help.xml 3 | Module Name: UnifiStockTracker 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Wait-UnifiStockLegacy 9 | 10 | ## SYNOPSIS 11 | When run waits for the specified SKU or Product to be in stock in Ubiquiti's online store. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Wait-UnifiStockLegacy [[-ProductName] ] [[-ProductSKU] ] [-Store] 17 | [[-Seconds] ] [-DoNotOpenWebsite] [-DoNotPlaySound] [-DoNotUseBeep] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | When run waits for the specified SKU or Product to be in stock in Ubiquiti's online store. 22 | Once the product is in stock the function will play a beep, read which product is in stock and open a browser to specific product page. 23 | 24 | ## EXAMPLES 25 | 26 | ### EXAMPLE 1 27 | ``` 28 | Wait-UnifiStockLegacy -ProductSKU 'UDR-EU' -ProductName 'Switch Flex XG' -Seconds 60 -Store Brazil 29 | ``` 30 | 31 | ### EXAMPLE 2 32 | ``` 33 | Wait-UnifiStockLegacy -ProductName 'UniFi6 Mesh', 'G4 Doorbell Pro', 'Camera G4 Pro', 'Test' -Seconds 60 -Store Brazil 34 | ``` 35 | 36 | ### EXAMPLE 3 37 | ``` 38 | Wait-UnifiStockLegacy -ProductName 'UniFi6 Mesh', 'G4 Doorbell Pro', 'Camera G4 Pro', 'Test' -Seconds 60 -DoNotUseBeep -Store Brazil 39 | ``` 40 | 41 | ## PARAMETERS 42 | 43 | ### -ProductName 44 | One or more products to wait for to be in stock with search by it's Name 45 | 46 | ```yaml 47 | Type: String[] 48 | Parameter Sets: (All) 49 | Aliases: 50 | 51 | Required: False 52 | Position: 1 53 | Default value: None 54 | Accept pipeline input: False 55 | Accept wildcard characters: False 56 | ``` 57 | 58 | ### -ProductSKU 59 | One or more products to wait for to be in stock with search by it's SKU 60 | 61 | ```yaml 62 | Type: String[] 63 | Parameter Sets: (All) 64 | Aliases: 65 | 66 | Required: False 67 | Position: 2 68 | Default value: None 69 | Accept pipeline input: False 70 | Accept wildcard characters: False 71 | ``` 72 | 73 | ### -Store 74 | The store to check for stock. 75 | Valid values are Brazil, India, Japan, Taiwan, Signapore, Mexico, China 76 | If you want EU/USA store you can use Wait-UnifiStock for those. 77 | 78 | ```yaml 79 | Type: String 80 | Parameter Sets: (All) 81 | Aliases: 82 | 83 | Required: True 84 | Position: 3 85 | Default value: None 86 | Accept pipeline input: False 87 | Accept wildcard characters: False 88 | ``` 89 | 90 | ### -Seconds 91 | The number of seconds to wait between checks. 92 | Default is 60 seconds. 93 | 94 | ```yaml 95 | Type: Int32 96 | Parameter Sets: (All) 97 | Aliases: 98 | 99 | Required: False 100 | Position: 4 101 | Default value: 60 102 | Accept pipeline input: False 103 | Accept wildcard characters: False 104 | ``` 105 | 106 | ### -DoNotOpenWebsite 107 | If specified the website will not be opened when the product is in stock. 108 | 109 | ```yaml 110 | Type: SwitchParameter 111 | Parameter Sets: (All) 112 | Aliases: 113 | 114 | Required: False 115 | Position: Named 116 | Default value: False 117 | Accept pipeline input: False 118 | Accept wildcard characters: False 119 | ``` 120 | 121 | ### -DoNotPlaySound 122 | If specified the sound will not be played when the product is in stock. 123 | 124 | ```yaml 125 | Type: SwitchParameter 126 | Parameter Sets: (All) 127 | Aliases: 128 | 129 | Required: False 130 | Position: Named 131 | Default value: False 132 | Accept pipeline input: False 133 | Accept wildcard characters: False 134 | ``` 135 | 136 | ### -DoNotUseBeep 137 | If specified the beep will not be played when the product is in stock. 138 | 139 | ```yaml 140 | Type: SwitchParameter 141 | Parameter Sets: (All) 142 | Aliases: 143 | 144 | Required: False 145 | Position: Named 146 | Default value: False 147 | Accept pipeline input: False 148 | Accept wildcard characters: False 149 | ``` 150 | 151 | ### CommonParameters 152 | 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). 153 | 154 | ## INPUTS 155 | 156 | ## OUTPUTS 157 | 158 | ## NOTES 159 | General notes 160 | 161 | ## RELATED LINKS 162 | -------------------------------------------------------------------------------- /Docs/Wait-UnifiStock.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: UnifiStockTracker-help.xml 3 | Module Name: UnifiStockTracker 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Wait-UnifiStock 9 | 10 | ## SYNOPSIS 11 | When run waits for the specified SKU or Product to be in stock in Ubiquiti's online store. 12 | 13 | ## SYNTAX 14 | 15 | ``` 16 | Wait-UnifiStock [[-ProductName] ] [[-ProductSKU] ] [-Store] [[-Seconds] ] 17 | [-DoNotOpenWebsite] [-DoNotPlaySound] [-DoNotUseBeep] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | When run waits for the specified SKU or Product to be in stock in Ubiquiti's online store. 22 | Once the product is in stock the function will play a beep, read which product is in stock and open a browser to specific product page. 23 | 24 | ## EXAMPLES 25 | 26 | ### EXAMPLE 1 27 | ``` 28 | Wait-UnifiStock -ProductSKU 'UDR-EU' -ProductName 'Switch Flex XG' -Seconds 60 -Store Europe 29 | ``` 30 | 31 | ### EXAMPLE 2 32 | ``` 33 | Wait-UnifiStock -ProductName 'UniFi6 Mesh', 'G4 Doorbell Pro', 'Camera G4 Pro', 'Test' -Seconds 60 -Store Europe 34 | ``` 35 | 36 | ### EXAMPLE 3 37 | ``` 38 | Wait-UnifiStock -ProductName 'UniFi6 Mesh', 'G4 Doorbell Pro', 'Camera G4 Pro', 'Test' -Seconds 60 -DoNotUseBeep -Store Europe 39 | ``` 40 | 41 | ## PARAMETERS 42 | 43 | ### -ProductName 44 | One or more products to wait for to be in stock with search by it's Name 45 | 46 | ```yaml 47 | Type: String[] 48 | Parameter Sets: (All) 49 | Aliases: 50 | 51 | Required: False 52 | Position: 1 53 | Default value: None 54 | Accept pipeline input: False 55 | Accept wildcard characters: False 56 | ``` 57 | 58 | ### -ProductSKU 59 | One or more products to wait for to be in stock with search by it's SKU 60 | 61 | ```yaml 62 | Type: String[] 63 | Parameter Sets: (All) 64 | Aliases: 65 | 66 | Required: False 67 | Position: 2 68 | Default value: None 69 | Accept pipeline input: False 70 | Accept wildcard characters: False 71 | ``` 72 | 73 | ### -Store 74 | The store to check for stock. 75 | Valid values are Europe, USA and UK. 76 | If you want to use a different store you can use Wait-UnifiStockLegacy for other countries. 77 | This is because the legacy store has a different format for the JSON data, and are not yet migrated to new "look" 78 | 79 | ```yaml 80 | Type: String 81 | Parameter Sets: (All) 82 | Aliases: 83 | 84 | Required: True 85 | Position: 3 86 | Default value: None 87 | Accept pipeline input: False 88 | Accept wildcard characters: False 89 | ``` 90 | 91 | ### -Seconds 92 | The number of seconds to wait between checks. 93 | Default is 60 seconds. 94 | 95 | ```yaml 96 | Type: Int32 97 | Parameter Sets: (All) 98 | Aliases: 99 | 100 | Required: False 101 | Position: 4 102 | Default value: 60 103 | Accept pipeline input: False 104 | Accept wildcard characters: False 105 | ``` 106 | 107 | ### -DoNotOpenWebsite 108 | If specified the website will not be opened when the product is in stock. 109 | 110 | ```yaml 111 | Type: SwitchParameter 112 | Parameter Sets: (All) 113 | Aliases: 114 | 115 | Required: False 116 | Position: Named 117 | Default value: False 118 | Accept pipeline input: False 119 | Accept wildcard characters: False 120 | ``` 121 | 122 | ### -DoNotPlaySound 123 | If specified the sound will not be played when the product is in stock. 124 | 125 | ```yaml 126 | Type: SwitchParameter 127 | Parameter Sets: (All) 128 | Aliases: 129 | 130 | Required: False 131 | Position: Named 132 | Default value: False 133 | Accept pipeline input: False 134 | Accept wildcard characters: False 135 | ``` 136 | 137 | ### -DoNotUseBeep 138 | If specified the beep will not be played when the product is in stock. 139 | 140 | ```yaml 141 | Type: SwitchParameter 142 | Parameter Sets: (All) 143 | Aliases: 144 | 145 | Required: False 146 | Position: Named 147 | Default value: False 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 | ## OUTPUTS 158 | 159 | ## NOTES 160 | General notes 161 | 162 | ## RELATED LINKS 163 | -------------------------------------------------------------------------------- /Build/Manage-UnifiStockTracker.ps1: -------------------------------------------------------------------------------- 1 | Invoke-ModuleBuild -ModuleName 'UnifiStockTracker' { 2 | # Usual defaults as per standard module 3 | $Manifest = @{ 4 | # Version number of this module. 5 | ModuleVersion = '2.X.0' 6 | # Supported PSEditions 7 | CompatiblePSEditions = @('Desktop', 'Core') 8 | # ID used to uniquely identify this module 9 | GUID = 'e3d09753-16be-4535-b74f-d9a4c6927a54' 10 | # Author of this module 11 | Author = 'Przemyslaw Klys' 12 | # Company or vendor of this module 13 | CompanyName = 'Evotec' 14 | # Copyright statement for this module 15 | Copyright = "(c) 2011 - $((Get-Date).Year) Przemyslaw Klys @ Evotec. All rights reserved." 16 | # Description of the functionality provided by this module 17 | Description = 'PowerShell module to get current stock in Ubiquiti Unifi store' 18 | # Minimum version of the Windows PowerShell engine required by this module 19 | PowerShellVersion = '5.1' 20 | # 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. 21 | Tags = @('Windows', 'macOS', "Linux", 'Ubiquiti', 'Unifi', 'Stock', 'Tracker') 22 | 23 | IconUri = 'https://help.ui.com/hc/article_attachments/360010605813/ubiquiti_logo.png' 24 | 25 | ProjectUri = 'https://github.com/EvotecIT/UnifiStockTracker' 26 | } 27 | New-ConfigurationManifest @Manifest 28 | 29 | New-ConfigurationModule -Type RequiredModule -Name 'PSWriteColor' -Guid Auto -Version Latest 30 | #New-ConfigurationModule -Type ExternalModule -Name 'Microsoft.PowerShell.Utility', 'Microsoft.PowerShell.Management','Microsoft.PowerShell.Security' 31 | New-ConfigurationModule -Type ApprovedModule -Name 'PSSharedGoods', 'PSWriteColor', 'Connectimo', 'PSUnifi', 'PSWebToolbox', 'PSMyPassword', 'ADEssentials' 32 | 33 | New-ConfigurationModule -Type ExternalModule -Name @( 34 | "Microsoft.PowerShell.Management" 35 | "Microsoft.PowerShell.Utility" 36 | ) 37 | 38 | $ConfigurationFormat = [ordered] @{ 39 | RemoveComments = $true 40 | RemoveEmptyLines = $true 41 | 42 | PlaceOpenBraceEnable = $true 43 | PlaceOpenBraceOnSameLine = $true 44 | PlaceOpenBraceNewLineAfter = $true 45 | PlaceOpenBraceIgnoreOneLineBlock = $false 46 | 47 | PlaceCloseBraceEnable = $true 48 | PlaceCloseBraceNewLineAfter = $true 49 | PlaceCloseBraceIgnoreOneLineBlock = $false 50 | PlaceCloseBraceNoEmptyLineBefore = $true 51 | 52 | UseConsistentIndentationEnable = $true 53 | UseConsistentIndentationKind = 'space' 54 | UseConsistentIndentationPipelineIndentation = 'IncreaseIndentationAfterEveryPipeline' 55 | UseConsistentIndentationIndentationSize = 4 56 | 57 | UseConsistentWhitespaceEnable = $true 58 | UseConsistentWhitespaceCheckInnerBrace = $true 59 | UseConsistentWhitespaceCheckOpenBrace = $true 60 | UseConsistentWhitespaceCheckOpenParen = $true 61 | UseConsistentWhitespaceCheckOperator = $true 62 | UseConsistentWhitespaceCheckPipe = $true 63 | UseConsistentWhitespaceCheckSeparator = $true 64 | 65 | AlignAssignmentStatementEnable = $true 66 | AlignAssignmentStatementCheckHashtable = $true 67 | 68 | UseCorrectCasingEnable = $true 69 | } 70 | # format PSD1 and PSM1 files when merging into a single file 71 | # enable formatting is not required as Configuration is provided 72 | New-ConfigurationFormat -ApplyTo 'OnMergePSM1', 'OnMergePSD1' -Sort None @ConfigurationFormat 73 | # format PSD1 and PSM1 files within the module 74 | # enable formatting is required to make sure that formatting is applied (with default settings) 75 | New-ConfigurationFormat -ApplyTo 'DefaultPSD1', 'DefaultPSM1' -EnableFormatting -Sort None 76 | # when creating PSD1 use special style without comments and with only required parameters 77 | New-ConfigurationFormat -ApplyTo 'DefaultPSD1', 'OnMergePSD1' -PSD1Style 'Minimal' 78 | # configuration for documentation, at the same time it enables documentation processing 79 | New-ConfigurationDocumentation -Enable:$false -StartClean -UpdateWhenNew -PathReadme 'Docs\Readme.md' -Path 'Docs' 80 | 81 | New-ConfigurationImportModule -ImportSelf 82 | 83 | New-ConfigurationBuild -Enable:$true -SignModule -MergeModuleOnBuild -MergeFunctionsFromApprovedModules -CertificateThumbprint '483292C9E317AA13B07BB7A96AE9D1A5ED9E7703' 84 | 85 | # New-ConfigurationTest -TestsPath "$PSScriptRoot\..\Tests" -Enable 86 | 87 | New-ConfigurationArtefact -Type Unpacked -Enable -Path "$PSScriptRoot\..\Artefacts\Unpacked" -AddRequiredModules 88 | New-ConfigurationArtefact -Type Packed -Enable -Path "$PSScriptRoot\..\Artefacts\Packed" -ArtefactName '.v.zip' -AddRequiredModules 89 | 90 | # options for publishing to github/psgallery 91 | #New-ConfigurationPublish -Type PowerShellGallery -FilePath 'C:\Support\Important\PowerShellGalleryAPI.txt' -Enabled:$true 92 | #New-ConfigurationPublish -Type GitHub -FilePath 'C:\Support\Important\GitHubAPI.txt' -UserName 'EvotecIT' -Enabled:$true 93 | } -ExitCode -------------------------------------------------------------------------------- /Public/Wait-UnifiStockLegacy.ps1: -------------------------------------------------------------------------------- 1 | function Wait-UnifiStockLegacy { 2 | <# 3 | .SYNOPSIS 4 | When run waits for the specified SKU or Product to be in stock in Ubiquiti's online store. 5 | 6 | .DESCRIPTION 7 | When run waits for the specified SKU or Product to be in stock in Ubiquiti's online store. 8 | Once the product is in stock the function will play a beep, read which product is in stock and open a browser to specific product page. 9 | 10 | .PARAMETER ProductName 11 | One or more products to wait for to be in stock with search by it's Name 12 | 13 | .PARAMETER ProductSKU 14 | One or more products to wait for to be in stock with search by it's SKU 15 | 16 | .PARAMETER Store 17 | The store to check for stock. Valid values are Brazil, India, Japan, Taiwan, Signapore, Mexico, China 18 | If you want EU/USA store you can use Wait-UnifiStock for those. 19 | 20 | .PARAMETER Seconds 21 | The number of seconds to wait between checks. Default is 60 seconds. 22 | 23 | .PARAMETER DoNotOpenWebsite 24 | If specified the website will not be opened when the product is in stock. 25 | 26 | .PARAMETER DoNotPlaySound 27 | If specified the sound will not be played when the product is in stock. 28 | 29 | .PARAMETER DoNotUseBeep 30 | If specified the beep will not be played when the product is in stock. 31 | 32 | .EXAMPLE 33 | Wait-UnifiStockLegacy -ProductSKU 'UDR-EU' -ProductName 'Switch Flex XG' -Seconds 60 -Store Brazil 34 | 35 | .EXAMPLE 36 | Wait-UnifiStockLegacy -ProductName 'UniFi6 Mesh', 'G4 Doorbell Pro', 'Camera G4 Pro', 'Test' -Seconds 60 -Store Brazil 37 | 38 | .EXAMPLE 39 | Wait-UnifiStockLegacy -ProductName 'UniFi6 Mesh', 'G4 Doorbell Pro', 'Camera G4 Pro', 'Test' -Seconds 60 -DoNotUseBeep -Store Brazil 40 | 41 | .NOTES 42 | General notes 43 | #> 44 | [cmdletBinding()] 45 | param( 46 | [string[]] $ProductName, 47 | [string[]] $ProductSKU, 48 | [parameter(Mandatory)][ValidateSet('Brazil', 'India', 'Japan', 'Taiwan', 'Signapore', 'Mexico', 'China')][string] $Store, 49 | [int] $Seconds = 60, 50 | [switch] $DoNotOpenWebsite, 51 | [switch] $DoNotPlaySound, 52 | [switch] $DoNotUseBeep 53 | ) 54 | $Cache = [ordered] @{} 55 | $CurrentStock = Get-UnifiStockLegacy -Store $Store 56 | foreach ($Product in $CurrentStock) { 57 | $Cache[$Product.Name] = $Product 58 | $Cache[$Product.SKU] = $Product 59 | } 60 | 61 | [Array] $ApplicableProducts = @( 62 | foreach ($Name in $ProductName) { 63 | $Found = $false 64 | foreach ($StockName in $CurrentStock.Name) { 65 | if ($StockName -like "$Name") { 66 | $StockName 67 | $found = $true 68 | } 69 | } 70 | if (-not $Found) { 71 | Write-Color -Text "Product Name '$Name' not found in stock. Ignoring" -Color Red 72 | } 73 | } 74 | foreach ($Name in $ProductSKU) { 75 | if ($Name -in $CurrentStock.SKU) { 76 | $Name 77 | } else { 78 | Write-Color -Text "Product SKU '$Name' not found in stock. Ignoring" -Color Red 79 | } 80 | } 81 | ) 82 | if ($ApplicableProducts.Count -eq 0) { 83 | Write-Color -Text "No products requested by user not found on list of available products. Exiting" -Color Red 84 | return 85 | } 86 | 87 | $Collections = @( 88 | foreach ($Product in $ApplicableProducts) { 89 | $Cache[$Product].Category 90 | } 91 | ) | Select-Object -Unique 92 | 93 | Write-Color -Text "Setting up monitoring for ", ($ApplicableProducts -join ", ") -Color Yellow, Green 94 | $Count = 0 95 | Do { 96 | if ($Count -ne 0) { 97 | Start-Sleep -Seconds $Seconds 98 | } 99 | Write-Color -Text "Checking stock..." -Color Yellow 100 | $CurrentResults = Get-UnifiStockLegacy -Store $Store -Collection $Collections | Where-Object { 101 | $_.Name -in $ApplicableProducts -or $_.SKU -in $ApplicableProducts 102 | } | Sort-Object -Property Name 103 | Write-Color -Text "Checking stock... Done, sleeping for $Seconds seconds" -Color Green 104 | $Count++ 105 | } While ($CurrentResults.Available -notcontains $true) 106 | 107 | foreach ($Product in $CurrentResults | Where-Object { $_.Available -eq $true }) { 108 | Write-Color -Text "Product ", $($Product.Name), " is in stock! ", "SKU: $($Product.SKU)" -Color Yellow, Green, Yellow, Green 109 | 110 | if (-not $DoNotOpenWebsite) { 111 | Start-Process $Product.ProductUrl 112 | } 113 | 114 | if (-not $DoNotPlaySound) { 115 | try { 116 | $Voice = New-Object -ComObject Sapi.spvoice -ErrorAction Stop 117 | } catch { 118 | Write-Color -Text "Failed to create voice object. Error: $($_.Exception.Message)" -Color Red 119 | } 120 | if ($Voice) { 121 | # Set the speed - positive numbers are faster, negative numbers, slower 122 | $voice.rate = 0 123 | 124 | # Say something 125 | try { 126 | $null = $voice.speak("Hey,there is stock available for $($Product.Name)") 127 | } catch { 128 | Write-Color -Text "Failed to speak. Error: $($_.Exception.Message)" -Color Red 129 | } 130 | } 131 | } 132 | if (-not $DoNotUseBeep) { 133 | [console]::beep(500, 300) 134 | } 135 | } 136 | } -------------------------------------------------------------------------------- /Public/Wait-UnifiStock.ps1: -------------------------------------------------------------------------------- 1 | function Wait-UnifiStock { 2 | <# 3 | .SYNOPSIS 4 | When run waits for the specified SKU or Product to be in stock in Ubiquiti's online store. 5 | 6 | .DESCRIPTION 7 | When run waits for the specified SKU or Product to be in stock in Ubiquiti's online store. 8 | Once the product is in stock the function will play a beep, read which product is in stock and open a browser to specific product page. 9 | 10 | .PARAMETER ProductName 11 | One or more products to wait for to be in stock with search by it's Name 12 | 13 | .PARAMETER ProductSKU 14 | One or more products to wait for to be in stock with search by it's SKU 15 | 16 | .PARAMETER Store 17 | The store to check for stock. Valid values are Europe, USA and UK. 18 | If you want to use a different store you can use Wait-UnifiStockLegacy for other countries. 19 | This is because the legacy store has a different format for the JSON data, and are not yet migrated to new "look" 20 | 21 | .PARAMETER Seconds 22 | The number of seconds to wait between checks. Default is 60 seconds. 23 | 24 | .PARAMETER DoNotOpenWebsite 25 | If specified the website will not be opened when the product is in stock. 26 | 27 | .PARAMETER DoNotPlaySound 28 | If specified the sound will not be played when the product is in stock. 29 | 30 | .PARAMETER DoNotUseBeep 31 | If specified the beep will not be played when the product is in stock. 32 | 33 | .EXAMPLE 34 | Wait-UnifiStock -ProductSKU 'UDR-EU' -ProductName 'Switch Flex XG' -Seconds 60 -Store Europe 35 | 36 | .EXAMPLE 37 | Wait-UnifiStock -ProductName 'UniFi6 Mesh', 'G4 Doorbell Pro', 'Camera G4 Pro', 'Test' -Seconds 60 -Store Europe 38 | 39 | .EXAMPLE 40 | Wait-UnifiStock -ProductName 'UniFi6 Mesh', 'G4 Doorbell Pro', 'Camera G4 Pro', 'Test' -Seconds 60 -DoNotUseBeep -Store Europe 41 | 42 | .NOTES 43 | General notes 44 | #> 45 | [cmdletBinding()] 46 | param( 47 | [string[]] $ProductName, 48 | [string[]] $ProductSKU, 49 | [parameter(Mandatory)][ValidateSet('Europe', 'USA', 'UK')][string] $Store, 50 | [int] $Seconds = 60, 51 | [switch] $DoNotOpenWebsite, 52 | [switch] $DoNotPlaySound, 53 | [switch] $DoNotUseBeep 54 | ) 55 | $Cache = [ordered] @{} 56 | $CurrentStock = Get-UnifiStock -Store $Store 57 | foreach ($Product in $CurrentStock) { 58 | $Cache[$Product.Name] = $Product 59 | $Cache[$Product.SKU] = $Product 60 | } 61 | 62 | [Array] $ApplicableProducts = @( 63 | foreach ($Name in $ProductName) { 64 | $Found = $false 65 | foreach ($StockName in $CurrentStock.Name) { 66 | if ($StockName -like "$Name") { 67 | $StockName 68 | $found = $true 69 | } 70 | } 71 | if (-not $Found) { 72 | Write-Color -Text "Product Name '$Name' not found in stock. Ignoring" -Color Red 73 | } 74 | } 75 | foreach ($Name in $ProductSKU) { 76 | if ($Name -in $CurrentStock.SKU) { 77 | $Name 78 | } else { 79 | Write-Color -Text "Product SKU '$Name' not found in stock. Ignoring" -Color Red 80 | } 81 | } 82 | ) 83 | $ApplicableProducts = $ApplicableProducts | Sort-Object -Unique 84 | if ($ApplicableProducts.Count -eq 0) { 85 | Write-Color -Text "No products requested by user not found on list of available products. Exiting" -Color Red 86 | return 87 | } 88 | 89 | # $Collections = @( 90 | # foreach ($Product in $ApplicableProducts) { 91 | # $Cache[$Product].Category 92 | # } 93 | # ) | Select-Object -Unique 94 | 95 | Write-Color -Text "Setting up monitoring for ", ($ApplicableProducts -join ", ") -Color Yellow, Green 96 | $Count = 0 97 | Do { 98 | if ($Count -ne 0) { 99 | Start-Sleep -Seconds $Seconds 100 | } 101 | Write-Color -Text "Checking stock..." -Color Yellow 102 | $CurrentResults = Get-UnifiStock -Store $Store | Where-Object { 103 | $_.Name -in $ApplicableProducts -or $_.SKU -in $ApplicableProducts 104 | } | Sort-Object -Property Name 105 | Write-Color -Text "Checking stock... Done, sleeping for $Seconds seconds" -Color Green 106 | $Count++ 107 | } While ($CurrentResults.Available -notcontains $true) 108 | 109 | foreach ($Product in $CurrentResults | Where-Object { $_.Available -eq $true }) { 110 | Write-Color -Text "Product ", $($Product.Name), " is in stock! ", "SKU: $($Product.SKU)" -Color Yellow, Green, Yellow, Green 111 | 112 | if (-not $DoNotOpenWebsite) { 113 | Start-Process $Product.ProductUrl 114 | } 115 | 116 | if (-not $DoNotPlaySound) { 117 | try { 118 | $Voice = New-Object -ComObject Sapi.spvoice -ErrorAction Stop 119 | } catch { 120 | Write-Color -Text "Failed to create voice object. Error: $($_.Exception.Message)" -Color Red 121 | } 122 | if ($Voice) { 123 | # Set the speed - positive numbers are faster, negative numbers, slower 124 | $voice.rate = 0 125 | 126 | # Say something 127 | try { 128 | $null = $voice.speak("Hey,there is stock available for $($Product.Name)") 129 | } catch { 130 | Write-Color -Text "Failed to speak. Error: $($_.Exception.Message)" -Color Red 131 | } 132 | } 133 | } 134 | if (-not $DoNotUseBeep) { 135 | [console]::beep(500, 300) 136 | } 137 | } 138 | } -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # UnifiStockTracker - PowerShell Module 2 | 3 |

4 | 5 | 6 | 7 | 8 |

9 | 10 |

11 | 12 | 13 | 14 | 15 |

16 | 17 |

18 | 19 | 20 | 21 |

22 | 23 | `UnifiStockTracker` is a PowerShell module to get current stock on Europe, Brazil or USA Ubiquiti stores. 24 | Since I was constantly checking stock on Ubiquiti store waiting for specific products I decided to automate it. 25 | I know there are places doing the same thing such as: 26 | 27 | - [x] [Ubiquiti in-stock Spam Alerts](https://www.reddit.com/r/UbiquitiInStock/) 28 | 29 | But there is one problem - they monitor for every single product so you get a lot of spam. I wanted to monitor only for specific products, in my own time. So I created this module. 30 | 31 | You can find more about this module on my blog (this blog is outdated due to redesign of Ubiquiti store for US/EU, but still valid for all other shops), but provides some background information: 32 | - [Track Ubiquiti Unifi Stock, and get notified of changes](https://evotec.xyz/simplify-notifications-about-ubiquiti-unifi-stock/) 33 | 34 | ## Installation 35 | 36 | This module is available to install from PowerShellGallery which is enabled by default on Windows. 37 | 38 | ```powershell 39 | Install-Module -Name UnifiStockTracker -Scope CurrentUser -Verbose 40 | ``` 41 | 42 | ## Usage 43 | 44 | Due to Unifi store changes this module now contains 4 commands: 45 | 46 | - `Get-UnifiStock` - supporting only US/EU/UK stores 47 | - `Get-UnifiStockLegacy` - supporting all other stores 48 | - `Wait-UnifiStock` - supporting only US/EU/UK stores 49 | - `Wait-UnifiStockLegacy` - supporting all other stores 50 | 51 | Once redesign for all stores will be done I'll try to fix other stores and remove compatibility with old ones. 52 | 53 | ### Getting a list of products (non-EU, non-USA) stores 54 | 55 | Get all products from 3 categories in Brazil store, sort them by name and display 56 | 57 | ```powershell 58 | Get-UnifiStockLegacy -Store Brazil -Collection Protect, ProtectAccessories, ProtectNVR | Sort-Object -Property Name | Format-Table 59 | ``` 60 | 61 | Get all products from 2 categories in Brazil store, sort them by name and display 62 | 63 | ```powershell 64 | Get-UnifiStockLegacy -Store Brazil -Collection Protect, NetworkWifi | Sort-Object -Property Name | Format-Table 65 | ``` 66 | 67 | Get all products from India store, sort them by name and display 68 | 69 | ```powershell 70 | Get-UnifiStockLegacy -Store India | Sort-Object -Property Name | Format-Table 71 | ``` 72 | 73 | ### Waiting for specific products (non-EU, non-USA, non-UK) 74 | 75 | Wait for 4 products of which one will be ignored because it doesn't exists and recheck store every 60 seconds (Europe store is default) 76 | 77 | ```powershell 78 | Wait-UnifiStockLegacy -ProductName 'UniFi6 Mesh', 'G4 Doorbell Pro', 'Camera G4 Pro', 'Test' -Seconds 60 79 | ``` 80 | 81 | Wait for 1 product via specific SKU and recheck store every 60 seconds (Europe store is default) 82 | 83 | ```powershell 84 | Wait-UnifiStockLegacy -ProductSKU 'UDR-EU' -ProductName 'Switch Flex XG' -Seconds 60 85 | ``` 86 | 87 | ### Getting a list of products (EU, USA, UK) stores 88 | 89 | ```powershell 90 | Get-UnifiStock -Store Europe | Sort-Object -Property Name | Format-Table 91 | Get-UnifiStock -Store USA -Verbose | Sort-Object -Property Name | Format-Table 92 | 93 | Get-UnifiStock -Store USA -Collection AccessoriesCabling, CableBox | Sort-Object -Property Name | Format-Table 94 | Get-UnifiStock -Store Europe -Collection CameraSecurityDome360, CameraSecurityCompactPoEWired | Sort-Object -Property Name | Format-Table 95 | Get-UnifiStock -Store USA -Collection HostingAndGatewaysCloud,DreamMachine, DreamRouter | Sort-Object -Property Name | Format-Table 96 | ``` 97 | 98 | ### Waiting for specific products (EU, USA, UK) 99 | 100 | ```powershell 101 | Wait-UnifiStock -ProductName 'UniFi6 Mesh', 'G4 Doorbell Pro', 'Camera G4 Pro', 'Test' -Seconds 60 -Store USA 102 | Wait-UnifiStock -ProductSKU 'UDR-EU' -ProductName 'Switch Flex XG' -Seconds 60 -Store Europe 103 | Wait-UnifiStock -ProductName 'Access Point AC Lite' -Seconds 60 -Store Europe 104 | ``` 105 | -------------------------------------------------------------------------------- /Public/Get-UnifiStockLegacy.ps1: -------------------------------------------------------------------------------- 1 | function Get-UnifiStockLegacy { 2 | <# 3 | .SYNOPSIS 4 | Get the stock status of Ubiquiti products from their online store. 5 | 6 | .DESCRIPTION 7 | Get the stock status of Ubiquiti products from their online store. 8 | 9 | .PARAMETER Store 10 | The store to check for stock. Valid values are: Europe, USA, Brazil, India, Japan, Taiwan, Signapore, Mexico, China 11 | 12 | .PARAMETER Collection 13 | Which collection to list. 14 | 15 | .EXAMPLE 16 | Get-UnifiStock -Store USA -Collection Protect, ProtectAccessories, ProtectNVR | Sort-Object -Property Name | Format-Table 17 | 18 | .EXAMPLE 19 | Get-UnifiStock -Store Europe -Collection Protect, NetworkWifi | Sort-Object -Property Name | Format-Table 20 | 21 | .EXAMPLE 22 | Get-UnifiStock -Store Europe | Sort-Object -Property Name | Format-Table 23 | 24 | .NOTES 25 | General notes 26 | #> 27 | [cmdletbinding()] 28 | param( 29 | [ValidateSet('Brazil', 'India', 'Japan', 'Taiwan', 'Signapore', 'Mexico', 'China')] 30 | [Parameter(Mandatory)] 31 | [string] $Store, 32 | [ValidateSet( 33 | 'EarlyAccess', 34 | 'EarlyAccessConnect', 35 | 'EarlyAccessDoorAccess', 36 | 'EarlyAccessSmartpower', 37 | 'EarlyAccessUispFiber', 38 | 'EarlyAccessUispWired', 39 | 'EarlyAccessUispWireless', 40 | 'EarlyAccessUnifiNetworkHost', 41 | 'NetworkHost', 42 | 'NetworkOS', 43 | 'NetworkRoutingOffload', 44 | 'NetworkRoutingSwitching', 45 | 'NetworkSmartPower', 46 | 'NetworkSwitching', 47 | 'NetworkWifi', 48 | 'OperatorAirmaxAndLtu', 49 | 'OperatorIspInfrastructure', 50 | 'Protect', 51 | 'ProtectAccessories', 52 | 'ProtectNVR', 53 | 'UnifiAccessories', 54 | 'UnifiConnect', 55 | 'UnifiDoorAccess', 56 | 'UnifiPhoneSystem' 57 | )] 58 | [string[]] $Collection 59 | ) 60 | 61 | $Stores = @{ 62 | Europe = 'https://eu.store.ui.com' 63 | USA = 'https://store.ui.com' 64 | Brazil = 'https://br.store.ui.com' 65 | India = 'https://store-ui.in' 66 | Japan = 'https://jp.store.ui.com' 67 | Taiwan = 'https://tw.store.ui.com' 68 | Singapore = 'https://sg.store.ui.com' 69 | Mexico = 'https://mx.store.ui.com' 70 | China = 'https://store.ui.com.cn' 71 | } 72 | 73 | $Collections = @{ 74 | Protect = 'unifi-protect' 75 | ProtectNVR = 'unifi-protect-nvr' 76 | ProtectAccessories = 'unifi-protect-accessories' 77 | NetworkOS = 'unifi-network-unifi-os-consoles' 78 | NetworkRoutingSwitching = 'unifi-network-routing-switching' 79 | NetworkSmartPower = 'unifi-network-smartpower' 80 | NetworkRoutingOffload = 'unifi-network-routing-offload' 81 | NetworkHost = 'unifi-network-host' 82 | NetworkSwitching = 'unifi-network-switching' 83 | NetworkWifi = 'unifi-network-wireless' 84 | UnifiAccessories = 'unifi-accessories' 85 | EarlyAccess = 'early-access' 86 | EarlyAccessDoorAccess = 'early-access-door-access' 87 | EarlyAccessConnect = 'early-access-connect' 88 | EarlyAccessSmartpower = 'early-access-smartpower' 89 | EarlyAccessUispFiber = 'early-access-uisp-fiber' 90 | EarlyAccessUispWired = 'early-access-uisp-wired' 91 | EarlyAccessUispWireless = 'early-access-uisp-wireless' 92 | EarlyAccessUnifiNetworkHost = 'early-access-unifi-network-host' 93 | UnifiConnect = 'unifi-connect' 94 | UnifiDoorAccess = 'unifi-door-access' 95 | OperatorAirmaxAndLtu = 'operator-airmax -and -ltu' 96 | OperatorIspInfrastructure = 'operator-isp-infrastructure' 97 | UnifiPhoneSystem = 'unifi-phone-system' 98 | } 99 | 100 | $UrlStore = $Stores[$Store] 101 | 102 | if (-not $Collection) { 103 | $Collection = $Collections.Keys 104 | } 105 | 106 | foreach ($Category in $Collection) { 107 | $UrlCollection = $Collections[$Category] 108 | $Url = "$UrlStore/collections/$UrlCollection" 109 | $UrlProducts = "$Url/products.json" 110 | $ProgressPreference = 'SilentlyContinue' 111 | try { 112 | Write-Verbose -Message "Get-UnifiStock - Getting $UrlProducts" 113 | $Output = Invoke-WebRequest -Uri $UrlProducts -ErrorAction Stop -Verbose:$false 114 | } catch { 115 | Write-Color -Text "Unable to get $UrlProducts. Error: $($_.Exception.Message)" -Color Red 116 | return 117 | } 118 | if ($Output) { 119 | $OutputJSON = $Output.Content | ConvertFrom-Json 120 | $UnifiProducts = foreach ($Product in $OutputJSON.products) { 121 | foreach ($Variant in $Product.variants) { 122 | try { 123 | $DateCreated = [DateTime]::Parse($Variant.created_at) 124 | #$DateCreated = [DateTime]::ParseExact($Variant.created_at, 'yyyy-MM-ddTHH:mm:sszzz', $null) 125 | } catch { 126 | Write-Verbose -Message "Unable to parse date: $($Variant.created_at). Skipping" 127 | $DateCreated = $null 128 | } 129 | try { 130 | $DateUpdated = [DateTime]::Parse($Variant.updated_at) 131 | #$DateUpdated = [DateTime]::ParseExact($Variant.updated_at, 'yyyy-MM-ddTHH:mm:sszzz', $null) 132 | } catch { 133 | Write-Verbose -Message "Unable to parse date: $($Variant.updated_at). Skipping" 134 | $DateUpdated = $null 135 | } 136 | [PSCustomObject] @{ 137 | Name = $Product.title 138 | Available = $Variant.available 139 | Category = $Category 140 | Price = $Variant.price 141 | SKU = $Variant.sku 142 | SKUName = $Variant.title 143 | #Inventory = $Variant.inventory_quantity 144 | Created = $DateCreated 145 | Updated = $DateUpdated 146 | ProductUrl = "$Url/products/$($Product.handle)" 147 | Tags = $Product.tags 148 | } 149 | } 150 | } 151 | $UnifiProducts 152 | } 153 | } 154 | } -------------------------------------------------------------------------------- /Public/Get-UnifiStock.ps1: -------------------------------------------------------------------------------- 1 | function Get-UnifiStock { 2 | <# 3 | .SYNOPSIS 4 | Get the stock status of Ubiquiti products from their online store. 5 | 6 | .DESCRIPTION 7 | Get the stock status of Ubiquiti products from their online store. 8 | 9 | .PARAMETER Store 10 | The store to check for stock. Valid values are: Europe, USA, UK 11 | If you want to use a different store you can use Get-UnifiStockLegacy for other countries. 12 | This is because the legacy store has a different format for the JSON data, and are not yet migrated to new "look" 13 | 14 | .PARAMETER Collection 15 | Which collection to list. 16 | 17 | .EXAMPLE 18 | Get-UnifiStock -Store USA -Collection AccessoriesCabling, CableBox | Sort-Object -Property Name | Format-Table 19 | 20 | .EXAMPLE 21 | Get-UnifiStock -Store Europe -Collection HostingAndGatewaysCloud,DreamMachine, DreamRouter | Sort-Object -Property Name | Format-Table 22 | 23 | .EXAMPLE 24 | Get-UnifiStock -Store Europe | Sort-Object -Property Name | Format-Table 25 | 26 | .NOTES 27 | General notes 28 | #> 29 | [cmdletbinding()] 30 | param( 31 | [ValidateSet('Europe', 'USA', 'UK')] 32 | [Parameter(Mandatory)][string] $Store, 33 | [ValidateSet( 34 | 'AccessoriesCabling', 35 | 'AccessPointMounting', 36 | 'AccessPointSkins', 37 | 'CableBox', 38 | 'CablePatch', 39 | 'CableSFP', 40 | 'CameraEnhancers', 41 | 'CameraSecurityBulletDSLR', 42 | 'CameraSecurityBulletHighPerformance', 43 | 'CameraSecurityBulletStandard', 44 | 'CameraSecurityCompactPoEWired', 45 | 'CameraSecurityCompactWiFiConnected', 46 | 'CameraSecurityDome360', 47 | 'CameraSecurityDomeSlim', 48 | 'CameraSecurityDoorAccessAccessories', 49 | 'CameraSecurityDoorAccessReaders', 50 | 'CameraSecurityDoorAccessStarterKit', 51 | 'CameraSecurityInteriorDesign', 52 | 'CameraSecurityNVRLargeScale', 53 | 'CameraSecurityNVRMidScale', 54 | 'CameraSecurityPTZ', 55 | 'CameraSecuritySpecialChime', 56 | 'CameraSecuritySpecialSensor', 57 | 'CameraSecuritySpecialViewport', 58 | 'CameraSecuritySpecialWiFiDoorbell', 59 | 'CameraSkins', 60 | 'DesktopStands', 61 | 'DeviceMounting', 62 | 'DreamMachine', 63 | 'DreamRouter', 64 | 'HDDStorage', 65 | 'HostingAndGatewaysCloud', 66 | 'HostingAndGatewaysLargeScale', 67 | 'HostingAndGatewaysSmallScale', 68 | 'InstallationsRackmount', 69 | 'InternetBackup', 70 | 'NewIntegrationsAVDisplayMounting', 71 | 'NewIntegrationsAVGiantPoETouchscreens', 72 | 'NewIntegrationsPhoneATA', 73 | 'NewIntegrationsPhoneCompact', 74 | 'NewIntegrationsPhoneExecutive', 75 | 'PoEAndPower', 76 | 'PoEPower', 77 | 'PowerTechPowerRedundancy', 78 | 'PowerTechUninterruptiblePoE', 79 | 'SwitchingEnterpriseAggregation', 80 | 'SwitchingEnterprisePoE', 81 | 'SwitchingProEthernet', 82 | 'SwitchingProPoE', 83 | 'SwitchingStandardEthernet', 84 | 'SwitchingStandardPoE', 85 | 'SwitchingUtility10GbpsEthernet', 86 | 'SwitchingUtilityMini', 87 | 'SwitchingUtilityPoE', 88 | 'WiFiBuildingBridge10Gigabit', 89 | 'WiFiFlagshipCompact', 90 | 'WiFiFlagshipHighCapacity', 91 | 'WiFiInWallOutletMesh', 92 | 'WiFiMan', 93 | 'WiFiOutdoorFlexible', 94 | 'WiFiFlagshipLongRange', 95 | 'WiFiOutdoorLongRange', 96 | "NewIntegrationsMobileRouting", 97 | "CameraSecurityDoorAccessHub", 98 | "NewIntegrationsAVDigitalSignage", 99 | "SwitchingUtilityIndustrial", 100 | "SwitchingUtilityIndoorOutdoor", 101 | "SwitchingEnterprise10GbpsEthernet", 102 | "SwitchingUtilityHiPowerPoE", 103 | "WiFiMegaCapacity", 104 | "PowerTechUninterruptiblePower", 105 | "PowerTechPowerDistribution", 106 | "CameraSecuritySpecialFloodlight", 107 | "DreamWall", 108 | "NewIntegrationsEVCharging", 109 | "CloudKeyRackMount", 110 | "AmpliFiMesh", 111 | "AmpliFiAlien", 112 | "WiFiInWallCompact", 113 | "WiFiInWallHighCapacity", 114 | "AccessPointAntennas", 115 | "CameraSecurityBulletEnhancedAI", 116 | "WiFiBuildingBridgeGigabit", 117 | # organizational collections 118 | "Cabling", "AccessPointMounting", "AccessPointSkins", 119 | "CableSFP", "CameraEnhancers", "CameraSkins", "DeviceMounting", "DisplayMounting", 120 | "HostingAndGatewaysCloud", "HostingAndGatewaysLargeScale", "HostingAndGatewaysSmallScale", 121 | "PoEAndPower", "PoEPower", "WiFiManager", "InternetBackup", "PowerRedundancy", 122 | "ProEthernetSwitching", "StandardEthernetSwitching", "StandardPoESwitching", 123 | "10GbpsEthernetSwitching", "PoESwitching", 124 | "FlagshipCompactWiFi", "FlagshipHighCapacityWiFi", "InWallHighCapacityWiFi", "OutdoorFlexibleWiFi", "UICare" 125 | )][string[]] $Collection 126 | ) 127 | 128 | $Stores = @{ 129 | Europe = 'eu' 130 | USA = 'us' 131 | UK = 'uk' 132 | } 133 | 134 | $StoreLinks = @{ 135 | Europe = 'https://eu.store.ui.com/eu/en' 136 | USA = 'https://store.ui.com/us/en' 137 | UK = 'https://uk.store.ui.com/uk/en' 138 | } 139 | 140 | $Accessories = @{ 141 | # direct collections 142 | "uisp-accessories-cabling" = "AccessoriesCabling" 143 | "unifi-accessory-tech-access-point-mounting" = "AccessPointMounting" 144 | "unifi-accessory-tech-access-point-skins" = "AccessPointSkins" 145 | "unifi-accessory-tech-cable-box" = "CableBox" 146 | "unifi-accessory-tech-cable-patch" = "CablePatch" 147 | "unifi-accessory-tech-cable-sfp" = "CableSFP" 148 | "unifi-accessory-tech-camera-enhancers" = "CameraEnhancers" 149 | "unifi-accessory-tech-camera-skins" = "CameraSkins" 150 | "unifi-accessory-tech-desktop-stands" = "DesktopStands" 151 | "unifi-accessory-tech-device-mounting" = "DeviceMounting" 152 | "unifi-accessory-tech-hdd-storage" = "HDDStorage" 153 | "unifi-accessory-tech-hosting-and-gateways-cloud" = "HostingAndGatewaysCloud" 154 | "unifi-accessory-tech-hosting-and-gateways-large-scale" = "HostingAndGatewaysLargeScale" 155 | "unifi-accessory-tech-hosting-and-gateways-small-scale" = "HostingAndGatewaysSmallScale" 156 | "unifi-accessory-tech-installations-rackmount" = "InstallationsRackmount" 157 | "unifi-accessory-tech-poe-and-power" = "PoEAndPower" 158 | "unifi-accessory-tech-poe-power" = "PoEPower" 159 | "unifi-accessory-tech-wifiman" = "WiFiMan" 160 | "unifi-camera-security-bullet-dslr" = "CameraSecurityBulletDSLR" 161 | "unifi-camera-security-bullet-high-performance" = "CameraSecurityBulletHighPerformance" 162 | "unifi-camera-security-bullet-standard" = "CameraSecurityBulletStandard" 163 | "unifi-camera-security-compact-poe-wired" = "CameraSecurityCompactPoEWired" 164 | "unifi-camera-security-compact-wifi-connected" = "CameraSecurityCompactWiFiConnected" 165 | "unifi-camera-security-dome-360" = "CameraSecurityDome360" 166 | "unifi-camera-security-dome-slim" = "CameraSecurityDomeSlim" 167 | "unifi-camera-security-door-access-accessories" = "CameraSecurityDoorAccessAccessories" 168 | "unifi-camera-security-door-access-readers" = "CameraSecurityDoorAccessReaders" 169 | "unifi-camera-security-door-access-starter-kit" = "CameraSecurityDoorAccessStarterKit" 170 | "unifi-camera-security-interior-design" = "CameraSecurityInteriorDesign" 171 | "unifi-camera-security-nvr-large-scale" = "CameraSecurityNVRLargeScale" 172 | "unifi-camera-security-nvr-mid-scale" = "CameraSecurityNVRMidScale" 173 | "unifi-camera-security-ptz" = "CameraSecurityPTZ" 174 | "unifi-camera-security-special-chime" = "CameraSecuritySpecialChime" 175 | "unifi-camera-security-special-sensor" = "CameraSecuritySpecialSensor" 176 | "unifi-camera-security-special-viewport" = "CameraSecuritySpecialViewport" 177 | "unifi-camera-security-special-wifi-doorbell" = "CameraSecuritySpecialWiFiDoorbell" 178 | "unifi-dream-machine" = "DreamMachine" 179 | "unifi-dream-router" = "DreamRouter" 180 | "unifi-internet-backup" = "InternetBackup" 181 | "unifi-new-integrations-av-display-mounting" = "NewIntegrationsAVDisplayMounting" 182 | "unifi-new-integrations-av-giant-poe-touchscreens" = "NewIntegrationsAVGiantPoETouchscreens" 183 | "unifi-new-integrations-phone-ata" = "NewIntegrationsPhoneATA" 184 | "unifi-new-integrations-phone-compact" = "NewIntegrationsPhoneCompact" 185 | "unifi-new-integrations-phone-executive" = "NewIntegrationsPhoneExecutive" 186 | "unifi-power-tech-power-redundancy" = "PowerTechPowerRedundancy" 187 | "unifi-power-tech-uninterruptible-poe" = "PowerTechUninterruptiblePoE" 188 | "unifi-switching-enterprise-aggregation" = "SwitchingEnterpriseAggregation" 189 | "unifi-switching-enterprise-power-over-ethernet" = "SwitchingEnterprisePoE" 190 | "unifi-switching-pro-ethernet" = "SwitchingProEthernet" 191 | "unifi-switching-pro-power-over-ethernet" = "SwitchingProPoE" 192 | "unifi-switching-standard-ethernet" = "SwitchingStandardEthernet" 193 | "unifi-switching-standard-power-over-ethernet" = "SwitchingStandardPoE" 194 | "unifi-switching-utility-10-gbps-ethernet" = "SwitchingUtility10GbpsEthernet" 195 | "unifi-switching-utility-mini" = "SwitchingUtilityMini" 196 | "unifi-switching-utility-poe" = "SwitchingUtilityPoE" 197 | "unifi-wifi-building-bridge-10-gigabit" = "WiFiBuildingBridge10Gigabit" 198 | "unifi-wifi-flagship-compact" = "WiFiFlagshipCompact" 199 | "unifi-wifi-flagship-high-capacity" = "WiFiFlagshipHighCapacity" 200 | "unifi-wifi-inwall-outlet-mesh" = "WiFiInWallOutletMesh" 201 | "unifi-wifi-outdoor-flexible" = "WiFiOutdoorFlexible" 202 | "unifi-wifi-flagship-long-range" = "WiFiFlagshipLongRange" 203 | "unifi-wifi-outdoor-long-range" = "WiFiOutdoorLongRange" 204 | 205 | "unifi-new-integrations-mobile-routing" = "NewIntegrationsMobileRouting" 206 | "unifi-camera-security-door-access-hub" = "CameraSecurityDoorAccessHub" 207 | "unifi-new-integrations-av-digital-signage" = "NewIntegrationsAVDigitalSignage" 208 | "unifi-switching-utility-industrial" = "SwitchingUtilityIndustrial" 209 | "unifi-switching-utility-indoor-outdoor" = "SwitchingUtilityIndoorOutdoor" 210 | "unifi-switching-enterprise-10-gbps-ethernet" = "SwitchingEnterprise10GbpsEthernet" 211 | "unifi-switching-utility-hi-power-poe" = "SwitchingUtilityHiPowerPoE" 212 | "unifi-wifi-mega-capacity" = "WiFiMegaCapacity" 213 | "unifi-power-tech-uninterruptible-power" = "PowerTechUninterruptiblePower" 214 | "unifi-power-tech-power-distribution" = "PowerTechPowerDistribution" 215 | "unifi-camera-security-special-floodlight" = "CameraSecuritySpecialFloodlight" 216 | "unifi-dream-wall" = "DreamWall" 217 | "unifi-new-integrations-ev-charging" = "NewIntegrationsEVCharging" 218 | "cloud-key-rack-mount" = "CloudKeyRackMount" 219 | "amplifi-mesh" = "AmpliFiMesh" 220 | "amplifi-alien" = "AmpliFiAlien" 221 | "unifi-wifi-inwall-compact" = "WiFiInWallCompact" 222 | "unifi-wifi-inwall-high-capacity" = "WiFiInWallHighCapacity" 223 | "unifi-accessory-tech-access-point-antennas" = "AccessPointAntennas" 224 | "unifi-camera-security-bullet-enhanced-ai" = "CameraSecurityBulletEnhancedAI" 225 | "unifi-wifi-building-bridge-gigabit" = "WiFiBuildingBridgeGigabit" 226 | 227 | # organizational collection 228 | "accessories-cabling" = "Cabling" 229 | "accessory-tech-access-point-mounting" = "AccessPointMounting" 230 | "accessory-tech-access-point-skins" = "AccessPointSkins" 231 | "accessory-tech-cable-sfp" = "CableSFP" 232 | "accessory-tech-camera-enhancers" = "CameraEnhancers" 233 | "accessory-tech-camera-skins" = "CameraSkins" 234 | "accessory-tech-device-mounting" = "DeviceMounting" 235 | "accessory-tech-display-mounting" = "DisplayMounting" 236 | "accessory-tech-hosting-and-gateways-cloud" = "HostingAndGatewaysCloud" 237 | "accessory-tech-hosting-and-gateways-large-scale" = "HostingAndGatewaysLargeScale" 238 | "accessory-tech-hosting-and-gateways-small-scale" = "HostingAndGatewaysSmallScale" 239 | "accessory-tech-poe-and-power" = "PoEAndPower" 240 | "accessory-tech-poe-power" = "PoEPower" 241 | "accessory-tech-wifiman" = "WiFiManager" 242 | "internet-backup" = "InternetBackup" 243 | "power-tech-power-redundancy" = "PowerRedundancy" 244 | "switching-pro-ethernet" = "ProEthernetSwitching" 245 | "switching-standard-ethernet" = "StandardEthernetSwitching" 246 | "switching-standard-power-over-ethernet" = "StandardPoESwitching" 247 | "switching-utility-10-gbps-ethernet" = "10GbpsEthernetSwitching" 248 | "switching-utility-poe" = "PoESwitching" 249 | "wifi-flagship-compact" = "FlagshipCompactWiFi" 250 | "wifi-flagship-high-capacity" = "FlagshipHighCapacityWiFi" 251 | "wifi-inwall-high-capacity" = "InWallHighCapacityWiFi" 252 | "wifi-outdoor-flexible" = "OutdoorFlexibleWiFi" 253 | 254 | "ui-care" = "UICare" 255 | } 256 | 257 | $UrlStore = $Stores[$Store] 258 | $UrlStoreLink = $StoreLinks[$Store] 259 | 260 | $ProgressPreference = 'SilentlyContinue' 261 | try { 262 | Write-Verbose -Message "Get-UnifiStock - Getting Unifi products" 263 | 264 | $invokeRestMethodSplat = @{ 265 | UseBasicParsing = $true 266 | Uri = "https://ecomm.svc.ui.com/graphql" 267 | Method = 'Post' 268 | ContentType = "application/json" 269 | } 270 | 271 | $Limit = 250 272 | $Offset = 0 273 | $Total = 1 274 | 275 | $Products = while ($offset -lt $total) { 276 | 277 | $Body = [ordered] @{ 278 | operationName = "GetProductsForLandingPagePro" 279 | variables = @{ 280 | input = @{ 281 | limit = $Limit 282 | offset = $Offset 283 | filter = @{ 284 | storeId = "$UrlStore" 285 | language = "en" 286 | line = "Unifi" 287 | } 288 | } 289 | } 290 | query = @" 291 | query GetProductsForLandingPagePro(`$input: StorefrontProductListInput!) { 292 | storefrontProducts(input: `$input) { 293 | pagination { 294 | limit 295 | offset 296 | total 297 | __typename 298 | } 299 | items { 300 | ...LandingProProductFragment 301 | __typename 302 | } 303 | __typename 304 | } 305 | } 306 | 307 | fragment LandingProProductFragment on StorefrontProduct { 308 | id 309 | title 310 | shortTitle 311 | name 312 | slug 313 | collectionSlug 314 | organizationalCollectionSlug 315 | shortDescription 316 | tags { 317 | name 318 | __typename 319 | } 320 | gallery { 321 | ...ImageOnlyGalleryFragment 322 | __typename 323 | } 324 | options { 325 | id 326 | title 327 | values { 328 | id 329 | title 330 | __typename 331 | } 332 | __typename 333 | } 334 | variants { 335 | id 336 | sku 337 | status 338 | title 339 | galleryItemIds 340 | isEarlyAccess 341 | optionValueIds 342 | displayPrice { 343 | ...MoneyFragment 344 | __typename 345 | } 346 | hasPurchaseHistory 347 | __typename 348 | } 349 | __typename 350 | } 351 | 352 | fragment ImageOnlyGalleryFragment on Gallery { 353 | id 354 | items { 355 | id 356 | data { 357 | __typename 358 | ... on Asset { 359 | id 360 | mimeType 361 | url 362 | height 363 | width 364 | __typename 365 | } 366 | } 367 | __typename 368 | } 369 | type 370 | __typename 371 | } 372 | 373 | fragment MoneyFragment on Money { 374 | amount 375 | currency 376 | __typename 377 | } 378 | "@ 379 | } 380 | $invokeRestMethodSplat.Body = $Body | ConvertTo-Json -Depth 10 381 | $Output = Invoke-RestMethod @invokeRestMethodSplat 382 | $CurrentProducts = $Output.data.storefrontProducts.items 383 | $CurrentProducts 384 | $Pagination = $Output.data.storefrontProducts.pagination 385 | $total = $pagination.total 386 | $offset += $limit 387 | } 388 | } catch { 389 | Write-Color -Text "Unable to get Unifi products. Error: $($_.Exception.Message)" -Color Red 390 | return 391 | } 392 | if ($Products) { 393 | Write-Verbose -Message "Get-UnifiStock - Got $($Products.Count) products" 394 | $UnifiProducts = foreach ($Product in $Products) { 395 | foreach ($Variant in $Product.variants) { 396 | if ($Product.collectionSlug) { 397 | $Category = $Accessories[$Product.collectionSlug] 398 | } elseif ($Product.organizationalCollectionSlug) { 399 | $Category = $Accessories[$Product.organizationalCollectionSlug] 400 | } else { 401 | $Category = 'Unknown' 402 | } 403 | if ($Collection) { 404 | if ($Category -notin $Collection) { 405 | continue 406 | } 407 | } 408 | [PSCustomObject] @{ 409 | Name = $Product.title 410 | ShortName = $Product.shortTitle 411 | Available = $Variant.status -eq 'AVAILABLE' 412 | Category = $Category 413 | Collection = $Product.collectionSlug 414 | OrganizationalCollectionSlug = $Product.organizationalCollectionSlug 415 | SKU = $Variant.sku 416 | SKUName = $Variant.title 417 | EarlyAccess = $Variant.isEarlyAccess 418 | ProductUrl = "$UrlStoreLink/collections/$($Product.collectionSlug)/products/$($Product.slug)" 419 | #Tags = $Product.tags 420 | } 421 | } 422 | } 423 | $UnifiProducts 424 | } 425 | } --------------------------------------------------------------------------------