1616. PARAMETER AssetId
1717 Asset ID to pin or unpin. Required for ByAssetId parameter set.
1818
19+ . PARAMETER OUPath
20+ Organizational Unit (OU) path to pin or unpin all assets within. Required for ByOuPath parameter set.
21+
1922. PARAMETER DeploymentClusterId
20- Deployment cluster ID to pin/unpin assets to. Required for ByAssetId parameter set .
23+ Deployment cluster ID to pin/unpin assets to. Required for ByAssetId and ByOuPath parameter sets .
2124
2225. PARAMETER Unpin
23- Switch to unpin assets instead of pinning them. Available for ByAssetId and ByCsvPath parameter sets.
26+ Switch to unpin assets instead of pinning them. Available for ByAssetId, ByOuPath, and ByCsvPath parameter sets.
2427
2528. PARAMETER SkipSegmentServerValidation
26- Skip validation that deployment clusters have online segment servers. Available for ByAssetId and ByCsvPath parameter sets.
29+ Skip validation that deployment clusters have online segment servers. Available for ByAssetId, ByOuPath, and ByCsvPath parameter sets.
2730
2831. PARAMETER DryRun
29- Preview changes without applying them. Available for ByAssetId and ByCsvPath parameter sets.
32+ Preview changes without applying them. Available for ByAssetId, ByOuPath, and ByCsvPath parameter sets.
3033
3134. PARAMETER ListDeploymentClusters
3235 Switch to list all deployment clusters with detailed information.
5255. EXAMPLE
5356 .\Pin-AssetsToClusters.ps1 -ApiKey "your-api-key" -CsvPath ".\assets.csv" -DryRun
5457 Previews what changes would be made without actually applying them.
58+
59+ . EXAMPLE
60+ .\Pin-AssetsToClusters.ps1 -ApiKey "your-api-key" -OUPath "OU=Computers,DC=domain,DC=com" -DeploymentClusterId "C:d:00fd409f"
61+ Pins all assets within the specified OU path to a deployment cluster.
5562#>
5663
5764<# PSScriptInfo
6673param (
6774 # Shared parameter for sets that require authentication
6875 [Parameter (ParameterSetName = " ByAssetId" , Mandatory = $true )]
76+ [Parameter (ParameterSetName = " ByOuPath" , Mandatory = $true )]
6977 [Parameter (ParameterSetName = " ListDeploymentClusters" , Mandatory = $true )]
7078 [Parameter (ParameterSetName = " ByCsvPath" , Mandatory = $true )]
7179 [string ]$ApiKey ,
7280
7381 [Parameter (ParameterSetName = " ByAssetId" , Mandatory = $false )]
82+ [Parameter (ParameterSetName = " ByOuPath" , Mandatory = $false )]
7483 [Parameter (ParameterSetName = " ListDeploymentClusters" , Mandatory = $false )]
7584 [Parameter (ParameterSetName = " ByCsvPath" , Mandatory = $false )]
7685 [string ]$PortalUrl = " https://portal.zeronetworks.com" ,
@@ -79,21 +88,29 @@ param(
7988 [Parameter (ParameterSetName = " ByAssetId" , Mandatory = $true )]
8089 [string ]$AssetId ,
8190
91+ # ParameterSet: Pin by OU Path and Deployment Cluster ID
92+ [Parameter (ParameterSetName = " ByOuPath" , Mandatory = $true )]
93+ [string ]$OUPath ,
94+
8295 [Parameter (ParameterSetName = " ByAssetId" , Mandatory = $true )]
96+ [Parameter (ParameterSetName = " ByOuPath" , Mandatory = $true )]
8397 [string ]$DeploymentClusterId ,
8498
85- # Shared switch parameter for unpinning (available in ByAssetId and ByCsvPath sets)
99+ # Shared switch parameter for unpinning (available in ByAssetId, ByOuPath, and ByCsvPath sets)
86100 [Parameter (ParameterSetName = " ByAssetId" )]
101+ [Parameter (ParameterSetName = " ByOuPath" )]
87102 [Parameter (ParameterSetName = " ByCsvPath" )]
88103 [switch ]$Unpin ,
89104
90105 # Shared switch parameter to skip segment server validation (available in all sets with ApiKey)
91106 [Parameter (ParameterSetName = " ByAssetId" , Mandatory = $false )]
107+ [Parameter (ParameterSetName = " ByOuPath" , Mandatory = $false )]
92108 [Parameter (ParameterSetName = " ByCsvPath" , Mandatory = $false )]
93109 [switch ]$SkipSegmentServerValidation ,
94110
95111 # Shared switch parameter for dry run mode (available in all sets with ApiKey)
96112 [Parameter (ParameterSetName = " ByAssetId" , Mandatory = $false )]
113+ [Parameter (ParameterSetName = " ByOuPath" , Mandatory = $false )]
97114 [Parameter (ParameterSetName = " ByCsvPath" , Mandatory = $false )]
98115 [switch ]$DryRun ,
99116
@@ -316,6 +333,60 @@ function Get-AssetDetails {
316333 }
317334}
318335
336+ <#
337+ . SYNOPSIS
338+ Retrieves all assets within a specified Organizational Unit (OU) path from the Zero Networks API.
339+ . PARAMETER OUPath
340+ The OU path to retrieve assets for.
341+ . OUTPUTS
342+ Returns an array of asset entity objects that match the OU path.
343+ . NOTES
344+ Throws an exception if no assets are found or if the API response is malformed.
345+ #>
346+ function Get-AssetsByOUPath {
347+ param (
348+ [Parameter (Mandatory = $true )]
349+ [string ]$OUPath
350+ )
351+ Write-Host " Getting assets for OU path: $OUPath "
352+ try {
353+ # Query assets API with OU path filter
354+ $FilterArray = @ (
355+ @ {
356+ id = " name"
357+ includesValues = @ (
358+ $OUPath
359+ )
360+ }
361+ )
362+ $FilterJson = $FilterArray | ConvertTo-Json - Compress - AsArray
363+ $response = Invoke-ApiRequest - Method " GET" - ApiEndpoint " assets?_limit=1&_filter=$FilterJson "
364+
365+ # Validate response structure
366+ if ($null -eq $response.items ) {
367+ throw " Assets response is malformed and does not contain 'items' property"
368+ }
369+
370+ # Ensure items is an array (handle single item responses)
371+ if ($response.items -isnot [System.Array ]) {
372+ $assets = @ ($response.items )
373+ }
374+ else {
375+ $assets = $response.items
376+ }
377+
378+ if ($assets.Count -eq 0 ) {
379+ throw " No assets found for OU path: $OUPath "
380+ }
381+
382+ Write-Host " Found $ ( $assets.Count ) assets for OU path: $OUPath "
383+ return $assets
384+ }
385+ catch {
386+ throw " Failed to retrieve assets for OU path $OUPath : $_ "
387+ }
388+ }
389+
319390<#
320391 . SYNOPSIS
321392 Pins or unpins assets to a deployment cluster via the Zero Networks API.
@@ -879,6 +950,53 @@ switch ($PSCmdlet.ParameterSetName) {
879950
880951 Write-Host " $ ( $DryRun ? " [DRY RUN] " : ' ' ) Finished workflow to $ ( $Unpin ? " unpin" : " pin" ) asset $AssetId to deployment cluster $DeploymentClusterId "
881952 }
953+ " ByOuPath" {
954+ Write-Host " $ ( $DryRun ? " [DRY RUN] " : ' ' ) Starting workflow to $ ( $Unpin ? " unpin" : " pin" ) assets in OU path $OUPath to deployment cluster $DeploymentClusterId "
955+ Initialize-ApiContext
956+
957+
958+ # Validate deployment cluster exists and has online segment servers
959+ Invoke-ValidateDeploymentClusterId - DeploymentClusterId $DeploymentClusterId - SkipSegmentServerValidation:$SkipSegmentServerValidation
960+
961+ # Get assets by OU path
962+ $assets = Get-AssetsByOUPath - OUPath $OUPath
963+
964+ # Extract asset IDs from assets array
965+ $assetIds = $assets | ForEach-Object { $_.id }
966+
967+ # Validate each asset can be pinned/unpinned
968+ foreach ($assetId in $assetIds ) {
969+ Test-AssetCanBePinned - AssetId $assetId - AssetMustBePinned:$Unpin
970+ }
971+ Write-Host " Validated that all assets can be $ ( $Unpin ? " unpinned" : " pinned" ) to deployment cluster"
972+
973+ $totalAssets = $assetIds.Count
974+ Write-Host " $ ( $Unpin ? " Unpinning" : " Pinning" ) $totalAssets assets to deployment cluster $ ( $script :DeploymentClusterHashtable [$DeploymentClusterId ].name) "
975+
976+ # Batch processing for large asset lists (>50 assets)
977+ if ($totalAssets -gt 50 ) {
978+ $batchSize = 50
979+ $batchNumber = 1
980+ $totalBatches = [math ]::Ceiling($totalAssets / $batchSize )
981+
982+ for ($i = 0 ; $i -lt $totalAssets ; $i += $batchSize ) {
983+ # Create batch using array slicing
984+ $batch = $assetIds [$i .. ([math ]::Min($i + $batchSize - 1 , $totalAssets - 1 ))]
985+ Write-Host " Processing batch $batchNumber of $totalBatches ($ ( $batch.Count ) assets)..."
986+ Set-AssetsToDeploymentCluster - AssetIdsArray $batch - DeploymentClusterId $DeploymentClusterId - Unpin:$Unpin - DryRun:$DryRun
987+ if (-not $DryRun ) {
988+ Write-Host " Successfully $ ( $Unpin ? " unpinned" : " pinned" ) $ ( $batch.Count ) assets to deployment cluster $ ( $script :DeploymentClusterHashtable [$DeploymentClusterId ].name) "
989+ }
990+ $batchNumber ++
991+ }
992+ }
993+ else {
994+ # Process all assets at once for smaller lists
995+ Set-AssetsToDeploymentCluster - AssetIdsArray $assetIds - DeploymentClusterId $DeploymentClusterId - Unpin:$Unpin - DryRun:$DryRun
996+ }
997+
998+ Write-Host " $ ( $DryRun ? " [DRY RUN] " : ' ' ) Finished workflow to $ ( $Unpin ? " unpin" : " pin" ) assets in OU path $OUPath to deployment cluster $DeploymentClusterId "
999+ }
8821000 " ByCsvPath" {
8831001 Write-Host " $ ( $DryRun ? " [DRY RUN] " : ' ' ) Starting workflow to $ ( $Unpin ? " unpin" : " pin" ) assets from CSV file $CsvPath "
8841002 Initialize-ApiContext
0 commit comments