Get-ADOArtifactFeed.ps1
function Get-ADOArtifactFeed { <# .Synopsis Gets artifact feeds from Azure DevOps .Description Gets artifact feeds from Azure DevOps. Artifact feeds can be used to publish packages. .Link https://docs.microsoft.com/en-us/rest/api/azure/devops/artifacts/feed%20%20management/get%20feeds?view=azure-devops-rest-5.1 .Example Get-ADOArtifactFeed -Organization myOrganization -Project MyProject #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSPossibleIncorrectComparisonWithNull", "", Justification="Explicitly checking for nulls")] [CmdletBinding(DefaultParameterSetName='packaging/Feeds/{FeedId}')] [OutputType('PSDevOps.ArtfiactFeed', 'PSDevOps.ArtfiactFeed.View', 'PSDevOps.ArtfiactFeed.Change')] param( # The Organization [Parameter(Mandatory,ValueFromPipelineByPropertyName)] [Alias('Org')] [string] $Organization, # The Project [Parameter(ValueFromPipelineByPropertyName)] [string] $Project, # The name or ID of the feed. [Parameter(ValueFromPipelineByPropertyName)] [Alias('fullyQualifiedId')] [string] $FeedID, # If set, will Get Artifact Feed Views [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/Feeds/{feedID}/views')] [Alias('Views')] [switch] $View, # If set, will get artifact permissions [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/Feeds/{feedID}/permissions')] [Alias('Permissions')] [switch] $Permission, # If set, will get artifact retention policies [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/Feeds/{feedID}/retentionpolicies')] [Alias('RetentionPolicies')] [switch] $RetentionPolicy, # If set, will list versions of a particular package. [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/Feeds/{feedID}/packages/{packageId}/versions')] [Alias('ListVersions','ListVersion','PackageVersions')] [switch] $PackageVersionList, # If set, will get provenance for a package version [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/Feeds/{feedId}/Packages/{packageId}/Versions/{VersionId}/provenance')] [switch] $Provenance, # A package version ID. Only required when getting version provenance. [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/Feeds/{feedId}/Packages/{packageId}/Versions/{VersionId}/provenance')] [string] $VersionID, # If set, will list packages within a feed. [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/Feeds/{feedID}/packages')] [Alias('ListPackages','ListPackage','Packages')] [switch] $PackageList, # If set, will include all versions of packages within a feed. [Parameter(ValueFromPipelineByPropertyName,ParameterSetName='packaging/Feeds/{feedID}/packages')] [Alias('IncludeAllVersions')] [switch] $IncludeAllVersion, # If set, will include descriptions of a package. [Parameter(ValueFromPipelineByPropertyName,ParameterSetName='packaging/Feeds/{feedID}/packages')] [switch] $IncludeDescription, # If provided, will return packages of a given protocol. [Parameter(ValueFromPipelineByPropertyName,ParameterSetName='packaging/Feeds/{feedID}/packages')] [string] $ProtocolType, # If set, will get information about a Node Package Manager module. [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/feeds/{feedId}/npm/{packageName}/versions/{packageVersion}')] [Alias('NodePackageManager')] [switch] $NPM, # If set, will get information about a Nuget module. [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/feeds/{feedId}/nuget/packages/{packageName}/versions/{packageVersion}')] [switch] $NuGet, # If set, will get information about a Python module. [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/feeds/{feedId}/pypi/packages/{packageName}/versions/{packageVersion}')] [Alias('PyPi')] [switch] $Python, # If set, will get information about a Universal package module. [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/feeds/{feedId}/upack/packages/{packageName}/versions/{packageVersion}')] [Alias('UPack')] [switch] $Universal, # The Package Name. Must be used with -NPM, -NuGet, -Python, or -Universal. [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/feeds/{feedId}/upack/packages/{packageName}/versions/{packageVersion}')] [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/feeds/{feedId}/npm/{packageName}/versions/{packageVersion}')] [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/feeds/{feedId}/nuget/packages/{packageName}/versions/{packageVersion}')] [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/feeds/{feedId}/pypi/packages/{packageName}/versions/{packageVersion}')] [Parameter(ValueFromPipelineByPropertyName,ParameterSetName='packaging/Feeds/{feedID}/packages')] [string] $PackageName, # The Package Version. Must be used with -NPM, -NuGet, -Python, or -Universal. [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/feeds/{feedId}/upack/packages/{packageName}/versions/{packageVersion}')] [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/feeds/{feedId}/npm/{packageName}/versions/{packageVersion}')] [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/feeds/{feedId}/nuget/packages/{packageName}/versions/{packageVersion}')] [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/feeds/{feedId}/pypi/packages/{packageName}/versions/{packageVersion}')] [string] $PackageVersion, # The Feed Role [Parameter(ValueFromPipelineByPropertyName,ParameterSetName='packaging/Feeds')] [ValidateSet('Administrator','Collaborator', 'Contributor','Reader')] [string] $FeedRole, # A -PackageID. This can be used to get Packages -Metrics, -ListPackageVersion, or get -Provenance of a particular version. [Parameter(Mandatory,ValueFromPipelineByPropertyName,ParameterSetName='packaging/Feeds/{feedId}/packagemetricsbatch')] [string] $PackageID, # If set, will get package metrics. [Parameter(Mandatory,ParameterSetName='packaging/Feeds/{feedId}/packagemetricsbatch')] [Alias('Metrics')] [switch] $Metric, # If set, will include deleted feeds. [switch] $IncludeDeleted, # If set, will get changes in artifact feeds. [Alias('Changes')] [switch] $Change, # The server. By default https://feeds.dev.azure.com/. [uri] $Server = "https://feeds.dev.azure.com/", # The api version. By default, 5.1-preview. [string] $ApiVersion = "5.1-preview") dynamicParam { Invoke-ADORestAPI -DynamicParameter } begin { #region Copy Invoke-ADORestAPI parameters $invokeParams = Invoke-ADORestAPI -MapParameter $PSBoundParameters #endregion Copy Invoke-ADORestAPI parameters $q = [Collections.Queue]::new() } process { $in = $_ $ParameterSet = $psCmdlet.ParameterSetName $q.Enqueue(@{ParameterSet=$ParameterSet;InputObject=$in} + $PSBoundParameters) } end { $c, $t, $id = 0, $q.Count, [Random]::new().Next() $metricsBatches = @{} :nextInputObject while ($q.Count) { . $DQ $q # Pop one off the queue and declare all of it's variables (see /parts/DQ.ps1). # First, construct a base URI. It's made up of: $uriBase = "$Server".TrimEnd('/'), # * The server $Organization, # * The organization $(if ($Project) { $project}) -ne $null -join # * an optional project '/' $subTypeName = '' if ($Change) { # If we're looking for changes, $subtypeName = '.Change' if (-not $FeedID) { # but haven't specified feed $uri = $uriBase, "_apis/packaging/feedchanges?" -join '/' } elseif ($Change) { $uri = $uriBase, "_apis/packaging/feeds/$FeedID", 'packagechanges?' -join '/' } } elseif (-not $Change) { $uriParameters = [Regex]::Replace($PSCmdlet.ParameterSetName, '/\{(?<Variable>\w+)\}', {param($match) $var = $ExecutionContext.SessionState.PSVariable.Get($match.Groups['Variable'].ToString()) if ($null -ne $var.Value) { return '/' + ($var.Value.ToString()) } else { return '' } }, 'IgnoreCase,IgnorePatternWhitespace') $uri = $uriBase, '_apis', $uriParameters -join '/' # Next, add on the REST api endpoint $uri += '?' } foreach ($typeSwitch in 'View', 'Permission', 'RetentionPolicy', 'NPM', 'Nuget','Python', 'Universal') { if ($PSBoundParameters.$typeSwitch -and -not $FeedID) { $splat = @{} + $PSBoundParameters $splat.Remove($typeSwitch) $splat2 = if ('NPM', 'NuGet', 'Python', 'Universal' -contains $typeSwitch) { $splat.Remove('PackageName') $splat.Remove('PackageVersion') $splat + @{$typeSwitch=$true;PackageName=$PackageName;PackageVersion=$PackageVersion} } else { $splat + @{$typeSwitch=$true} } Get-ADOArtifactFeed @splat | & { process { $feedID = $_.FullyQualifiedID $_ | Get-ADOArtifactFeed @splat2 | Add-Member NoteProperty FeedID $feedID -Force -PassThru } } continue nextInputObject } elseif ($PSBoundParameters.$typeSwitch) { $subtypeName = ".$typeSwitch" } } if ($Server -ne 'https://feeds.dev.azure.com/' -and -not $PSBoundParameters.ApiVersion) { $ApiVersion = '2.0' } $qp = @{"api-version"=$ApiVersion} if ($FeedRole) { $qp.feedRole = $FeedRole.ToLower() } if ($IncludeDeleted) { if ($packageList) { $qp.includeDeleted = $true } else { $qp.includeDeletedUpstreams = $true } } if ($PackageName -and $PackageList) { $qp.PackageName = $PackageName } if ($IncludeDescription) { $qp.includeDescription = $true } if ($IncludeAllVersion) { $qp.includeAllVersions = $true } if ($ProtocolType) { $qp.protocolType = $ProtocolType } $invokeParams.Uri = $uri if ($PackageList) { $subTypeName = '.Package' if (-not $invokeParams.DecorateProperty) { $invokeParams.DecorateProperty = @{} } $invokeParams.DecorateProperty['Versions'] = @( if ($Organization -and $Project) { "$Organization.$Project.ArtifactFeed.PackageVersion" } "$Organization.ArtifactFeed.PackageVersion" "PSDevOps.ArtifactFeed.PackageVersion" ) } if ($PackageVersionList) { $subTypeName = '.PackageVersion' } if ($Metric) { $subTypeName = '.PackageMetric' } $typenames = @( # Prepare a list of typenames so we can customize formatting: if ($Organization -and $Project) { "$Organization.$Project.ArtifactFeed$subtypeName" # * $Organization.$Project.ArtifactFeed (if $product exists) } "$Organization.ArtifactFeed$subtypeName" # * $Organization.ArtifactFeed "PSDevOps.ArtifactFeed$subtypeName" # * PSDevOps.ArtifactFeed ) $additionalProperty = @{Organization=$Organization;Server=$Server} if ($Project) { $additionalProperty['Project'] = $Project } $invokeParams.Property = $additionalProperty if (-not $subTypeName) { $invokeParams.RemoveProperty = 'ViewID','ViewName' } else { $invokeParams.Property["FeedID"] = if ($FeedID) { $FeedID } elseif ($inputObject.feedId) { $inputobject.FeedID} } if ($inputObject.packageID) { if ($inputObject.name) { $invokeParams.Property["PackageName"] = $inputObject.name } $inputObject.Property["PackageID"] = $inputObject.PackageID } $invokeParams.PSTypename = $typenames $invokeParams.QueryParameter = $qp if ($parameterSet -eq 'packaging/Feeds/{feedId}/packagemetricsbatch') { # If we want to get metrics in a batch, let's batch if (-not $metricsBatches["$($invokeParams.Uri)"]) { $metricsBatches["$($invokeParams.Uri)"] = @() } $metricsBatches["$($invokeParams.Uri)"] += @{Method='POST';Body=@{packageIds=$PackageID}} + $invokeParams continue nextInputObject } if ($t -gt 1 -and $ProgressPreference -ne 'silentlyContinue') { $c++ Write-Progress "Getting $(@($ParameterSet -split '/' -notlike '{*}')[-1])" "$($invokeParams.Uri) " -Id $id -PercentComplete ($c * 100/$t) } # Invoke the REST api Invoke-ADORestAPI @invokeParams # decorate results with the Typenames. } if ($metricsBatches.Count) { $c, $t = 0, $metricsBatches.Count foreach ($batch in $metricsBatches.GetEnumerator()) { $packageIdBatch = @(foreach ($val in $batch.Value) { $val.body.packageIDs }) $packageNamesBatch = @(foreach ($val in $batch.Value) { $val.property.PackageName }) $ip = $batch.Value[0] $ip.body.packageIDs = $packageIdBatch if ($t -gt 1 -and $ProgressPreference -ne 'silentlyContinue') { $c++ Write-Progress "Getting $(@($ParameterSet -split '/' -notlike '{*}')[-1])" "$($invokeParams.Uri) " -Id $id -PercentComplete ($c * 100/$t) } $rc = 0 # Invoke the REST api Invoke-ADORestAPI @IP | & { process { $_.PackageName = $packageNamesBatch[$rc] $rc++ $_ } } } } if ($t -gt 1 -and $ProgressPreference -ne 'silentlyContinue') { Write-Progress "Getting $(@($ParameterSet -split '/' -notlike '{*}')[-1])" "$($invokeParams.Uri) " -Id $id -Completed } } } |