vsteam.functions.ps1
# Apply types to the returned objects so format and type files can # identify the object and act on it. function _applyTypes { param( $item, $type ) $item.PSObject.TypeNames.Insert(0, $type) } function _applyTypesWorkItemType { param($item) $item.PSObject.TypeNames.Insert(0, 'Team.WorkItemType') } function _applyTypesToWorkItem { param($item) # If there are ids in the list that don't map to a work item and empty # entry is returned in its place if ErrorPolicy is Omit. if ($item) { $item.PSObject.TypeNames.Insert(0, 'Team.WorkItem') } } function _applyTypesToWiql { param($item) if ($item) { $item.PSObject.TypeNames.Insert(0, 'Team.Wiql') } } function _applyTypesToUser { param( [Parameter(Mandatory = $true)] $item ) $item.PSObject.TypeNames.Insert(0, 'Team.UserEntitlement') $item.accessLevel.PSObject.TypeNames.Insert(0, 'Team.AccessLevel') } function _applyTypesToTfvcBranch { param($item) $item.PSObject.TypeNames.Insert(0, 'Team.TfvcBranch') } function _applyTypesToTeamMember { param( [Parameter(Mandatory = $true)] $item, [Parameter(Mandatory = $true)] $team, [Parameter(Mandatory = $true)] $ProjectName ) # Add the team name as a NoteProperty so we can use it further down the pipeline (it's not returned from the REST call) $item | Add-Member -MemberType NoteProperty -Name Team -Value $team $item | Add-Member -MemberType NoteProperty -Name ProjectName -Value $ProjectName $item.PSObject.TypeNames.Insert(0, 'Team.TeamMember') } function _applyTypesToApproval { param($item) $item.PSObject.TypeNames.Insert(0, 'Team.Approval') } function _applyTypesToBuild { param($item) $item.PSObject.TypeNames.Insert(0, 'Team.Build') $item.logs.PSObject.TypeNames.Insert(0, 'Team.Logs') $item._links.PSObject.TypeNames.Insert(0, 'Team.Links') $item.project.PSObject.TypeNames.Insert(0, 'Team.Project') $item.requestedBy.PSObject.TypeNames.Insert(0, 'Team.User') $item.requestedFor.PSObject.TypeNames.Insert(0, 'Team.User') $item.lastChangedBy.PSObject.TypeNames.Insert(0, 'Team.User') $item.repository.PSObject.TypeNames.Insert(0, 'Team.Repository') $item.definition.PSObject.TypeNames.Insert(0, 'Team.BuildDefinition') if ($item.PSObject.Properties.Match('queue').count -gt 0 -and $null -ne $item.queue) { $item.queue.PSObject.TypeNames.Insert(0, 'Team.Queue') } if ($item.PSObject.Properties.Match('orchestrationPlan').count -gt 0 -and $null -ne $item.orchestrationPlan) { $item.orchestrationPlan.PSObject.TypeNames.Insert(0, 'Team.OrchestrationPlan') } } function _applyArtifactTypes { $item.PSObject.TypeNames.Insert(0, "Team.Build.Artifact") if ($item.PSObject.Properties.Match('resource').count -gt 0 -and $null -ne $item.resource -and $item.resource.PSObject.Properties.Match('propeties').count -gt 0) { $item.resource.PSObject.TypeNames.Insert(0, 'Team.Build.Artifact.Resource') $item.resource.properties.PSObject.TypeNames.Insert(0, 'Team.Build.Artifact.Resource.Properties') } } function _applyTypesToAzureSubscription { param($item) $item.PSObject.TypeNames.Insert(0, 'Team.AzureSubscription') } function _applyTypesToPolicy { param($item) $item.PSObject.TypeNames.Insert(0, 'Team.Policy') } function _applyTypesToPolicyType { param($item) $item.PSObject.TypeNames.Insert(0, 'Team.PolicyType') } function _applyTypesToPullRequests { param($item) $item.PSObject.TypeNames.Insert(0, 'Team.PullRequest') } function _applyTypesToRelease { param($item) $item.PSObject.TypeNames.Insert(0, 'Team.Release') if ($item.PSObject.Properties.Match('environments').count -gt 0 -and $null -ne $item.environments) { foreach ($e in $item.environments) { $e.PSObject.TypeNames.Insert(0, 'Team.Environment') } } $item._links.PSObject.TypeNames.Insert(0, 'Team.Links') $item._links.self.PSObject.TypeNames.Insert(0, 'Team.Link') $item._links.web.PSObject.TypeNames.Insert(0, 'Team.Link') } function _applyTypesToServiceEndpoint { param($item) $item.PSObject.TypeNames.Insert(0, 'Team.ServiceEndpoint') $item.createdBy.PSObject.TypeNames.Insert(0, 'Team.User') $item.authorization.PSObject.TypeNames.Insert(0, 'Team.authorization') $item.data.PSObject.TypeNames.Insert(0, 'Team.ServiceEndpoint.Details') if ($item.PSObject.Properties.Match('operationStatus').count -gt 0 -and $null -ne $item.operationStatus) { # This is VSTS $item.operationStatus.PSObject.TypeNames.Insert(0, 'Team.OperationStatus') } } function _applyTypesToServiceEndpointType { param($item) $item.PSObject.TypeNames.Insert(0, 'Team.ServiceEndpointType') $item.inputDescriptors.PSObject.TypeNames.Insert(0, 'Team.InputDescriptor[]') foreach ($inputDescriptor in $item.inputDescriptors) { $inputDescriptor.PSObject.TypeNames.Insert(0, 'Team.InputDescriptor') } $item.authenticationSchemes.PSObject.TypeNames.Insert(0, 'Team.AuthenticationScheme[]') foreach ($authenticationScheme in $item.authenticationSchemes) { $authenticationScheme.PSObject.TypeNames.Insert(0, 'Team.AuthenticationScheme') } if ($item.PSObject.Properties.Match('dataSources').count -gt 0 -and $null -ne $item.dataSources) { $item.dataSources.PSObject.TypeNames.Insert(0, 'Team.DataSource[]') foreach ($dataSource in $item.dataSources) { $dataSource.PSObject.TypeNames.Insert(0, 'Team.DataSource') } } } function _applyTypesToVariableGroup { param($item) $item.PSObject.TypeNames.Insert(0, 'Team.VariableGroup') $item.createdBy.PSObject.TypeNames.Insert(0, 'Team.User') $item.modifiedBy.PSObject.TypeNames.Insert(0, 'Team.User') if ($item.PSObject.Properties.Match('providerData').count -gt 0 -and $null -ne $item.providerData) { $item.providerData.PSObject.TypeNames.Insert(0, 'Team.ProviderData') } $item.variables.PSObject.TypeNames.Insert(0, 'Team.Variables') } function _applyTypesToYamlPipelineResultType { param($item) $item.PSObject.TypeNames.Insert(0, 'Team.YamlPipelineResult') } function _callMembershipAPI { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string] $Id, [ValidateSet('Get', 'Post', 'Patch', 'Delete', 'Options', 'Put', 'Default', 'Head', 'Merge', 'Trace')] [string] $Method, [ValidateSet('', 'Up', 'Down')] [string] $Direction ) Set-StrictMode -Version Latest # This will throw if this account does not support the graph API _supportsGraph Write-Verbose "Getting members for $Id" $query = @{} if ($Direction) { $query['direction'] = $Direction } # Call the REST API $resp = _callAPI -Area 'graph' -Resource 'memberships' ` -Id $Id ` -SubDomain "vssps" ` -Method $Method ` -Version $([VSTeamVersions]::Graph) ` -QueryString $query return $resp } Set-StrictMode -Version Latest $here = Split-Path -Parent $MyInvocation.MyCommand.Path [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "It is used in other files")] $profilesPath = "$HOME/vsteam_profiles.json" # Not all versions support the name features. function _supportsGraph { _hasAccount if ($false -eq $(_testGraphSupport)) { throw 'This account does not support the graph API.' } } function _testGraphSupport { if (-not [VSTeamVersions]::Graph) { return $false } return $true } function _supportsFeeds { _hasAccount if ($false -eq $(_testFeedSupport)) { throw 'This account does not support packages.' } } function _testFeedSupport { if (-not [VSTeamVersions]::Packaging) { return $false } return $true } function _supportsSecurityNamespace { _hasAccount if (([VSTeamVersions]::Version -ne "VSTS") -and ([VSTeamVersions]::Version -ne "AzD")) { throw 'Security Namespaces are currently only supported in Azure DevOps Service (Online)' } } function _supportsMemberEntitlementManagement { _hasAccount if (-not [VSTeamVersions]::MemberEntitlementManagement) { throw 'This account does not support Member Entitlement.' } } function _testAdministrator { $user = [Security.Principal.WindowsIdentity]::GetCurrent() (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) } function _getInstance { return [VSTeamVersions]::Account } function _hasAccount { if (-not $(_getInstance)) { throw 'You must call Set-VSTeamAccount before calling any other functions in this module.' } } function _buildRequestURI { [CmdletBinding()] param( [string]$team, [string]$resource, [string]$area, [string]$id, [string]$version, [string]$subDomain, [object]$queryString ) DynamicParam { _buildProjectNameDynamicParam -Mandatory $false } process { _hasAccount # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $sb = New-Object System.Text.StringBuilder $sb.Append($(_addSubDomain -subDomain $subDomain -instance $(_getInstance))) | Out-Null if ($ProjectName) { $sb.Append("/$projectName") | Out-Null } if ($team) { $sb.Append("/$team") | Out-Null } $sb.Append("/_apis") | Out-Null if ($area) { $sb.Append("/$area") | Out-Null } if ($resource) { $sb.Append("/$resource") | Out-Null } if ($id) { $sb.Append("/$id") | Out-Null } if ($version) { $sb.Append("?api-version=$version") | Out-Null } $url = $sb.ToString() if ($queryString) { foreach ($key in $queryString.keys) { $Url += _appendQueryString -name $key -value $queryString[$key] } } return $url } } function _handleException { param( [Parameter(Position = 1)] $ex ) $handled = $false if ($ex.Exception.PSObject.Properties.Match('Response').count -gt 0 -and $null -ne $ex.Exception.Response -and $ex.Exception.Response.StatusCode -ne "BadRequest") { $handled = $true $msg = "An error occurred: $($ex.Exception.Message)" Write-Warning -Message $msg } try { $e = (ConvertFrom-Json $ex.ToString()) $hasValueProp = $e.PSObject.Properties.Match('value') if (0 -eq $hasValueProp.count) { $handled = $true Write-Warning -Message $e.message } else { $handled = $true Write-Warning -Message $e.value.message } } catch { $msg = "An error occurred: $($ex.Exception.Message)" } if (-not $handled) { throw $ex } } function _isVSTS { param( [parameter(Mandatory = $true)] [string] $instance ) return $instance -like "*.visualstudio.com*" -or $instance -like "https://dev.azure.com/*" } function _getVSTeamAPIVersion { param( [parameter(Mandatory = $true)] [string] $instance, [string] $Version ) if ($Version) { return $Version } else { if (_isVSTS $instance) { return 'VSTS' } else { return 'TFS2017' } } } function _isOnWindows { $os = Get-OperatingSystem return $os -eq 'Windows' } function _addSubDomain { param( [string] $subDomain, [string] $instance ) # For VSTS Entitlements is under .vsaex if ($subDomain -and $instance.ToLower().Contains('dev.azure.com')) { $instance = $instance.ToLower().Replace('dev.azure.com', "$subDomain.dev.azure.com") } return $instance } function _appendQueryString { param( $name, $value, # When provided =0 will be outputed otherwise zeros will not be # added. I had to add this for the userentitlements that is the only # VSTS API I have found that requires Top and Skip to be passed in. [Switch]$retainZero ) if ($retainZero.IsPresent) { if ($null -ne $value) { return "&$name=$value" } } else { if ($value) { return "&$name=$value" } } } function _getUserAgent { [CmdletBinding()] param() $os = Get-OperatingSystem $result = "Team Module/$([VSTeamVersions]::ModuleVersion) ($os) PowerShell/$($PSVersionTable.PSVersion.ToString())" Write-Verbose $result return $result } function _useWindowsAuthenticationOnPremise { return (_isOnWindows) -and (!$env:TEAM_PAT) -and -not ($(_getInstance) -like "*visualstudio.com") -and -not ($(_getInstance) -like "https://dev.azure.com/*") } function _useBearerToken { return (!$env:TEAM_PAT) -and ($env:TEAM_TOKEN) } function _getWorkItemTypes { param( [Parameter(Mandatory = $true)] [string] $ProjectName ) if (-not $(_getInstance)) { Write-Output @() return } # Call the REST API try { $resp = _callAPI -ProjectName $ProjectName -area 'wit' -resource 'workitemtypes' -version $([VSTeamVersions]::Core) # This call returns JSON with "": which causes the ConvertFrom-Json to fail. # To replace all the "": with "_end": $resp = $resp.Replace('"":', '"_end":') | ConvertFrom-Json if ($resp.count -gt 0) { Write-Output ($resp.value).name } } catch { Write-Verbose $_ Write-Output @() } } function _getProjects { if (-not $(_getInstance)) { Write-Output @() return } $resource = "/projects" $instance = $(_getInstance) $version = [VSTeamVersions]::Core # Build the url to list the projects # You CANNOT use _buildRequestURI here or you will end up # in an infinite loop. $listurl = $instance + '/_apis' + $resource + '?api-version=' + $version + '&stateFilter=All&$top=9999' # Call the REST API try { $resp = _callAPI -url $listurl if ($resp.count -gt 0) { Write-Output ($resp.value).name } } catch { Write-Output @() } } function _buildProjectNameDynamicParam { param( [string] $ParameterName = 'ProjectName', [string] $ParameterSetName, [bool] $Mandatory = $true, [string] $AliasName, [int] $Position = 0 ) # Create the dictionary $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary # Create the collection of attributes $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] # Create and set the parameters' attributes $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute $ParameterAttribute.Mandatory = $Mandatory $ParameterAttribute.Position = $Position if ($ParameterSetName) { $ParameterAttribute.ParameterSetName = $ParameterSetName } $ParameterAttribute.ValueFromPipelineByPropertyName = $true $ParameterAttribute.HelpMessage = "The name of the project. You can tab complete from the projects in your Team Services or TFS account when passed on the command line." # Add the attributes to the attributes collection $AttributeCollection.Add($ParameterAttribute) if ($AliasName) { $AliasAttribute = New-Object System.Management.Automation.AliasAttribute(@($AliasName)) $AttributeCollection.Add($AliasAttribute) } # Generate and set the ValidateSet if ($([VSTeamProjectCache]::timestamp) -ne (Get-Date).Minute) { $arrSet = _getProjects [VSTeamProjectCache]::projects = $arrSet [VSTeamProjectCache]::timestamp = (Get-Date).Minute } else { $arrSet = [VSTeamProjectCache]::projects } if ($arrSet) { Write-Verbose "arrSet = $arrSet" $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet) # Add the ValidateSet to the attributes collection $AttributeCollection.Add($ValidateSetAttribute) } # Create and return the dynamic parameter $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection) $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter) return $RuntimeParameterDictionary <# Builds a dynamic parameter that can be used to tab complete the ProjectName parameter of functions from a list of projects from the added TFS Account. You must call Set-VSTeamAccount before trying to use any function that relies on this dynamic parameter or you will get an error. This can only be used in Advanced Fucntion with the [CmdletBinding()] attribute. The function must also have a begin block that maps the value to a common variable like this. DynamicParam { # Generate and set the ValidateSet $arrSet = Get-VSTeamProjects | Select-Object -ExpandProperty Name _buildProjectNameDynamicParam -arrSet $arrSet } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters[$ParameterName] } #> } function _getProcesses { if (-not $(_getInstance)) { Write-Output @() return } # Call the REST API try { $query = @{} $query['stateFilter'] = 'All' $query['$top'] = '9999' $resp = _callAPI -area 'process' -resource 'processes' -Version $([VSTeamVersions]::Core) -QueryString $query if ($resp.count -gt 0) { Write-Output ($resp.value).name } } catch { Write-Output @() } } function _buildProcessNameDynamicParam { param( [string] $ParameterName = 'ProcessName', [string] $ParameterSetName, [bool] $Mandatory = $true, [string] $AliasName, [int] $Position = 0 ) # Create the dictionary $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary # Create the collection of attributes $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] # Create and set the parameters' attributes $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute $ParameterAttribute.Mandatory = $Mandatory $ParameterAttribute.Position = $Position if ($ParameterSetName) { $ParameterAttribute.ParameterSetName = $ParameterSetName } $ParameterAttribute.ValueFromPipelineByPropertyName = $true $ParameterAttribute.HelpMessage = "The name of the process. You can tab complete from the processes in your Team Services or TFS account when passed on the command line." # Add the attributes to the attributes collection $AttributeCollection.Add($ParameterAttribute) if ($AliasName) { $AliasAttribute = New-Object System.Management.Automation.AliasAttribute(@($AliasName)) $AttributeCollection.Add($AliasAttribute) } # Generate and set the ValidateSet if ($([VSTeamProcessCache]::timestamp) -ne (Get-Date).Minute) { $arrSet = _getProcesses [VSTeamProcessCache]::processes = $arrSet [VSTeamProcessCache]::timestamp = (Get-Date).Minute } else { $arrSet = [VSTeamProcessCache]::projects } if ($arrSet) { Write-Verbose "arrSet = $arrSet" $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet) # Add the ValidateSet to the attributes collection $AttributeCollection.Add($ValidateSetAttribute) } # Create and return the dynamic parameter $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection) $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter) return $RuntimeParameterDictionary <# Builds a dynamic parameter that can be used to tab complete the ProjectName parameter of functions from a list of projects from the added TFS Account. You must call Set-VSTeamAccount before trying to use any function that relies on this dynamic parameter or you will get an error. This can only be used in Advanced Fucntion with the [CmdletBinding()] attribute. The function must also have a begin block that maps the value to a common variable like this. DynamicParam { # Generate and set the ValidateSet $arrSet = Get-VSTeamProjects | Select-Object -ExpandProperty Name _buildProjectNameDynamicParam -arrSet $arrSet } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters[$ParameterName] } #> } function _buildDynamicParam { param( [string] $ParameterName = 'QueueName', [array] $arrSet, [bool] $Mandatory = $false, [string] $ParameterSetName, [int] $Position = -1, [type] $ParameterType = [string], [bool] $ValueFromPipelineByPropertyName = $true, [string] $AliasName, [string] $HelpMessage ) # Create the collection of attributes $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER ParameterName Parameter description .PARAMETER ParameterSetName Parameter description .PARAMETER Mandatory Parameter description .PARAMETER AliasName Parameter description .PARAMETER Position Parameter description .EXAMPLE An example .NOTES General notes #> # Create and set the parameters' attributes $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute $ParameterAttribute.Mandatory = $Mandatory $ParameterAttribute.ValueFromPipelineByPropertyName = $ValueFromPipelineByPropertyName if ($Position -ne -1) { $ParameterAttribute.Position = $Position } if ($ParameterSetName) { $ParameterAttribute.ParameterSetName = $ParameterSetName } if ($HelpMessage) { $ParameterAttribute.HelpMessage = $HelpMessage } # Add the attributes to the attributes collection $AttributeCollection.Add($ParameterAttribute) if ($AliasName) { $AliasAttribute = New-Object System.Management.Automation.AliasAttribute(@($AliasName)) $AttributeCollection.Add($AliasAttribute) } if ($arrSet) { # Generate and set the ValidateSet $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet) # Add the ValidateSet to the attributes collection $AttributeCollection.Add($ValidateSetAttribute) } # Create and return the dynamic parameter return New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, $ParameterType, $AttributeCollection) } function _convertSecureStringTo_PlainText { [CmdletBinding()] param( [parameter(ParameterSetName = 'Secure', Mandatory = $true, HelpMessage = 'Secure String')] [securestring] $SecureString ) # Convert the securestring to a normal string # this was the one technique that worked on Mac, Linux and Windows $credential = New-Object System.Management.Automation.PSCredential 'unknown', $SecureString return $credential.GetNetworkCredential().Password } # This is the main function for calling TFS and VSTS. It handels the auth and format of the route. # If you need to call TFS or VSTS this is the function to use. function _callAPI { param( [string]$resource, [string]$area, [string]$id, [string]$version, [string]$subDomain, [ValidateSet('Get', 'Post', 'Patch', 'Delete', 'Options', 'Put', 'Default', 'Head', 'Merge', 'Trace')] [string]$method, [Parameter(ValueFromPipeline = $true)] [object]$body, [string]$InFile, [string]$OutFile, [string]$ContentType, [string]$ProjectName, [string]$Team, [string]$Url, [object]$QueryString, [hashtable]$AdditionalHeaders ) # If the caller did not provide a Url build it. if (-not $Url) { $buildUriParams = @{ } + $PSBoundParameters; $extra = 'method', 'body', 'InFile', 'OutFile', 'ContentType', 'AdditionalHeaders' foreach ($x in $extra) { $buildUriParams.Remove($x) | Out-Null } $Url = _buildRequestURI @buildUriParams } elseif ($QueryString) { # If the caller provided the URL and QueryString we need # to add the querystring now foreach ($key in $QueryString.keys) { $Url += _appendQueryString -name $key -value $QueryString[$key] } } if ($body) { Write-Verbose "Body $body" } $params = $PSBoundParameters $params.Add('Uri', $Url) $params.Add('UserAgent', (_getUserAgent)) if (_useWindowsAuthenticationOnPremise) { $params.Add('UseDefaultCredentials', $true) $params.Add('Headers', @{}) } elseif (_useBearerToken) { $params.Add('Headers', @{Authorization = "Bearer $env:TEAM_TOKEN" }) } else { $params.Add('Headers', @{Authorization = "Basic $env:TEAM_PAT" }) } if ($AdditionalHeaders -and $AdditionalHeaders.PSObject.Properties.name -match "Keys") { foreach ($key in $AdditionalHeaders.Keys) { $params['Headers'].Add($key, $AdditionalHeaders[$key]) } } # We have to remove any extra parameters not used by Invoke-RestMethod $extra = 'Area', 'Resource', 'SubDomain', 'Id', 'Version', 'JSON', 'ProjectName', 'Team', 'Url', 'QueryString', 'AdditionalHeaders' foreach ($e in $extra) { $params.Remove($e) | Out-Null } try { $resp = Invoke-RestMethod @params if ($resp) { Write-Verbose "return type: $($resp.gettype())" Write-Verbose $resp } return $resp } catch { _handleException $_ throw } } function _trackProjectProgress { param( [Parameter(Mandatory = $true)] $Resp, [string] $Title, [string] $Msg ) $i = 0 $x = 1 $y = 10 $status = $resp.status # Track status while ($status -ne 'failed' -and $status -ne 'succeeded') { $status = (_callAPI -Url $resp.url).status # oscillate back a forth to show progress $i += $x Write-Progress -Activity $title -Status $msg -PercentComplete ($i / $y * 100) if ($i -eq $y -or $i -eq 0) { $x *= -1 } } } $iTracking = 0 $xTracking = 1 $yTracking = 10 $statusTracking = $null function _trackServiceEndpointProgress { param( [Parameter(Mandatory = $true)] [string] $projectName, [Parameter(Mandatory = $true)] $resp, [string] $title, [string] $msg ) $iTracking = 0 $xTracking = 1 $yTracking = 10 $isReady = $false # Track status while (-not $isReady) { $statusTracking = _callAPI -ProjectName $projectName -Area 'distributedtask' -Resource 'serviceendpoints' -Id $resp.id ` -Version $([VSTeamVersions]::DistributedTask) $isReady = $statusTracking.isReady; if (-not $isReady) { $state = $statusTracking.operationStatus.state if ($state -eq "Failed") { throw $statusTracking.operationStatus.statusMessage } } # oscillate back a forth to show progress $iTracking += $xTracking Write-Progress -Activity $title -Status $msg -PercentComplete ($iTracking / $yTracking * 100) if ($iTracking -eq $yTracking -or $iTracking -eq 0) { $xTracking *= -1 } } } function _supportsServiceFabricEndpoint { if (-not [VSTeamVersions]::ServiceFabricEndpoint) { throw 'This account does not support Service Fabric endpoints.' } } function _getModuleVersion { # Read the version from the psd1 file. # $content = (Get-Content -Raw "./VSTeam.psd1" | Out-String) $content = (Get-Content -Raw "$here\VSTeam.psd1" | Out-String) $r = [regex]"ModuleVersion += +'([^']+)'" $d = $r.Match($content) return $d.Groups[1].Value } function _setEnvironmentVariables { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")] param ( [string] $Level = "Process", [string] $Pat, [string] $Acct, [string] $BearerToken, [string] $Version ) # You always have to set at the process level or they will Not # be seen in your current session. $env:TEAM_PAT = $Pat $env:TEAM_ACCT = $Acct $env:TEAM_VERSION = $Version $env:TEAM_TOKEN = $BearerToken [VSTeamVersions]::Account = $Acct # This is so it can be loaded by default in the next session if ($Level -ne "Process") { [System.Environment]::SetEnvironmentVariable("TEAM_PAT", $Pat, $Level) [System.Environment]::SetEnvironmentVariable("TEAM_ACCT", $Acct, $Level) [System.Environment]::SetEnvironmentVariable("TEAM_VERSION", $Version, $Level) } } # If you remove an account the current default project needs to be cleared as well. function _clearEnvironmentVariables { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")] param ( [string] $Level = "Process" ) $env:TEAM_PROJECT = $null [VSTeamVersions]::DefaultProject = '' $Global:PSDefaultParameterValues.Remove("*:projectName") # This is so it can be loaded by default in the next session if ($Level -ne "Process") { [System.Environment]::SetEnvironmentVariable("TEAM_PROJECT", $null, $Level) } _setEnvironmentVariables -Level $Level -Pat '' -Acct '' -UseBearerToken '' -Version '' } function _convertToHex() { [cmdletbinding()] param( [parameter(Mandatory = $true)] [string]$Value ) $bytes = $Value | Format-Hex -Encoding Unicode $hexString = ($bytes.Bytes | ForEach-Object ToString X2) -join '' return $hexString.ToLowerInvariant(); } function _getVSTeamIdFromDescriptor { [cmdletbinding()] param( [parameter(Mandatory = $true)] [string]$Descriptor ) $identifier = $Descriptor.Split('.')[1] # We need to Pad the string for FromBase64String to work reliably (AzD Descriptors are not padded) $ModulusValue = ($identifier.length % 4) Switch ($ModulusValue) { '0' { $Padded = $identifier } '1' { $Padded = $identifier.Substring(0, $identifier.Length - 1) } '2' { $Padded = $identifier + ('=' * (4 - $ModulusValue)) } '3' { $Padded = $identifier + ('=' * (4 - $ModulusValue)) } } return [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($Padded)) } function _getDescriptorForACL { [cmdletbinding()] param( [parameter(Mandatory = $true, ParameterSetName = "ByUser")] [VSTeamUser]$User, [parameter(MAndatory = $true, ParameterSetName = "ByGroup")] [VSTeamGroup]$Group ) if ($User) { switch ($User.Origin) { "vsts" { $sid = _getVSTeamIdFromDescriptor -Descriptor $User.Descriptor $descriptor = "Microsoft.TeamFoundation.Identity;$sid" } "aad" { $descriptor = "Microsoft.IdentityModel.Claims.ClaimsIdentity;$($User.Domain)\\$($User.PrincipalName)" } default { throw "User type not handled yet for ACL. Please report this as an issue on the VSTeam Repository: https://github.com/DarqueWarrior/vsteam/issues" } } } if ($Group) { switch ($Group.Origin) { "vsts" { $sid = _getVSTeamIdFromDescriptor -Descriptor $Group.Descriptor $descriptor = "Microsoft.TeamFoundation.Identity;$sid" } default { throw "Group type not handled yet for Add-VSTeamGitRepositoryPermission. Please report this as an issue on the VSTeam Repository: https://github.com/DarqueWarrior/vsteam/issues" } } } return $descriptor } function Add-VSTeam { [CmdletBinding()] param( [Parameter(Mandatory = $true, Position = 1)] [Alias('TeamName')] [string]$Name, [string]$Description = '' ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $body = '{ "name": "' + $Name + '", "description": "' + $Description + '" }' # Call the REST API $resp = _callAPI -Area 'projects' -Resource "$ProjectName/teams" ` -Method Post -ContentType 'application/json' -Body $body -Version $([VSTeamVersions]::Core) $team = [VSTeamTeam]::new($resp, $ProjectName) Write-Output $team } } function Add-VSTeamAccessControlEntry { [CmdletBinding(DefaultParameterSetName = 'ByNamespace')] param( [Parameter(ParameterSetName = 'ByNamespace', Mandatory = $true, ValueFromPipeline = $true)] [VSTeamSecurityNamespace] $SecurityNamespace, [Parameter(ParameterSetName = 'ByNamespaceId', Mandatory = $true)] [ValidateScript({ try { [System.Guid]::Parse($_) | Out-Null $true } catch { $false } })] [string] $SecurityNamespaceId, [Parameter(ParameterSetName = 'ByNamespace', Mandatory = $true)] [Parameter(ParameterSetName = 'ByNamespaceId', Mandatory = $true)] [string] $Token, [Parameter(ParameterSetName = 'ByNamespace', Mandatory = $true)] [Parameter(ParameterSetName = 'ByNamespaceId', Mandatory = $true)] [string] $Descriptor, [Parameter(ParameterSetName = 'ByNamespace', Mandatory = $true)] [Parameter(ParameterSetName = 'ByNamespaceId', Mandatory = $true)] [ValidateRange(0, [int]::MaxValue)] [int] $AllowMask, [Parameter(ParameterSetName = 'ByNamespace', Mandatory = $true)] [Parameter(ParameterSetName = 'ByNamespaceId', Mandatory = $true)] [ValidateRange(0, [int]::MaxValue)] [int] $DenyMask ) process { if ($SecurityNamespace) { $SecurityNamespaceId = $SecurityNamespace.ID } $body = @" { "token": "$Token", "merge": true, "accessControlEntries": [ { "descriptor": "$Descriptor", "allow": $AllowMask, "deny": $DenyMask, "extendedinfo": {} } ] } "@ # Call the REST API $resp = _callAPI -Area 'accesscontrolentries' -id $SecurityNamespaceId -method POST -body $body ` -Version $([VSTeamVersions]::Core) ` -ContentType "application/json" if ($resp.count -ne 1) { throw "Expected 1 result, but got $($rep.count)" } # Storing the object before you return it cleaned up the pipeline. # When I just write the object from the constructor each property # seemed to be written $acl = [VSTeamAccessControlEntry]::new($resp.value) Write-Output $acl } } function Add-VSTeamAzureRMServiceEndpoint { [CmdletBinding(DefaultParameterSetName = 'Automatic')] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [Alias('displayName')] [string] $subscriptionName, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $subscriptionId, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $subscriptionTenantId, [Parameter(ParameterSetName = 'Manual', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $servicePrincipalId, [Parameter(ParameterSetName = 'Manual', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $servicePrincipalKey, [string] $endpointName ) DynamicParam { _buildProjectNameDynamicParam } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if (-not $endpointName) { $endpointName = $subscriptionName } if (-not $servicePrincipalId) { $creationMode = 'Automatic' } else { $creationMode = 'Manual' } $obj = @{ authorization = @{ parameters = @{ serviceprincipalid = $servicePrincipalId serviceprincipalkey = $servicePrincipalKey tenantid = $subscriptionTenantId } scheme = 'ServicePrincipal' } data = @{ subscriptionId = $subscriptionId subscriptionName = $subscriptionName creationMode = $creationMode } url = 'https://management.azure.com/' } return Add-VSTeamServiceEndpoint ` -ProjectName $ProjectName ` -endpointName $endpointName ` -endpointType 'azurerm' ` -object $obj } } function Add-VSTeamBuild { [CmdletBinding(DefaultParameterSetName = 'ByName')] param( [Parameter(ParameterSetName = 'ByID', ValueFromPipelineByPropertyName = $true)] [Int32] $BuildDefinitionId, [Parameter(Mandatory = $false)] [string] $SourceBranch, [Parameter(Mandatory = $false)] [hashtable] $BuildParameters ) DynamicParam { $dp = _buildProjectNameDynamicParam # If they have not set the default project you can't find the # validateset so skip that check. However, we still need to give # the option to pass a QueueName to use. $queues = $null $queueArrSet = $null if ($Global:PSDefaultParameterValues["*:projectName"]) { $queues = Get-VSTeamQueue -ProjectName $Global:PSDefaultParameterValues["*:projectName"] $queueArrSet = $queues.name } else { Write-Verbose 'Call Set-VSTeamDefaultProject for Tab Complete of QueueName' } $ParameterName = 'QueueName' $rp = _buildDynamicParam -ParameterName $ParameterName -arrSet $queueArrSet $dp.Add($ParameterName, $rp) $buildDefs = $null $buildDefsArrSet = $null if ($Global:PSDefaultParameterValues["*:projectName"]) { $buildDefs = Get-VSTeamBuildDefinition -ProjectName $Global:PSDefaultParameterValues["*:projectName"] $buildDefsArrSet = $buildDefs.name } else { Write-Verbose 'Call Set-VSTeamDefaultProject for Tab Complete of BuildDefinition' } $ParameterName = 'BuildDefinitionName' $rp = _buildDynamicParam -ParameterName $ParameterName -arrSet $buildDefsArrSet -ParameterSetName 'ByName' $dp.Add($ParameterName, $rp) $dp } process { # Bind the parameter to a friendly variable $QueueName = $PSBoundParameters["QueueName"] $ProjectName = $PSBoundParameters["ProjectName"] $BuildDefinition = $PSBoundParameters["BuildDefinitionName"] if ($BuildDefinitionId) { $id = $BuildDefinitionId } else { # Find the BuildDefinition id from the name $id = Get-VSTeamBuildDefinition -ProjectName "$ProjectName" -Type All | Where-Object { $_.name -eq $BuildDefinition } | Select-Object -ExpandProperty id } $body = @{ definition = @{ id = $id }; } if ($QueueName) { $queueId = Get-VSTeamQueue -ProjectName "$ProjectName" -queueName "$QueueName" | Select-Object -ExpandProperty Id $body.Add('queue', @{ id = $queueId }) } if ($SourceBranch) { $body.Add('sourceBranch', $SourceBranch) } if ($BuildParameters) { $body.Add('parameters', ($BuildParameters | ConvertTo-Json -Compress)) } # Call the REST API $resp = _callAPI -ProjectName $ProjectName -Area 'build' -Resource 'builds' ` -Method Post -ContentType 'application/json' -Body ($body | ConvertTo-Json) ` -Version $([VSTeamVersions]::Build) _applyTypesToBuild -item $resp return $resp } } function Add-VSTeamBuildDefinition { [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $InFile ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $resp = _callAPI -Method Post -ProjectName $ProjectName -Area build -Resource definitions -Version $([VSTeamVersions]::Build) -infile $InFile -ContentType 'application/json' return $resp } } function Add-VSTeamBuildTag { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Low")] param( [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [string[]] $Tags, [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('BuildID')] [int[]] $Id, [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { $ProjectName = $PSBoundParameters["ProjectName"] foreach ($item in $id) { if ($Force -or $pscmdlet.ShouldProcess($item, "Add-VSTeamBuildTag")) { foreach ($tag in $tags) { # Call the REST API _callAPI -ProjectName $projectName -Area 'build' -Resource "builds/$Id/tags" ` -Method Put -Querystring @{tag = $tag} -Version $([VSTeamVersions]::Build) | Out-Null } } } } } function Add-VSTeamExtension { param( [parameter(Mandatory = $true)] [string] $PublisherId, [parameter(Mandatory = $true)] [string] $ExtensionId, [parameter(Mandatory = $false)] [string] $Version ) Process { $resource = "extensionmanagement/installedextensionsbyname/$PublisherId/$ExtensionId" if ($version) { $resource += '/' + $Version } $resp = _callAPI -Method Post -SubDomain 'extmgmt' -Resource $resource -Version $([VSTeamVersions]::ExtensionsManagement) -ContentType "application/json" $item = [VSTeamExtension]::new($resp) Write-Output $item } } function Add-VSTeamFeed { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [string] $Name, [Parameter(Position = 1)] [string] $Description, [switch] $EnableUpstreamSources, [switch] $showDeletedPackageVersions ) process { # Thi swill throw if this account does not support feeds _supportsFeeds $body = @{ name = $Name description = $Description hideDeletedPackageVersions = $true } if ($showDeletedPackageVersions.IsPresent) { $body.hideDeletedPackageVersions = $false } if ($EnableUpstreamSources.IsPresent) { $body.upstreamEnabled = $true $body.upstreamSources = @( @{ id = [System.Guid]::NewGuid() name = 'npmjs' protocol = 'npm' location = 'https://registry.npmjs.org/' upstreamSourceType = 1 }, @{ id = [System.Guid]::NewGuid() name = 'nuget.org' protocol = 'nuget' location = 'https://api.nuget.org/v3/index.json' upstreamSourceType = 1 } ) } $bodyAsJson = $body | ConvertTo-Json # Call the REST API $resp = _callAPI -subDomain feeds -Area packaging -Resource feeds ` -Method Post -ContentType 'application/json' -body $bodyAsJson -Version $([VSTeamVersions]::Packaging) return [VSTeamFeed]::new($resp) } } function Add-VSTeamGitRepository { [CmdletBinding()] param( [parameter(Mandatory = $true)] [string] $Name ) DynamicParam { _buildProjectNameDynamicParam } process { $ProjectName = $PSBoundParameters["ProjectName"] $body = '{"name": "' + $Name + '"}' try { # Call the REST API $resp = _callAPI -ProjectName $ProjectName -Area 'git' -Resource 'repositories' ` -Method Post -ContentType 'application/json' -Body $body -Version $([VSTeamVersions]::Git) # Storing the object before you return it cleaned up the pipeline. # When I just write the object from the constructor each property # seemed to be written $repo = [VSTeamGitRepository]::new($resp, $ProjectName) Write-Output $repo } catch { _handleException $_ } } } function Add-VSTeamGitRepositoryPermission { [CmdletBinding(DefaultParameterSetName = 'ByProjectAndUser')] param( [parameter(Mandatory=$true,ParameterSetName="ByProjectAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndDescriptor")] [VSTeamProject]$Project, [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndDescriptor")] [ValidateScript({ try { [System.Guid]::Parse($_) | Out-Null $true } catch { $false } })] [string]$RepositoryId, [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndDescriptor")] [string]$RepositoryName, [parameter(Mandatory=$false,ParameterSetName="ByRepositoryIdAndGroup")] [parameter(Mandatory=$false,ParameterSetName="ByRepositoryIdAndUser")] [parameter(Mandatory=$false,ParameterSetName="ByRepositoryNameAndGroup")] [parameter(Mandatory=$false,ParameterSetName="ByRepositoryNameAndUser")] [parameter(Mandatory=$false,ParameterSetName="ByRepositoryIdAndDescriptor")] [parameter(Mandatory=$false,ParameterSetName="ByRepositoryNameAndDescriptor")] [string]$BranchName, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndDescriptor")] [string]$Descriptor, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndGroup")] [VSTeamGroup]$Group, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndUser")] [VSTeamUser]$User, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndDescriptor")] [VSTeamGitRepositoryPermissions]$Allow, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryIdAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByRepositoryNameAndDescriptor")] [VSTeamGitRepositoryPermissions]$Deny ) process { # SecurityNamespaceID: 2e9eb7ed-3c0a-47d4-87c1-0ffdd275fd87 # Token: repoV2/<projectId>" <-- Whole project # Token: repoV2/<projectId>/<repositoryId>" <-- Whole repository # Token: repoV2/<projectId>/<repositoryId>/refs/heads/<branchName>" <-- Single branch $securityNamespaceId = "2e9eb7ed-3c0a-47d4-87c1-0ffdd275fd87" # Resolve Repository Name to ID if ($RepositoryName) { $repo = Get-VSTeamGitRepository -ProjectName $Project.Name -Name $RepositoryName if (!$repo) { throw "Repository not found" } $RepositoryId = $repo.ID } # Resolve Group to Descriptor if ($Group) { $Descriptor = _getDescriptorForACL -Group $Group } # Resolve User to Descriptor if ($User) { $Descriptor = _getDescriptorForACL -User $User } $token = "repoV2/$($Project.ID)" if ($RepositoryId) { $token += "/$($RepositoryId)" } if ($BranchName) { $branchHex = _convertToHex($BranchName) $token += "/refs/heads/$($branchHex)" } Add-VSTeamAccessControlEntry -SecurityNamespaceId $securityNamespaceId -Descriptor $Descriptor -Token $token -AllowMask ([int]$Allow) -DenyMask ([int]$Deny) } } function Add-VSTeamKubernetesEndpoint { [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $endpointName, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $kubeconfig, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $kubernetesUrl, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $clientCertificateData, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $clientKeyData, [switch] $acceptUntrustedCerts, [switch] $generatePfx ) DynamicParam { _buildProjectNameDynamicParam } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] # Process switch parameters $untrustedCerts = $false if ($acceptUntrustedCerts.IsPresent) { $untrustedCerts = $true } $pfx = $false if ($generatePfx.IsPresent) { $pfx = $true } $obj = @{ authorization = @{ parameters = @{ clientCertificateData = $clientCertificateData clientKeyData = $clientKeyData generatePfx = $pfx kubeconfig = $Kubeconfig }; scheme = 'None' }; data = @{ acceptUntrustedCerts = $untrustedCerts }; url = $kubernetesUrl } return Add-VSTeamServiceEndpoint ` -ProjectName $ProjectName ` -endpointName $endpointName ` -endpointType 'kubernetes' ` -object $obj } } function Add-VSTeamMembership { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string] $MemberDescriptor, [Parameter(Mandatory = $true)] [string] $ContainerDescriptor, [switch] $DontTest ) process { return _callMembershipAPI -Id "$MemberDescriptor/$ContainerDescriptor" -Method Put } } function Add-VSTeamNuGetEndpoint { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")] [CmdletBinding(DefaultParameterSetName = 'SecureApiKey')] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $EndpointName, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $NuGetUrl, [Parameter(ParameterSetName = 'ClearToken', Mandatory = $true, HelpMessage = 'Personal Access Token')] [string] $PersonalAccessToken, [Parameter(ParameterSetName = 'ClearApiKey', Mandatory = $true, HelpMessage = 'ApiKey')] [string] $ApiKey, [Parameter(ParameterSetName = 'SecurePassword', Mandatory = $true, HelpMessage = 'Username')] [string] $Username, [Parameter(ParameterSetName = 'SecureToken', Mandatory = $true, HelpMessage = 'Personal Access Token')] [securestring] $SecurePersonalAccessToken, [Parameter(ParameterSetName = 'SecureApiKey', Mandatory = $true, HelpMessage = 'ApiKey')] [securestring] $SecureApiKey, [Parameter(ParameterSetName = 'SecurePassword', Mandatory = $true, HelpMessage = 'Password')] [securestring] $SecurePassword ) DynamicParam { _buildProjectNameDynamicParam } Process { if ($PersonalAccessToken) { $Authentication = 'Token' $token = $PersonalAccessToken } elseif ($ApiKey) { $Authentication = 'ApiKey' $token = $ApiKey } elseif ($SecureApiKey) { $Authentication = 'ApiKey' $credential = New-Object System.Management.Automation.PSCredential "ApiKey", $SecureApiKey $token = $credential.GetNetworkCredential().Password } elseif ($SecurePassword) { $Authentication = 'UsernamePassword' $credential = New-Object System.Management.Automation.PSCredential "Password", $SecurePassword $token = $credential.GetNetworkCredential().Password } else { $Authentication = 'Token' $credential = New-Object System.Management.Automation.PSCredential "token", $securePersonalAccessToken $token = $credential.GetNetworkCredential().Password } # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters['ProjectName'] $obj = @{ data = @{} url = $NuGetUrl } if ($Authentication -eq 'ApiKey') { $obj['authorization'] = @{ parameters = @{ nugetkey = $token } scheme = 'None' } } elseif ($Authentication -eq 'Token') { $obj['authorization'] = @{ parameters = @{ apitoken = $token } scheme = 'Token' } } else { $obj['authorization'] = @{ parameters = @{ username = $Username password = $token } scheme = 'UsernamePassword' } } return Add-VSTeamServiceEndpoint ` -ProjectName $ProjectName ` -endpointName $endpointName ` -endpointType 'externalnugetfeed' ` -object $obj } } function Add-VSTeamPolicy { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [guid] $type, [switch] $enabled, [switch] $blocking, [Parameter(Mandatory = $true)] [hashtable] $settings ) DynamicParam { _buildProjectNameDynamicParam -mandatory $true } process { $ProjectName = $PSBoundParameters["ProjectName"] $body = @{ isEnabled = $enabled.IsPresent; isBlocking = $blocking.IsPresent; type = @{ id = $type }; settings = $settings } | ConvertTo-Json -Depth 10 -Compress try { # Call the REST API $resp = _callAPI -ProjectName $ProjectName -Area 'policy' -Resource 'configurations' ` -Method Post -ContentType 'application/json' -Body $body -Version $([VSTeamVersions]::Git) Write-Output $resp } catch { _handleException $_ } } } function Add-VSTeamProfile { [CmdletBinding(DefaultParameterSetName = 'Secure')] param( [parameter(ParameterSetName = 'Windows', Mandatory = $true, Position = 1)] [parameter(ParameterSetName = 'Secure', Mandatory = $true, Position = 1)] [Parameter(ParameterSetName = 'Plain')] [string] $Account, [parameter(ParameterSetName = 'Plain', Mandatory = $true, Position = 2, HelpMessage = 'Personal Access Token')] [string] $PersonalAccessToken, [parameter(ParameterSetName = 'Secure', Mandatory = $true, HelpMessage = 'Personal Access Token')] [securestring] $SecurePersonalAccessToken, [string] $Name, [ValidateSet('TFS2017', 'TFS2018', 'AzD2019', 'VSTS')] [string] $Version, [switch] $UseBearerToken ) DynamicParam { # Only add these options on Windows Machines if (_isOnWindows) { # Create the dictionary $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $ParameterName2 = 'UseWindowsAuthentication' # Create the collection of attributes $AttributeCollection2 = New-Object System.Collections.ObjectModel.Collection[System.Attribute] # Create and set the parameters' attributes $ParameterAttribute2 = New-Object System.Management.Automation.ParameterAttribute $ParameterAttribute2.Mandatory = $true $ParameterAttribute2.ParameterSetName = "Windows" $ParameterAttribute2.HelpMessage = "On Windows machines allows you to use the active user identity for authentication. Not available on other platforms." # Add the attributes to the attributes collection $AttributeCollection2.Add($ParameterAttribute2) # Create and return the dynamic parameter $RuntimeParameter2 = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName2, [switch], $AttributeCollection2) $RuntimeParameterDictionary.Add($ParameterName2, $RuntimeParameter2) return $RuntimeParameterDictionary } } process { if ($SecurePersonalAccessToken) { # Even when promoted for a Secure Personal Access Token you can just # press enter. This leads to an empty PAT so error below. # Convert the securestring to a normal string # this was the one technique that worked on Mac, Linux and Windows $_pat = _convertSecureStringTo_PlainText -SecureString $SecurePersonalAccessToken } else { $_pat = $PersonalAccessToken } if (_isOnWindows) { # Bind the parameter to a friendly variable $UsingWindowsAuth = $PSBoundParameters[$ParameterName2] if (!($_pat) -and !($UsingWindowsAuth)) { Write-Error 'Personal Access Token must be provided if you are not using Windows Authentication; please see the help.' return } } # If they only gave an account name add https://dev.azure.com if ($Account -notlike "*/*") { if (-not $Name) { $Name = $Account } $Account = "https://dev.azure.com/$($Account)" } # If they gave https://dev.azure.com extract Account and Profile name if ($Account -match "(?<protocol>https\://)?(?<domain>dev\.azure\.com/)(?<account>[A-Z0-9][-A-Z0-9]*[A-Z0-9])") { if (-not $Name) { $Name = $matches.account } $Account = "https://dev.azure.com/$($matches.account)" } # If they gave https://xxx.visualstudio.com extract Account and Profile name, convert to new URL if ($Account -match "(?<protocol>https?\://)?(?<account>[A-Z0-9][-A-Z0-9]*[A-Z0-9])(?<domain>\.visualstudio\.com)") { if (-not $Name) { $Name = $matches.account } $Account = "https://dev.azure.com/$($matches.account)" } if ($UseBearerToken.IsPresent) { $authType = 'Bearer' $token = $_pat $encodedPat = '' } else { $token = '' $authType = 'Pat' $encodedPat = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$_pat")) } # If no SecurePersonalAccessToken is entered, and on windows, are we using default credentials for REST calls if ((!$_pat) -and (_isOnWindows) -and ($UsingWindowsAuth)) { Write-Verbose 'Using Default Windows Credentials for authentication; no Personal Access Token required' $encodedPat = '' $token = '' $authType = 'OnPremise' } if (-not $Name) { $Name = $Account } # See if this item is already in there # I am testing URL because the user may provide a different # name and I don't want two with the same URL. # The @() forces even 1 item to an array $profiles = @(Get-VSTeamProfile | Where-Object URL -ne $Account) $newProfile = [PSCustomObject]@{ Name = $Name URL = $Account Type = $authType Pat = $encodedPat Token = $token Version = (_getVSTeamAPIVersion -Instance $Account -Version $Version) } $profiles += $newProfile $contents = ConvertTo-Json $profiles Set-Content -Path $profilesPath -Value $contents } } function Add-VSTeamProject { param( [parameter(Mandatory = $true)] [Alias('Name')] [string] $ProjectName, [string] $Description, [switch] $TFVC ) DynamicParam { [VSTeamProcessCache]::timestamp = -1 _buildProcessNameDynamicParam -ParameterName 'ProcessTemplate' -Mandatory $false } process { # Bind the parameter to a friendly variable $ProcessTemplate = $PSBoundParameters["ProcessTemplate"] if ($TFVC.IsPresent) { $srcCtrl = "Tfvc" } else { $srcCtrl = 'Git' } if ($ProcessTemplate) { Write-Verbose "Finding $ProcessTemplate id" $templateTypeId = (Get-VSTeamProcess -Name $ProcessTemplate).Id } else { # Default to Scrum Process Template $ProcessTemplate = 'Scrum' $templateTypeId = '6b724908-ef14-45cf-84f8-768b5384da45' } $body = '{"name": "' + $ProjectName + '", "description": "' + $Description + '", "capabilities": {"versioncontrol": { "sourceControlType": "' + $srcCtrl + '"}, "processTemplate":{"templateTypeId": "' + $templateTypeId + '"}}}' try { # Call the REST API $resp = _callAPI -Area 'projects' ` -Method Post -ContentType 'application/json' -body $body -Version $([VSTeamVersions]::Core) _trackProjectProgress -resp $resp -title 'Creating team project' -msg "Name: $($ProjectName), Template: $($processTemplate), Src: $($srcCtrl)" # Invalidate any cache of projects. [VSTeamProjectCache]::timestamp = -1 return Get-VSTeamProject $ProjectName } catch { _handleException $_ } } } function Add-VSTeamProjectPermission { [CmdletBinding(DefaultParameterSetName = 'ByProjectAndUser')] param( [parameter(Mandatory=$true,ParameterSetName="ByProjectAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndUser")] [VSTeamProject]$Project, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndDescriptor")] [string]$Descriptor, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndGroup")] [VSTeamGroup]$Group, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndUser")] [VSTeamUser]$User, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndUser")] [VSTeamProjectPermissions]$Allow, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndUser")] [VSTeamProjectPermissions]$Deny ) process { # SecurityNamespaceID: 52d39943-cb85-4d7f-8fa8-c6baac873819 # Token: $PROJECT:vstfs:///Classification/TeamProject/<projectId> $securityNamespaceId = "52d39943-cb85-4d7f-8fa8-c6baac873819" # Resolve Group to Descriptor if ($Group) { $Descriptor = _getDescriptorForACL -Group $Group } # Resolve User to Descriptor if ($User) { $Descriptor = _getDescriptorForACL -User $User } $token = "`$PROJECT:vstfs:///Classification/TeamProject/$($Project.ID)" Add-VSTeamAccessControlEntry -SecurityNamespaceId $securityNamespaceId -Descriptor $Descriptor -Token $token -AllowMask ([int]$Allow) -DenyMask ([int]$Deny) } } function Add-VSTeamPullRequest { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Low")] param( [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true, Position = 0)] [Alias('Id')] [Guid] $RepositoryId, [Parameter(Mandatory = $true, HelpMessage = "Should be a ref like refs/heads/MyBranch")] [ValidatePattern('^refs/.*')] [string] $SourceRefName, [Parameter(Mandatory = $true, HelpMessage = "Should be a ref like refs/heads/MyBranch")] [ValidatePattern('^refs/.*')] [string] $TargetRefName, [Parameter(Mandatory = $true)] [string] $Title, [Parameter(Mandatory = $true)] [string] $Description, [Parameter()] [switch] $Draft, # Forces the command without confirmation [Parameter()] [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } process { Write-Verbose "Add-VSTeamPullRequest" # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $body = '{"sourceRefName": "' + $SourceRefName + '", "targetRefName": "' + $TargetRefName + '", "title": "' + $Title + '", "description": "' + $Description + '", "isDraft": ' + $Draft.ToString().ToLower() + '}' Write-Verbose $body # Call the REST API if ($force -or $pscmdlet.ShouldProcess($Title, "Add Pull Request")) { try { Write-Debug 'Add-VSTeamPullRequest Call the REST API' $resp = _callAPI -ProjectName $ProjectName -Area 'git' -Resource 'repositories' -Id "$RepositoryId/pullrequests" ` -Method Post -ContentType 'application/json;charset=utf-8' -Body $body -Version $([VSTeamVersions]::Release) _applyTypesToPullRequests -item $resp Write-Output $resp } catch { _handleException $_ } } } } function Add-VSTeamRelease { [CmdletBinding(DefaultParameterSetName = 'ById', SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param( [Parameter(ParameterSetName = 'ById', Mandatory = $true)] [int] $DefinitionId, [Parameter(Mandatory = $false)] [string] $Description, [Parameter(ParameterSetName = 'ById', Mandatory = $true)] [string] $ArtifactAlias, [Parameter()] [string] $Name, [Parameter(ParameterSetName = 'ById', Mandatory = $true)] [string] $BuildId, [Parameter()] [string] $SourceBranch, # Forces the command without confirmation [switch] $Force ) DynamicParam { $dp = _buildProjectNameDynamicParam # If they have not set the default project you can't find the # validateset so skip that check. However, we still need to give # the option to pass by name. if ($Global:PSDefaultParameterValues["*:projectName"]) { $defs = Get-VSTeamReleaseDefinition -ProjectName $Global:PSDefaultParameterValues["*:projectName"] -expand artifacts $arrSet = $defs.name } else { Write-Verbose 'Call Set-VSTeamDefaultProject for Tab Complete of DefinitionName' $defs = $null $arrSet = $null } $ParameterName = 'DefinitionName' $rp = _buildDynamicParam -ParameterName $ParameterName -arrSet $arrSet -ParameterSetName 'ByName' -Mandatory $true $dp.Add($ParameterName, $rp) if ($Global:PSDefaultParameterValues["*:projectName"]) { $builds = Get-VSTeamBuild -ProjectName $Global:PSDefaultParameterValues["*:projectName"] $arrSet = $builds.name } else { Write-Verbose 'Call Set-VSTeamDefaultProject for Tab Complete of BuildName' $builds = $null $arrSet = $null } $ParameterName = 'BuildNumber' $rp = _buildDynamicParam -ParameterName $ParameterName -arrSet $arrSet -ParameterSetName 'ByName' -Mandatory $true $dp.Add($ParameterName, $rp) $dp } process { Write-Debug 'Add-VSTeamRelease Process' # Bind the parameter to a friendly variable $BuildNumber = $PSBoundParameters["BuildNumber"] $ProjectName = $PSBoundParameters["ProjectName"] $DefinitionName = $PSBoundParameters["DefinitionName"] #Write-Verbose $builds if ($builds -and -not $buildId) { $buildId = $builds | Where-Object {$_.name -eq $BuildNumber} | Select-Object -ExpandProperty id } if ($defs -and -not $artifactAlias) { $def = $defs | Where-Object {$_.name -eq $DefinitionName} $DefinitionId = $def | Select-Object -ExpandProperty id $artifactAlias = $def.artifacts[0].alias } $body = '{"definitionId": ' + $DefinitionId + ', "description": "' + $description + '", "artifacts": [{"alias": "' + $artifactAlias + '", "instanceReference": {"id": "' + $buildId + '", "name": "' + $Name + '", "sourceBranch": "' + $SourceBranch + '"}}]}' Write-Verbose $body # Call the REST API if ($force -or $pscmdlet.ShouldProcess($description, "Add Release")) { try { Write-Debug 'Add-VSTeamRelease Call the REST API' $resp = _callAPI -SubDomain 'vsrm' -ProjectName $ProjectName -Area 'release' -Resource 'releases' ` -Method Post -ContentType 'application/json' -Body $body -Version $([VSTeamVersions]::Release) _applyTypesToRelease $resp Write-Output $resp } catch { _handleException $_ } } } } function Add-VSTeamReleaseDefinition { [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $inFile ) DynamicParam { _buildProjectNameDynamicParam } process { Write-Debug 'Add-VSTeamReleaseDefinition Process' # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $resp = _callAPI -Method Post -subDomain vsrm -Area release -Resource definitions -ProjectName $ProjectName ` -Version $([VSTeamVersions]::Release) -inFile $inFile -ContentType 'application/json' Write-Output $resp } } function Add-VSTeamServiceEndpoint { [CmdletBinding(DefaultParameterSetName = 'Secure')] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $endpointName, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $endpointType, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [hashtable] $object ) DynamicParam { _buildProjectNameDynamicParam } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $object['name'] = $endpointName $object['type'] = $endpointType $body = $object | ConvertTo-Json # Call the REST API $resp = _callAPI -ProjectName $projectName -Area 'distributedtask' -Resource 'serviceendpoints' ` -Method Post -ContentType 'application/json' -body $body -Version $([VSTeamVersions]::DistributedTask) _trackServiceEndpointProgress -projectName $projectName -resp $resp -title 'Creating Service Endpoint' -msg "Creating $endpointName" return Get-VSTeamServiceEndpoint -ProjectName $ProjectName -id $resp.id } } function Add-VSTeamServiceFabricEndpoint { [CmdletBinding(DefaultParameterSetName = 'Certificate')] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [Alias('displayName')] [string] $endpointName, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $url, [parameter(ParameterSetName = 'Certificate', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $certificate, [Parameter(ParameterSetName = 'Certificate', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [securestring] $certificatePassword, [parameter(ParameterSetName = 'Certificate', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [parameter(ParameterSetName = 'AzureAd', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $serverCertThumbprint, [Parameter(ParameterSetName = 'AzureAd', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $username, [Parameter(ParameterSetName = 'AzureAd', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [securestring] $password, [Parameter(ParameterSetName = 'None', Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string] $clusterSpn, [Parameter(ParameterSetName = 'None', Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [bool] $useWindowsSecurity ) DynamicParam { _buildProjectNameDynamicParam } Process { # This will throw if this account does not support ServiceFabricEndpoint _supportsServiceFabricEndpoint # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] switch ($PSCmdlet.ParameterSetName) { "Certificate" { # copied securestring usage from Set-VSTeamAccount # while we don't actually have a username here, PSCredential requires that a non empty string is provided $credential = New-Object System.Management.Automation.PSCredential $serverCertThumbprint, $certificatePassword $certPass = $credential.GetNetworkCredential().Password $authorization = @{ parameters = @{ certificate = $certificate certificatepassword = $certPass servercertthumbprint = $serverCertThumbprint } scheme = 'Certificate' } } "AzureAd" { # copied securestring usage from Set-VSTeamAccount $credential = New-Object System.Management.Automation.PSCredential $username, $password $pass = $credential.GetNetworkCredential().Password $authorization = @{ parameters = @{ password = $pass servercertthumbprint = $serverCertThumbprint username = $username } scheme = 'UsernamePassword' } } Default { $authorization = @{ parameters = @{ ClusterSpn = $clusterSpn UseWindowsSecurity = $useWindowsSecurity } scheme = 'None' } } } $obj = @{ authorization = $authorization data = @{} url = $url } return Add-VSTeamServiceEndpoint ` -ProjectName $ProjectName ` -endpointName $endpointName ` -endpointType 'servicefabric' ` -object $obj } } function Add-VSTeamSonarQubeEndpoint { [CmdletBinding(DefaultParameterSetName = 'Secure')] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $endpointName, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $sonarqubeUrl, [parameter(ParameterSetName = 'Plain', Mandatory = $true, Position = 2, HelpMessage = 'Personal Access Token')] [string] $personalAccessToken, [parameter(ParameterSetName = 'Secure', Mandatory = $true, HelpMessage = 'Personal Access Token')] [securestring] $securePersonalAccessToken ) DynamicParam { _buildProjectNameDynamicParam } Process { if ($personalAccessToken) { $token = $personalAccessToken } else { $credential = New-Object System.Management.Automation.PSCredential "nologin", $securePersonalAccessToken $token = $credential.GetNetworkCredential().Password } # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters['ProjectName'] $obj = @{ authorization = @{ parameters = @{ username = $token; password = '' }; scheme = 'UsernamePassword' }; data = @{}; url = $sonarqubeUrl } try { return Add-VSTeamServiceEndpoint ` -ProjectName $ProjectName ` -endpointName $endpointName ` -endpointType 'sonarqube' ` -object $obj } catch [System.Net.WebException] { if ($_.Exception.status -eq 'ProtocolError') { $errorDetails = ConvertFrom-Json $_.ErrorDetails $message = $errorDetails.message # The error message is different on TFS and VSTS if ($message.StartsWith("Endpoint type couldn't be recognized 'sonarqube'") -or $message.StartsWith("Unable to find service endpoint type 'sonarqube'")) { Write-Error -Message 'The Sonarqube extension not installed. Please install from https://marketplace.visualstudio.com/items?itemName=SonarSource.sonarqube' return } } throw } } } function Add-VSTeamTaskGroup { [CmdletBinding()] param( [Parameter(ParameterSetName = 'ByFile', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $InFile, [Parameter(ParameterSetName = 'ByBody', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $Body ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($InFile) { $resp = _callAPI -Method Post -ProjectName $ProjectName -Area distributedtask -Resource taskgroups -Version $([VSTeamVersions]::TaskGroups) -InFile $InFile -ContentType 'application/json' } else { $resp = _callAPI -Method Post -ProjectName $ProjectName -Area distributedtask -Resource taskgroups -Version $([VSTeamVersions]::TaskGroups) -ContentType 'application/json' -Body $Body } return $resp } } function Add-VSTeamUserEntitlement { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [Alias('UserEmail')] [string]$Email, [ValidateSet('Advanced', 'EarlyAdopter', 'Express', 'None', 'Professional', 'StakeHolder')] [string]$License = 'EarlyAdopter', [ValidateSet('Custom', 'ProjectAdministrator', 'ProjectContributor', 'ProjectReader', 'ProjectStakeholder')] [string]$Group = 'ProjectContributor', [ValidateSet('account', 'auto', 'msdn', 'none', 'profile', 'trial')] [string]$LicensingSource = "account", [ValidateSet('eligible', 'enterprise', 'none', 'platforms', 'premium', 'professional', 'testProfessional', 'ultimate')] [string]$MSDNLicenseType = "none" ) DynamicParam { _buildProjectNameDynamicParam -Mandatory $false } process { # Thi swill throw if this account does not support MemberEntitlementManagement _supportsMemberEntitlementManagement # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $obj = @{ accessLevel = @{ accountLicenseType = $License licensingSource = $LicensingSource msdnLicenseType = $MSDNLicenseType } user = @{ principalName = $email subjectKind = 'user' } projectEntitlements = @{ group = @{ groupType = $Group } projectRef = @{ id = $ProjectName } } } $body = $obj | ConvertTo-Json # Call the REST API _callAPI -Method Post -Body $body -SubDomain 'vsaex' -Resource 'userentitlements' -Version $([VSTeamVersions]::MemberEntitlementManagement) -ContentType "application/json" } } function Add-VSTeamVariableGroup { param( [Parameter(ParameterSetName = 'ByHashtable', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $Name, [Parameter(ParameterSetName = 'ByHashtable', Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string] $Description, [Parameter(ParameterSetName = 'ByHashtable', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [hashtable] $Variables, [Parameter(ParameterSetName = 'ByBody', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $Body ) DynamicParam { $dp = _buildProjectNameDynamicParam if ([VSTeamVersions]::Version -ne "TFS2017" -and $PSCmdlet.ParameterSetName -eq "ByHashtable") { $ParameterName = 'Type' $rp = _buildDynamicParam -ParameterName $ParameterName -arrSet ('Vsts', 'AzureKeyVault') -Mandatory $true $dp.Add($ParameterName, $rp) $ParameterName = 'ProviderData' $rp = _buildDynamicParam -ParameterName $ParameterName -Mandatory $false -ParameterType ([hashtable]) $dp.Add($ParameterName, $rp) } return $dp } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ([string]::IsNullOrWhiteSpace($Body)) { $bodyAsHashtable = @{ name = $Name description = $Description variables = $Variables } if ([VSTeamVersions]::Version -ne "TFS2017") { $Type = $PSBoundParameters['Type'] $bodyAsHashtable.Add("type", $Type) $ProviderData = $PSBoundParameters['ProviderData'] if ($null -ne $ProviderData) { $bodyAsHashtable.Add("providerData", $ProviderData) } } $body = $bodyAsHashtable | ConvertTo-Json } # Call the REST API $resp = _callAPI -ProjectName $projectName -Area 'distributedtask' -Resource 'variablegroups' ` -Method Post -ContentType 'application/json' -body $body -Version $([VSTeamVersions]::VariableGroups) return Get-VSTeamVariableGroup -ProjectName $ProjectName -id $resp.id } } function Add-VSTeamWorkItem { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Title, [Parameter(Mandatory = $false)] [string]$Description, [Parameter(Mandatory = $false)] [string]$IterationPath, [Parameter(Mandatory = $false)] [string]$AssignedTo, [Parameter(Mandatory = $false)] [int]$ParentId, [Parameter(Mandatory = $false)] [hashtable]$AdditionalFields ) DynamicParam { $dp = _buildProjectNameDynamicParam -mandatory $true # If they have not set the default project you can't find the # validateset so skip that check. However, we still need to give # the option to pass a WorkItemType to use. if ($Global:PSDefaultParameterValues["*:projectName"]) { $wittypes = _getWorkItemTypes -ProjectName $Global:PSDefaultParameterValues["*:projectName"] $arrSet = $wittypes } else { Write-Verbose 'Call Set-VSTeamDefaultProject for Tab Complete of WorkItemType' $wittypes = $null $arrSet = $null } $ParameterName = 'WorkItemType' $rp = _buildDynamicParam -ParameterName $ParameterName -arrSet $arrSet -Mandatory $true $dp.Add($ParameterName, $rp) $dp } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] # The type has to start with a $ $WorkItemType = "`$$($PSBoundParameters["WorkItemType"])" # Constructing the contents to be send. # Empty parameters will be skipped when converting to json. [Array]$body = @( @{ op = "add" path = "/fields/System.Title" value = $Title } @{ op = "add" path = "/fields/System.Description" value = $Description } @{ op = "add" path = "/fields/System.IterationPath" value = $IterationPath } @{ op = "add" path = "/fields/System.AssignedTo" value = $AssignedTo }) | Where-Object { $_.value } if ($ParentId) { $parentUri = _buildRequestURI -ProjectName $ProjectName -Area 'wit' -Resource 'workitems' -id $ParentId $body += @{ op = "add" path = "/relations/-" value = @{ "rel" = "System.LinkTypes.Hierarchy-Reverse" "url" = $parentURI } } } #this loop must always come after the main work item fields defined in the function parameters if ($AdditionalFields) { foreach ($fieldName in $AdditionalFields.Keys) { #check that main properties are not added into the additional fields hashtable $foundFields = $body | Where-Object { $null -ne $_ -and $_.path -like "*$fieldName" } if ($null -ne $foundFields) { throw "Found duplicate field '$fieldName' in parameter AdditionalFields, which is already a parameter. Please remove it." } else { $body += @{ op = "add" path = "/fields/$fieldName" value = $AdditionalFields[$fieldName] } } } } # It is very important that even if the user only provides # a single value above that the item is an array and not # a single object or the call will fail. # You must call ConvertTo-Json passing in the value and not # not using pipeline. # https://stackoverflow.com/questions/18662967/convertto-json-an-array-with-a-single-item $json = ConvertTo-Json @($body) -Compress # Call the REST API $resp = _callAPI -ProjectName $ProjectName -Area 'wit' -Resource 'workitems' ` -Version $([VSTeamVersions]::Core) -id $WorkItemType -Method Post ` -ContentType 'application/json-patch+json' -Body $json _applyTypesToWorkItem -item $resp return $resp } } function Add-VSTeamWorkItemAreaPermission { [CmdletBinding(DefaultParameterSetName = 'ByProjectAndAreaIdAndUser')] param( [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndGroup")] [VSTeamProject]$Project, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndUser")] [int]$AreaID, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndGroup")] [string]$AreaPath, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndDescriptor")] [string]$Descriptor, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndGroup")] [VSTeamGroup]$Group, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndUser")] [VSTeamUser]$User, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndGroup")] [VSTeamWorkItemAreaPermissions]$Allow, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaIdAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndAreaPathAndGroup")] [VSTeamWorkItemAreaPermissions]$Deny ) process { # SecurityID: 83e28ad4-2d72-4ceb-97b0-c7726d5502c3 # Token: vstfs:///Classification/Node/862eb45f-3873-41d7-89c8-4b2f8802eaa9 (https://dev.azure.com/<organization>/<project>/_apis/wit/classificationNodes/Areas) # "token": "vstfs:///Classification/Node/ae76de05-8b53-4e02-9205-e73e2012585e:vstfs:///Classification/Node/f8c5b667-91dd-4fe7-bf23-3138c439d07e", $securityNamespaceId = "83e28ad4-2d72-4ceb-97b0-c7726d5502c3" if ($AreaID) { $area = Get-VSTeamClassificationNode -ProjectName $Project.Name -Depth 0 -Ids $AreaID } if ($AreaPath) { $area = Get-VSTeamClassificationNode -ProjectName $Project.Name -Depth 0 -Path $AreaPath -StructureGroup "areas" } if (-not $area) { throw "Area not found" } if ($area.StructureType -ne "area") { throw "This is not an Area" } $nodes = @() $nodes += $area while ($area.ParentUrl) { $path = $area.ParentUrl -ireplace ".*(classificationNodes/Areas)\/?" if ($path.length -gt 0) { # We have a Path to resolve $area = Get-VSTeamClassificationNode -ProjectName $Project.Name -Depth 0 -Path $path -StructureGroup "Areas" } else { # We need to get the "root" node now $area = Get-VSTeamClassificationNode -ProjectName $Project.Name -Depth 0 -StructureGroup "Areas" } $nodes += $area } # Build Token from Path [array]::Reverse($nodes) $token = ($nodes | ForEach-Object { "vstfs:///Classification/Node/$($_.Identifier)" }) -join ":" # Resolve Group to Descriptor if ($Group) { $Descriptor = _getDescriptorForACL -Group $Group } # Resolve User to Descriptor if ($User) { $Descriptor = _getDescriptorForACL -User $User } Add-VSTeamAccessControlEntry -SecurityNamespaceId $securityNamespaceId -Descriptor $Descriptor -Token $token -AllowMask ([int]$Allow) -DenyMask ([int]$Deny) } } function Add-VSTeamWorkItemIterationPermission { [CmdletBinding(DefaultParameterSetName = 'ByProjectAndIterationIdAndUser')] param( [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndGroup")] [VSTeamProject]$Project, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndUser")] [int]$IterationID, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndGroup")] [string]$IterationPath, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndDescriptor")] [string]$Descriptor, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndGroup")] [VSTeamGroup]$Group, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndUser")] [VSTeamUser]$User, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndGroup")] [VSTeamWorkItemIterationPermissions]$Allow, [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndGroup")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationIdAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndDescriptor")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndUser")] [parameter(Mandatory=$true,ParameterSetName="ByProjectAndIterationPathAndGroup")] [VSTeamWorkItemIterationPermissions]$Deny ) process { # SecurityID: bf7bfa03-b2b7-47db-8113-fa2e002cc5b1 # Token: vstfs:///Classification/Node/862eb45f-3873-41d7-89c8-4b2f8802eaa9 (https://dev.azure.com/<organization>/<project>/_apis/wit/classificationNodes/Iterations) # "token": "vstfs:///Classification/Node/ae76de05-8b53-4e02-9205-e73e2012585e:vstfs:///Classification/Node/f8c5b667-91dd-4fe7-bf23-3138c439d07e", $securityNamespaceId = "bf7bfa03-b2b7-47db-8113-fa2e002cc5b1" if ($IterationID) { $iteration = Get-VSTeamClassificationNode -ProjectName $Project.Name -Depth 0 -Ids $IterationID } if ($IterationPath) { $iteration = Get-VSTeamClassificationNode -ProjectName $Project.Name -Depth 0 -Path $IterationPath -StructureGroup "iterations" } if (-not $iteration) { throw "Iteration not found" } if ($iteration.StructureType -ne "iteration") { throw "This is not an Iteration" } $nodes = @() $nodes += $iteration while ($iteration.ParentUrl) { $path = $iteration.ParentUrl -ireplace ".*(classificationNodes/Iterations)\/?" if ($path.length -gt 0) { # We have a Path to resolve $iteration = Get-VSTeamClassificationNode -ProjectName $Project.Name -Depth 0 -Path $path -StructureGroup "Iterations" } else { # We need to get the "root" node now $iteration = Get-VSTeamClassificationNode -ProjectName $Project.Name -Depth 0 -StructureGroup "Iterations" } $nodes += $iteration } # Build Token from Path [array]::Reverse($nodes) $token = ($nodes | ForEach-Object { "vstfs:///Classification/Node/$($_.Identifier)" }) -join ":" # Resolve Group to Descriptor if ($Group) { $Descriptor = _getDescriptorForACL -Group $Group } # Resolve User to Descriptor if ($User) { $Descriptor = _getDescriptorForACL -User $User } Add-VSTeamAccessControlEntry -SecurityNamespaceId $securityNamespaceId -Descriptor $Descriptor -Token $token -AllowMask ([int]$Allow) -DenyMask ([int]$Deny) } } function Clear-VSTeamDefaultProject { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")] [CmdletBinding()] param() DynamicParam { # # Only add these options on Windows Machines if (_isOnWindows) { $ParameterName = 'Level' # Create the dictionary $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary # Create the collection of attributes $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] # Create and set the parameters' attributes $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute $ParameterAttribute.Mandatory = $false $ParameterAttribute.HelpMessage = "On Windows machines allows you to store the default project at the process, user or machine level. Not available on other platforms." # Add the attributes to the attributes collection $AttributeCollection.Add($ParameterAttribute) # Generate and set the ValidateSet if (_testAdministrator) { $arrSet = "Process", "User", "Machine" } else { $arrSet = "Process", "User" } $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet) # Add the ValidateSet to the attributes collection $AttributeCollection.Add($ValidateSetAttribute) # Create and return the dynamic parameter $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection) $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter) return $RuntimeParameterDictionary } } begin { if (_isOnWindows) { # Bind the parameter to a friendly variable $Level = $PSBoundParameters[$ParameterName] } } process { if (_isOnWindows) { if (-not $Level) { $Level = "Process" } } else { $Level = "Process" } # You always have to set at the process level or they will Not # be seen in your current session. $env:TEAM_PROJECT = $null if (_isOnWindows) { [System.Environment]::SetEnvironmentVariable("TEAM_PROJECT", $null, $Level) } [VSTeamVersions]::DefaultProject = '' $Global:PSDefaultParameterValues.Remove("*:projectName") Write-Output "Removed default project" } } function Disable-VSTeamAgent { param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [int] $PoolId, [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 1)] [Alias('AgentID')] [int[]] $Id ) process { foreach ($item in $Id) { try { _callAPI -Method Patch -Area "distributedtask/pools/$PoolId" -Resource agents -Id $item -Version $([VSTeamVersions]::DistributedTask) -ContentType "application/json" -Body "{'enabled':false,'id':$item,'maxParallelism':1}" | Out-Null Write-Output "Disabled agent $item" } catch { _handleException $_ } } } } function Enable-VSTeamAgent { param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [int] $PoolId, [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 1)] [Alias('AgentID')] [int[]] $Id ) process { foreach ($item in $Id) { try { _callAPI -Method Patch -Area "distributedtask/pools/$PoolId" -Resource agents -Id $item -Version $([VSTeamVersions]::DistributedTask) -ContentType "application/json" -Body "{'enabled':true,'id':$item,'maxParallelism':1}" | Out-Null Write-Output "Enabled agent $item" } catch { _handleException $_ } } } } function Get-VSTeam { [CmdletBinding(DefaultParameterSetName = 'List')] param ( [Parameter(ParameterSetName = 'List')] [int] $Top, [Parameter(ParameterSetName = 'List')] [int] $Skip, [Parameter(ParameterSetName = 'ByID')] [Alias('TeamId')] [string[]] $Id, [Parameter(ParameterSetName = 'ByName')] [Alias('TeamName')] [string[]] $Name ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($Id) { foreach ($item in $Id) { # Call the REST API $resp = _callAPI -Area 'projects' -Resource "$ProjectName/teams" -id $item ` -Version $([VSTeamVersions]::Core) $team = [VSTeamTeam]::new($resp, $ProjectName) Write-Output $team } } elseif ($Name) { foreach ($item in $Name) { # Call the REST API $resp = _callAPI -Area 'projects' -Resource "$ProjectName/teams" -id $item ` -Version $([VSTeamVersions]::Core) $team = [VSTeamTeam]::new($resp, $ProjectName) Write-Output $team } } else { # Call the REST API $resp = _callAPI -Area 'projects' -Resource "$ProjectName/teams" ` -Version $([VSTeamVersions]::Core) ` -QueryString @{ '$top' = $top '$skip' = $skip } $obj = @() # Create an instance for each one foreach ($item in $resp.value) { $obj += [VSTeamTeam]::new($item, $ProjectName) } Write-Output $obj } } } function Get-VSTeamAccessControlList { [CmdletBinding(DefaultParameterSetName = 'ByNamespace')] param( [Parameter(ParameterSetName = 'ByNamespace', Mandatory = $true, ValueFromPipeline = $true)] [VSTeamSecurityNamespace] $SecurityNamespace, [Parameter(ParameterSetName = 'ByNamespaceId', Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('ID')] [ValidateScript({ try { [System.Guid]::Parse($_) | Out-Null $true } catch { $false } })] [string] $SecurityNamespaceId, [Parameter(ParameterSetName = 'ByNamespace', Mandatory = $false)] [Parameter(ParameterSetName = 'ByNamespaceId', Mandatory = $false)] [string] $Token, [Parameter(ParameterSetName = 'ByNamespace', Mandatory = $false)] [Parameter(ParameterSetName = 'ByNamespaceId', Mandatory = $false)] [string[]] $Descriptors, [Parameter(ParameterSetName = 'ByNamespace', Mandatory = $false)] [Parameter(ParameterSetName = 'ByNamespaceId', Mandatory = $false)] [switch] $IncludeExtendedInfo, [Parameter(ParameterSetName = 'ByNamespace', Mandatory = $false)] [Parameter(ParameterSetName = 'ByNamespaceId', Mandatory = $false)] [switch] $Recurse ) process { if ($SecurityNamespace) { $SecurityNamespaceId = $SecurityNamespace.ID } $queryString = @{} if ($Token) { $queryString.token = $Token } if ($Descriptors -and $Descriptors.Length -gt 0) { $queryString.descriptors = $Descriptors -join "," } if ($IncludeExtendedInfo.IsPresent) { $queryString.includeExtendedInfo = $true } if ($Recurse.IsPresent) { $queryString.recurse = $true } # Call the REST API $resp = _callAPI -Area 'accesscontrollists' -id $SecurityNamespaceId -method GET ` -Version $([VSTeamVersions]::Core) ` -QueryString $queryString try { $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamAccessControlList]::new($item) } Write-Output $objs } catch { # I catch because using -ErrorAction Stop on the Invoke-RestMethod # was still running the foreach after and reporting useless errors. # This casuses the first error to terminate this execution. _handleException $_ } } } function Get-VSTeamAgent { [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [int] $PoolId, [Parameter(ParameterSetName = 'ByID', Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 1)] [Alias('AgentID')] [int] $Id ) process { if ($id) { $resp = _callAPI -Area "distributedtask/pools/$PoolId" -Resource agents -Id $id ` -Body @{includeCapabilities = 'true'} -Version $([VSTeamVersions]::DistributedTask) # Storing the object before you return it cleaned up the pipeline. # When I just write the object from the constructor each property # seemed to be written $item = [VSTeamAgent]::new($resp, $PoolId) Write-Output $item } else { $resp = _callAPI -Area "distributedtask/pools/$PoolId" -Resource agents ` -Body @{includeCapabilities = 'true'} -Version $([VSTeamVersions]::DistributedTask) $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamAgent]::new($item, $PoolId) } Write-Output $objs } } } function Get-VSTeamAPIVersion { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param() return @{ Version = $([VSTeamVersions]::Version) Build = $([VSTeamVersions]::Build) Release = $([VSTeamVersions]::Release) Core = $([VSTeamVersions]::Core) Git = $([VSTeamVersions]::Git) DistributedTask = $([VSTeamVersions]::DistributedTask) VariableGroups = $([VSTeamVersions]::VariableGroups) Tfvc = $([VSTeamVersions]::Tfvc) Packaging = $([VSTeamVersions]::Packaging) TaskGroups = $([VSTeamVersions]::TaskGroups) MemberEntitlementManagement = $([VSTeamVersions]::MemberEntitlementManagement) ExtensionsManagement = $([VSTeamVersions]::ExtensionsManagement) ServiceFabricEndpoint = $([VSTeamVersions]::ServiceFabricEndpoint) Graph = $([VSTeamVersions]::Graph) } } function Get-VSTeamApproval { [CmdletBinding()] param( [ValidateSet('Approved', 'ReAssigned', 'Rejected', 'Canceled', 'Pending', 'Rejected', 'Skipped', 'Undefined')] [string] $StatusFilter, [Alias('ReleaseIdFilter')] [int[]] $ReleaseIdsFilter, [string] $AssignedToFilter ) DynamicParam { _buildProjectNameDynamicParam } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] try { # Build query string and determine if the includeMyGroupApprovals should be added. $queryString = @{statusFilter = $StatusFilter; assignedtoFilter = $AssignedToFilter; releaseIdsFilter = ($ReleaseIdsFilter -join ',')} # The support in TFS and VSTS are not the same. $instance = $(_getInstance) if (_isVSTS $instance) { if ([string]::IsNullOrEmpty($AssignedToFilter) -eq $false) { $queryString.includeMyGroupApprovals = 'true'; } } else { # For TFS all three parameters must be set before you can add # includeMyGroupApprovals. if ([string]::IsNullOrEmpty($AssignedToFilter) -eq $false -and [string]::IsNullOrEmpty($ReleaseIdsFilter) -eq $false -and $StatusFilter -eq 'Pending') { $queryString.includeMyGroupApprovals = 'true'; } } # Call the REST API $resp = _callAPI -ProjectName $ProjectName -Area release -Resource approvals -SubDomain vsrm -Version $([VSTeamVersions]::Release) -QueryString $queryString # Apply a Type Name so we can use custom format view and custom type extensions foreach ($item in $resp.value) { _applyTypesToApproval -item $item } Write-Output $resp.value } catch { _handleException $_ } } } function Get-VSTeamBuild { [CmdletBinding(DefaultParameterSetName = 'List')] param ( [Parameter(ParameterSetName = 'List')] [int] $Top, [Parameter(ParameterSetName = 'List')] [ValidateSet('succeeded', 'partiallySucceeded', 'failed', 'canceled')] [string] $ResultFilter, [Parameter(ParameterSetName = 'List')] [ValidateSet('manual', 'individualCI', 'batchedCI', 'schedule', 'userCreated', 'validateShelveset', 'checkInShelveset', 'triggered', 'all')] [string] $ReasonFilter, [Parameter(ParameterSetName = 'List')] [ValidateSet('inProgress', 'completed', 'cancelling', 'postponed', 'notStarted', 'all')] [string] $StatusFilter, [Parameter(ParameterSetName = 'List')] [int[]] $Queues, [Parameter(ParameterSetName = 'List')] [int[]] $Definitions, [Parameter(ParameterSetName = 'List')] [string] $BuildNumber, [Parameter(ParameterSetName = 'List')] [ValidateSet('build', 'xaml')] [string] $Type, [Parameter(ParameterSetName = 'List')] [int] $MaxBuildsPerDefinition, [Parameter(ParameterSetName = 'List')] [string[]] $Properties, [Parameter(ParameterSetName = 'ByID', ValueFromPipeline = $true)] [Alias('BuildID')] [int[]] $Id ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] try { if ($id) { foreach ($item in $id) { # Build the url to return the single build $resp = _callAPI -ProjectName $projectName -Area 'build' -Resource 'builds' -id $item ` -Version $([VSTeamVersions]::Build) _applyTypesToBuild -item $resp Write-Output $resp } } else { # Build the url to list the builds $resp = _callAPI -ProjectName $projectName -Area 'build' -Resource 'builds' ` -Version $([VSTeamVersions]::Build) ` -Querystring @{ '$top' = $top 'type' = $type 'buildNumber' = $buildNumber 'resultFilter' = $resultFilter 'statusFilter' = $statusFilter 'reasonFilter' = $reasonFilter 'maxBuildsPerDefinition' = $maxBuildsPerDefinition 'queues' = ($queues -join ',') 'properties' = ($properties -join ',') 'definitions' = ($definitions -join ',') } # Apply a Type Name so we can use custom format view and custom type extensions foreach ($item in $resp.value) { _applyTypesToBuild -item $item } Write-Output $resp.value } } catch { _handleException $_ } } } function Get-VSTeamBuildArtifact { param( [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('BuildID')] [int] $Id ) DynamicParam { _buildProjectNameDynamicParam } Process { $ProjectName = $PSBoundParameters["ProjectName"] $resp = _callAPI -ProjectName $projectName -Area 'build' -Resource "builds/$Id/artifacts" ` -Version $([VSTeamVersions]::Build) foreach ($item in $resp.value) { _applyArtifactTypes -item $item } Write-Output $resp.value } } function Get-VSTeamBuildDefinition { [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(ParameterSetName = 'List')] [string] $Filter, [Parameter(ParameterSetName = 'List')] [ValidateSet('build', 'xaml', 'All')] [string] $Type = 'All', [Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'ByIdRaw')] [Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'ByIdJson')] [Parameter(Position = 0, ParameterSetName = 'ByID', Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('BuildDefinitionID')] [int[]] $Id, [Parameter(ParameterSetName = 'ByIdRaw')] [Parameter(ParameterSetName = 'ByIdJson')] [Parameter(ParameterSetName = 'ByID')] [int] $Revision, [Parameter(Mandatory = $true, ParameterSetName = 'ByIdJson')] [switch]$JSON, [Parameter(Mandatory = $true, ParameterSetName = 'ByIdRaw')] [switch]$raw ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($id) { foreach ($item in $id) { $resp = _callAPI -ProjectName $ProjectName -Id $item -Area build -Resource definitions -Version $([VSTeamVersions]::Build) ` -QueryString @{revision = $revision } if ($JSON.IsPresent) { $resp | ConvertTo-Json -Depth 99 } else { if (-not $raw.IsPresent) { $item = [VSTeamBuildDefinition]::new($resp, $ProjectName) Write-Output $item } else { Write-Output $resp } } } } else { $resp = _callAPI -ProjectName $ProjectName -Area build -Resource definitions -Version $([VSTeamVersions]::Build) ` -QueryString @{type = $type; name = $filter; includeAllProperties = $true } $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamBuildDefinition]::new($item, $ProjectName) } Write-Output $objs } } } function Get-VSTeamBuildLog { [CmdletBinding(DefaultParameterSetName = 'ByID')] param ( [Parameter(Mandatory = $true, ParameterSetName = 'ByID', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('BuildID')] [int[]] $Id, [int] $Index ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] foreach ($item in $id) { if (-not $Index) { # Build the url to return the logs of the build # Call the REST API to get the number of logs for the build $resp = _callAPI -ProjectName $projectName -Area 'build' -Resource "builds/$item/logs" ` -Version $([VSTeamVersions]::Build) $fullLogIndex = $($resp.count - 1) } else { $fullLogIndex = $Index } # Now call REST API with the index for the fullLog # Build the url to return the single build # Call the REST API to get the number of logs for the build $resp = _callAPI -ProjectName $projectName -Area 'build' -Resource "builds/$item/logs" -id $fullLogIndex ` -Version $([VSTeamVersions]::Build) Write-Output $resp } } } function Get-VSTeamBuildTag { param( [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('BuildID')] [int] $Id ) DynamicParam { _buildProjectNameDynamicParam } Process { $ProjectName = $PSBoundParameters["ProjectName"] # Call the REST API $resp = _callAPI -ProjectName $projectName -Area 'build' -Resource "builds/$Id/tags" ` -Version $([VSTeamVersions]::Build) return $resp.value } } function Get-VSTeamClassificationNode { [CmdletBinding(DefaultParameterSetName = 'ByIds')] param( [ValidateSet("areas", "iterations")] [Parameter(Mandatory = $true, ParameterSetName="ByPath")] [string] $StructureGroup, [Parameter(Mandatory = $false, ParameterSetName="ByPath")] [string] $Path, [Parameter(Mandatory = $false, ParameterSetName="ByIds")] [int[]] $Ids, [Parameter(Mandatory = $false, ParameterSetName="ByPath")] [Parameter(Mandatory = $false, ParameterSetName="ByIds")] [int] $Depth ) DynamicParam { _buildProjectNameDynamicParam -Mandatory $true } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $id = $StructureGroup $Path = [uri]::UnescapeDataString($Path) if ($Path) { $Path = [uri]::EscapeUriString($Path) $Path = $Path.TrimStart("/") $id += "/$Path" } $queryString = @{} if ($Depth) { $queryString.Add("`$Depth", $Depth) } if ($Ids) { $queryString.Add("Ids", $Ids -join ",") } if ($queryString.Count -gt 0) { # Call the REST API $resp = _callAPI -ProjectName $ProjectName -Area 'wit' -Resource "classificationnodes" -id $id ` -Version $([VSTeamVersions]::Core) ` -QueryString $queryString } else { # Call the REST API $resp = _callAPI -ProjectName $ProjectName -Area 'wit' -Resource "classificationnodes" -id $id ` -Version $([VSTeamVersions]::Core) ` } if ([bool]($resp.PSobject.Properties.name -match "value")) { try { $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamClassificationNode]::new($item, $ProjectName) } Write-Output $objs } catch { # I catch because using -ErrorAction Stop on the Invoke-RestMethod # was still running the foreach after and reporting useless errors. # This casuses the first error to terminate this execution. _handleException $_ } } else { # Storing the object before you return it cleaned up the pipeline. # When I just write the object from the constructor each property # seemed to be written $classificationNode = [VSTeamClassificationNode]::new($resp, $ProjectName) Write-Output $classificationNode } } } function Get-VSTeamCloudSubscription { [CmdletBinding()] param() # Call the REST API $resp = _callAPI -Area 'distributedtask' -Resource 'serviceendpointproxy/azurermsubscriptions' ` -Version $([VSTeamVersions]::DistributedTask) # Apply a Type Name so we can use custom format view and custom type extensions foreach ($item in $resp.value) { _applyTypesToAzureSubscription -item $item } Write-Output $resp.value } function Get-VSTeamDescriptor { [CmdletBinding(DefaultParameterSetName = 'ByStorageKey')] param( [Parameter(ParameterSetName = 'ByStorageKey', Mandatory = $true)] [string] $StorageKey ) process { # This will throw if this account does not support the graph API _supportsGraph # Call the REST API $resp = _callAPI -Area 'graph' -Resource 'descriptors' -id $StorageKey ` -Version $([VSTeamVersions]::Graph) ` -SubDomain 'vssps' # Storing the object before you return it cleaned up the pipeline. # When I just write the object from the constructor each property # seemed to be written $descriptor = [VSTeamDescriptor]::new($resp) Write-Output $descriptor } } function Get-VSTeamExtension { param ( [Parameter(ParameterSetName = 'List', Mandatory = $false)] [switch] $IncludeInstallationIssues, [Parameter(ParameterSetName = 'List', Mandatory = $false)] [switch] $IncludeDisabledExtensions, [Parameter(ParameterSetName = 'List', Mandatory = $false)] [switch] $IncludeErrors, [Parameter(ParameterSetName = 'GetById', Mandatory = $true)] [string] $PublisherId, [Parameter(ParameterSetName = 'GetById', Mandatory = $true)] [string] $ExtensionId ) Process { if ($PublisherId -and $ExtensionId) { $resource = "extensionmanagement/installedextensionsbyname/$PublisherId/$ExtensionId" $resp = _callAPI -SubDomain 'extmgmt' -Resource $resource -Version $([VSTeamVersions]::ExtensionsManagement) $item = [VSTeamExtension]::new($resp) Write-Output $item } else { $queryString = @{} if ($IncludeInstallationIssues.IsPresent) { $queryString.includeCapabilities = $true } if ($IncludeDisabledExtensions.IsPresent) { $queryString.includeDisabledExtensions = $true } if ($IncludeErrors.IsPresent) { $queryString.includeErrors = $true } $resp = _callAPI -SubDomain 'extmgmt' -Resource 'extensionmanagement/installedextensions' -QueryString $queryString -Version $([VSTeamVersions]::ExtensionsManagement) $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamExtension]::new($item) } Write-Output $objs } } } function Get-VSTeamFeed { [CmdletBinding(DefaultParameterSetName = 'List')] param ( [Parameter(ParameterSetName = 'ByID', Position = 0)] [Alias('FeedId')] [string[]] $Id ) process { # Thi swill throw if this account does not support feeds _supportsFeeds if ($id) { foreach ($item in $id) { $resp = _callAPI -subDomain feeds -Id $item -Area packaging -Resource feeds -Version $([VSTeamVersions]::Packaging) Write-Verbose $resp $item = [VSTeamFeed]::new($resp) Write-Output $item } } else { $resp = _callAPI -subDomain feeds -Area packaging -Resource feeds -Version $([VSTeamVersions]::Packaging) $objs = @() foreach ($item in $resp.value) { Write-Verbose $item $objs += [VSTeamFeed]::new($item) } Write-Output $objs } } } function Get-VSTeamGitCommit { [CmdletBinding(DefaultParameterSetName='All')] param ( [Parameter(ParameterSetName = 'All', ValueFromPipelineByPropertyName = $true, Mandatory = $true, Position = 0)] [Parameter(ParameterSetName = 'ItemVersion', ValueFromPipelineByPropertyName = $true, Mandatory = $true, Position = 0)] [Parameter(ParameterSetName = 'CompareVersion', ValueFromPipelineByPropertyName = $true, Mandatory = $true, Position = 0)] [Parameter(ParameterSetName = 'ByIds', ValueFromPipelineByPropertyName = $true, Mandatory = $true, Position = 0)] [Parameter(ParameterSetName = 'ItemPath', ValueFromPipelineByPropertyName = $true, Mandatory = $true, Position = 0)] [Alias('Id')] [Guid] $RepositoryID, [Parameter(ParameterSetName = 'All', HelpMessage="FromDate, in UTC")] [Parameter(ParameterSetName = 'ItemVersion', HelpMessage="FromDate, in UTC")] [Parameter(ParameterSetName = 'CompareVersion', HelpMessage="FromDate, in UTC")] [Parameter(ParameterSetName = 'ItemPath', HelpMessage="FromDate, in UTC")] [DateTime] $FromDate, [Parameter(ParameterSetName = 'All', HelpMessage="ToDate, in UTC")] [Parameter(ParameterSetName = 'ItemVersion', HelpMessage="ToDate, in UTC")] [Parameter(ParameterSetName = 'CompareVersion', HelpMessage="ToDate, in UTC")] [Parameter(ParameterSetName = 'ItemPath', HelpMessage="ToDate, in UTC")] [DateTime] $ToDate, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'ItemVersion', Mandatory = $true)] [Parameter(ParameterSetName = 'CompareVersion')] [Parameter(ParameterSetName = 'ItemPath')] [ValidateSet('branch', 'commit', 'tag')] [string] $ItemVersionVersionType, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'ItemVersion', Mandatory = $true)] [Parameter(ParameterSetName = 'CompareVersion')] [Parameter(ParameterSetName = 'ItemPath')] [string] $ItemVersionVersion, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'ItemVersion', Mandatory = $false)] [Parameter(ParameterSetName = 'CompareVersion')] [Parameter(ParameterSetName = 'ItemPath')] [ValidateSet('firstParent', 'none', 'previousChange')] [string] $ItemVersionVersionOptions, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'CompareVersion', Mandatory = $true)] [Parameter(ParameterSetName = 'ItemVersion')] [Parameter(ParameterSetName = 'ItemPath')] [ValidateSet('branch', 'commit', 'tag')] [string] $CompareVersionVersionType, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'CompareVersion', Mandatory = $true)] [Parameter(ParameterSetName = 'ItemVersion')] [Parameter(ParameterSetName = 'ItemPath')] [string] $CompareVersionVersion, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'CompareVersion', Mandatory = $false)] [Parameter(ParameterSetName = 'ItemVersion')] [Parameter(ParameterSetName = 'ItemPath')] [ValidateSet('firstParent', 'none', 'previousChange')] [string] $CompareVersionVersionOptions, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'ItemVersion')] [Parameter(ParameterSetName = 'CompareVersion')] [Parameter(ParameterSetName = 'ItemPath')] [string] $FromCommitId, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'ItemVersion')] [Parameter(ParameterSetName = 'CompareVersion')] [Parameter(ParameterSetName = 'ItemPath')] [string] $ToCommitId, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'ItemVersion')] [Parameter(ParameterSetName = 'CompareVersion')] [Parameter(ParameterSetName = 'ItemPath')] [string] $Author, [Parameter(ParameterSetName = "ByIds")] [string[]] $Ids, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'ItemPath', Mandatory = $true)] [string] $ItemPath, [Parameter(ParameterSetName = 'ItemPath')] [switch] $ExcludeDeletes, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'ItemVersion')] [Parameter(ParameterSetName = 'CompareVersion')] [Parameter(ParameterSetName = 'ItemPath')] [int] $Top, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'ItemVersion')] [Parameter(ParameterSetName = 'CompareVersion')] [Parameter(ParameterSetName = 'ItemPath')] [int] $Skip, [Parameter(ParameterSetName = 'ItemPath')] [ValidateSet('firstParent','fullHistory','fullHistorySimplifyMerges','simplifiedHistory')] [string] $HistoryMode, [Parameter(ParameterSetName = 'All')] [Parameter(ParameterSetName = 'ItemVersion')] [Parameter(ParameterSetName = 'CompareVersion')] [Parameter(ParameterSetName = 'ItemPath')] [string] $User ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if (($ItemVersionVersionType -eq "commit") -and ($null -eq $ItemVersionVersion -or $ItemVersionVersion -eq '')) { throw "If you have a -ItemVersionVersionType of 'commit' you need to set a commit id as -ItemVersionVersion"; } if (($CompareVersionVersionType -eq "commit") -and ($null -eq $CompareVersionVersion -or $CompareVersionVersion -eq '')) { throw "If you have a -CompareVersionVersionType of 'commit' you need to set a commit id as -CompareVersionVersion"; } try { $queryString = @{ 'searchCriteria.fromDate' = if ($FromDate) { $FromDate.ToString('yyyy-MM-ddTHH:mm:ssZ') } else { $null } 'searchCriteria.toDate' = if ($ToDate) { $ToDate.ToString('yyyy-MM-ddTHH:mm:ssZ') } else { $null } 'searchCriteria.itemVersion.versionType' = $ItemVersionVersionType 'searchCriteria.itemVersion.version' = $ItemVersionVersion 'searchCriteria.itemVersion.versionOptions' = $ItemVersionVersionOptions 'searchCriteria.compareVersion.versionType' = $CompareVersionVersionType 'searchCriteria.compareVersion.version' = $CompareVersionVersion 'searchCriteria.compareVersion.versionOptions' = $CompareVersionVersionOptions 'searchCriteria.fromCommitId' = $FromCommitId 'searchCriteria.toCommitId' = $ToCommitId 'searchCriteria.author' = $Author 'searchCriteria.ids' = $Ids 'searchCriteria.itemPath' = $ItemPath 'searchCriteria.excludeDeletes' = $ExcludeDeletes 'searchCriteria.historyMode' = $HistoryMode 'searchCriteria.$top' = $Top 'searchCriteria.$skip' = $Skip 'searchCriteria.user' = $User } $resp = _callAPI -ProjectName $ProjectName -Id "$RepositoryID/commits" -Area git -Resource repositories -Version $([VSTeamVersions]::Git) -QueryString $queryString $obj = @() foreach ($item in $resp.value) { $obj += [VSTeamGitCommitRef]::new($item, $ProjectName) } Write-Output $obj } catch { throw $_ } } } function Get-VSTeamGitRef { [CmdletBinding()] param ( [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true)] [Alias('Id')] [guid] $RepositoryID, [Parameter()] [string] $Filter, [Parameter()] [string] $FilterContains, [Parameter()] [int] $Top, [Parameter()] [string] $ContinuationToken ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] try { $queryString = @{ '$top' = $Top 'filter' = $Filter 'filterContains' = $FilterContains 'continuationToken' = $continuationToken } $url = _buildRequestURI -Area git -Resource repositories -Version $([VSTeamVersions]::Git) -ProjectName $ProjectName -Id "$RepositoryID/refs" $resp = _callAPI -url $url -QueryString $queryString $obj = @() foreach ($item in $resp.value) { $obj += [VSTeamRef]::new($item, $ProjectName) } Write-Output $obj } catch { throw $_ } } } function Get-VSTeamGitRepository { [CmdletBinding(DefaultParameterSetName = 'ByID')] param ( [Parameter(ParameterSetName = 'ByID', ValueFromPipeline = $true)] [Alias('RepositoryID')] [guid[]] $Id, [Parameter(ParameterSetName = 'ByName', ValueFromPipeline = $true)] [string[]] $Name ) DynamicParam { _buildProjectNameDynamicParam -mandatory $false } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($id) { foreach ($item in $id) { try { $resp = _callAPI -ProjectName $ProjectName -Id $item -Area git -Resource repositories -Version $([VSTeamVersions]::Git) # Storing the object before you return it cleaned up the pipeline. # When I just write the object from the constructor each property # seemed to be written $item = [VSTeamGitRepository]::new($resp, $ProjectName) Write-Output $item } catch { throw $_ } } } elseif ($Name) { foreach ($item in $Name) { try { $resp = _callAPI -ProjectName $ProjectName -Id $item -Area git -Resource repositories -Version $([VSTeamVersions]::Git) # Storing the object before you return it cleaned up the pipeline. # When I just write the object from the constructor each property # seemed to be written $item = [VSTeamGitRepository]::new($resp, $ProjectName) Write-Output $item } catch { throw $_ } } } else { if($ProjectName) { $resp = _callAPI -ProjectName $ProjectName -Area git -Resource repositories -Version $([VSTeamVersions]::Git) } else { $resp = _callAPI -Area git -Resource repositories -Version $([VSTeamVersions]::Git) } $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamGitRepository]::new($item, $ProjectName) } Write-Output $objs } } } function Get-VSTeamGitStat { [CmdletBinding(DefaultParameterSetName = "ByOptionalName")] param ( [Parameter(ParameterSetName = "ByVersion", ValueFromPipelineByPropertyName = $true, Mandatory = $true)] [Parameter(ParameterSetName = "ByOptionalName", ValueFromPipelineByPropertyName = $true, Mandatory = $true)] [Alias('Id')] [guid] $RepositoryId, [Parameter(ParameterSetName = 'ByVersion', Mandatory = $false)] [Parameter(ParameterSetName = 'ByOptionalName', Mandatory = $false)] [string] $BranchName, [ValidateSet("firstParent", "none", "previousChange")] [Parameter(ParameterSetName = 'ByVersion', Mandatory = $false)] [string] $VersionOptions, [Parameter(ParameterSetName = 'ByVersion', Mandatory = $true)] [string] $Version, [Parameter(ParameterSetName = 'ByVersion', Mandatory = $true)] [ValidateSet("branch", "commit", "tag")] [string] $VersionType ) DynamicParam { _buildProjectNameDynamicParam -Mandatory $true } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if (($VersionType -eq "commit") -and ($null -eq $Version -or $Version -eq '')) { throw "If you have a -VersionType of 'commit' you need to set a commit id as -Version"; } try { $queryString = @{ 'name' = $BranchName 'baseVersionDescriptor.versionType' = $VersionType 'baseVersionDescriptor.version' = $Version 'baseVersionDescriptor.versionOptions' = $VersionOptions } $resp = _callAPI -ProjectName $ProjectName -Id "$RepositoryID/stats/branches" -Area git -Resource repositories -Version $([VSTeamVersions]::Git) -QueryString $queryString $hasValueProp = $resp.PSObject.Properties.Match('value') if (0 -eq $hasValueProp.count) { _applyTypes $resp "VSTeam.GitStat" Write-Output $resp } else { $obj = @() foreach ($item in $resp.value) { _applyTypes $item "VSTeam.GitStat" $obj += $item } Write-Output $obj } } catch { throw $_ } } } function Get-VSTeamGroup { [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(ParameterSetName = 'List')] [Parameter(ParameterSetName = 'ListByProjectName')] [ValidateSet('vssgp','aadgp')] [string[]] $SubjectTypes, [Parameter(ParameterSetName = 'List')] [string] $ScopeDescriptor, [Parameter(ParameterSetName = 'ByGroupDescriptor', Mandatory = $true)] [Alias('GroupDescriptor')] [string] $Descriptor ) DynamicParam { # Get-VSTeamGroup should never use cache [VSTeamProjectCache]::timestamp = -1 _buildProjectNameDynamicParam -ParameterSetName 'ListByProjectName' -ParameterName 'ProjectName' } process { # This will throw if this account does not support the graph API _supportsGraph # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($Descriptor) { # Call the REST API $resp = _callAPI -Area 'graph' -Resource 'groups' -id $Descriptor ` -Version $([VSTeamVersions]::Graph) ` -SubDomain 'vssps' # Storing the object before you return it cleaned up the pipeline. # When I just write the object from the constructor each property # seemed to be written $group = [VSTeamGroup]::new($resp) Write-Output $group } else { if ($ProjectName) { $project = Get-VSTeamProject -Name $ProjectName $ScopeDescriptor = Get-VSTeamDescriptor -StorageKey $project.id | Select-Object -ExpandProperty Descriptor } $queryString = @{} if ($ScopeDescriptor) { $queryString.scopeDescriptor = $ScopeDescriptor } if ($SubjectTypes -and $SubjectTypes.Length -gt 0) { $queryString.subjectTypes = $SubjectTypes -join ',' } try { # Call the REST API $resp = _callAPI -Area 'graph' -id 'groups' ` -Version $([VSTeamVersions]::Graph) ` -QueryString $queryString ` -SubDomain 'vssps' $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamGroup]::new($item) } Write-Output $objs } catch { # I catch because using -ErrorAction Stop on the Invoke-RestMethod # was still running the foreach after and reporting useless errors. # This casuses the first error to terminate this execution. _handleException $_ } } } } function Get-VSTeamInfo { return @{ Account = [VSTeamVersions]::Account Version = [VSTeamVersions]::Version ModuleVersion = [VSTeamVersions]::ModuleVersion DefaultProject = $Global:PSDefaultParameterValues['*:projectName'] } } function Get-VSTeamJobRequest { [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [int] $PoolId, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Position = 1)] [Alias('ID')] [int] $AgentID, [int] $completedRequestCount ) process { if ($null -ne $completedRequestCount) { $body = @{ agentid = $AgentID completedRequestCount = $completedRequestCount } } else { $body = @{agentid = $AgentID} } $resp = _callAPI -Area "distributedtask/pools/$PoolId" -Resource "jobrequests" ` -QueryString $body -Version $([VSTeamVersions]::DistributedTask) $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamJobRequest]::new($item) } Write-Output $objs } } function Get-VSTeamMember { [CmdletBinding()] param ( [Parameter()] [int] $Top, [Parameter()] [int] $Skip, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [Alias('Name')] [Alias('Id')] [string] $TeamId ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $resp = _callAPI -Id "$TeamId/members" -Area 'projects' -Resource "$ProjectName/teams" -Version $([VSTeamVersions]::Core) ` -QueryString @{'$top' = $top; '$skip' = $skip} # Apply a Type Name so we can use custom format view and custom type extensions foreach ($item in $resp.value) { _applyTypesToTeamMember -item $item -team $TeamId -ProjectName $ProjectName } Write-Output $resp.value } } function Get-VSTeamMembership { [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline, ValueFromPipelineByPropertyName,ParameterSetName="ByContainerId")] [string] $ContainerDescriptor, [Parameter(Mandatory = $true, ValueFromPipeline, ValueFromPipelineByPropertyName,ParameterSetName="ByMemberId")] [string] $MemberDescriptor ) process { if ($MemberDescriptor) { return _callMembershipAPI -Id $MemberDescriptor -Method Get -Direction Up } else { return _callMembershipAPI -Id $ContainerDescriptor -Method Get -Direction Down } } } function Get-VSTeamOption { [CmdletBinding()] param([string] $subDomain) # Build the url to list the projects $params = @{"Method" = "Options"} if ($subDomain) { $params.Add("SubDomain", $subDomain) } # Call the REST API $resp = _callAPI @params # Apply a Type Name so we can use custom format view and custom type extensions foreach ($item in $resp.value) { _applyTypes -item $item -type 'Team.Option' } Write-Output $resp.value } function Get-VSTeamPermissionInheritance { [OutputType([System.String])] [CmdletBinding()] param( [Parameter(Mandatory, ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true)] [string] $Name, [Parameter(Mandatory)] [ValidateSet('Repository', 'BuildDefinition', 'ReleaseDefinition')] [string] $resourceType ) DynamicParam { _buildProjectNameDynamicParam -mandatory $true } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] Write-Verbose "Creating VSTeamPermissionInheritance" $item = [VSTeamPermissionInheritance]::new($ProjectName, $Name, $resourceType) $token = $item.Token $version = $item.Version $projectID = $item.ProjectID $securityNamespaceID = $item.SecurityNamespaceID Write-Verbose "Token = $token" Write-Verbose "Version = $Version" Write-Verbose "ProjectID = $ProjectID" Write-Verbose "SecurityNamespaceID = $SecurityNamespaceID" if ($resourceType -eq "Repository") { Write-Output (Get-VSTeamAccessControlList -SecurityNamespaceId $securityNamespaceID -token $token | Select-Object -ExpandProperty InheritPermissions) } else { $body = @" { "contributionIds":["ms.vss-admin-web.security-view-data-provider"], "dataProviderContext": { "properties": { "permissionSetId":"$securityNamespaceID", "permissionSetToken":"$token", } } } "@ $resp = _callAPI -method POST -area "Contribution" -resource "HierarchyQuery/project" -id $projectID -Version $version -ContentType "application/json" -Body $body Write-Verbose $($resp | ConvertTo-Json -Depth 99) Write-Output ($resp | Select-Object -ExpandProperty dataProviders | Select-Object -ExpandProperty 'ms.vss-admin-web.security-view-data-provider' | Select-Object -ExpandProperty permissionsContextJson | ConvertFrom-Json | Select-Object -ExpandProperty inheritPermissions) } } } function Get-VSTeamPolicy { [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] [int[]] $Id ) DynamicParam { _buildProjectNameDynamicParam -mandatory $true } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($id) { foreach ($item in $id) { try { $resp = _callAPI -ProjectName $ProjectName -Id $item -Area policy -Resource configurations -Version $([VSTeamVersions]::Git) _applyTypesToPolicy -item $resp Write-Output $resp } catch { throw $_ } } } else { try { $resp = _callAPI -ProjectName $ProjectName -Area policy -Resource configurations -Version $([VSTeamVersions]::Git) # Apply a Type Name so we can use custom format view and custom type extensions foreach ($item in $resp.value) { _applyTypesToPolicy -item $item } Write-Output $resp.value } catch { throw $_ } } } } function Get-VSTeamPolicyType { [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] [guid[]] $Id ) DynamicParam { _buildProjectNameDynamicParam -mandatory $true } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($id) { foreach ($item in $id) { try { $resp = _callAPI -ProjectName $ProjectName -Id $item -Area policy -Resource types -Version $([VSTeamVersions]::Git) _applyTypesToPolicyType -item $resp Write-Output $resp } catch { throw $_ } } } else { try { $resp = _callAPI -ProjectName $ProjectName -Area policy -Resource types -Version $([VSTeamVersions]::Git) # Apply a Type Name so we can use custom format view and custom type extensions foreach ($item in $resp.value) { _applyTypesToPolicyType -item $item } Write-Output $resp.value } catch { throw $_ } } } } function Get-VSTeamPool { [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(ParameterSetName = 'ByID', Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 1)] [Alias('PoolID')] [int] $Id ) process { if ($id) { $resp = _callAPI -Area distributedtask -Resource pools -Id $id -Version $([VSTeamVersions]::DistributedTask) # Storing the object before you return it cleaned up the pipeline. # When I just write the object from the constructor each property # seemed to be written $item = [VSTeamPool]::new($resp) Write-Output $item } else { $resp = _callAPI -Area distributedtask -Resource pools -Version $([VSTeamVersions]::DistributedTask) $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamPool]::new($item) } Write-Output $objs } } } function Get-VSTeamProcess { [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(ParameterSetName = 'List')] [int] $Top = 100, [Parameter(ParameterSetName = 'List')] [int] $Skip = 0, [Parameter(ParameterSetName = 'ByID')] [Alias('ProcessTemplateID')] [string] $Id ) DynamicParam { [VSTeamProcessCache]::timestamp = -1 _buildProcessNameDynamicParam -ParameterSetName 'ByName' -ParameterName 'Name' } process { # Bind the parameter to a friendly variable $ProcessName = $PSBoundParameters["Name"] if ($id) { $queryString = @{} # Call the REST API $resp = _callAPI -Area 'process/processes' -id $id ` -Version $([VSTeamVersions]::Core) ` -QueryString $queryString $project = [VSTeamProcess]::new($resp) Write-Output $project } elseif ($ProcessName) { # Lookup Process ID by Name Get-VSTeamProcess | where-object {$_.name -eq $ProcessName} } else { # Return list of processes try { # Call the REST API $resp = _callAPI -Area 'process/processes' ` -Version $([VSTeamVersions]::Core) ` -QueryString @{ '$top' = $top '$skip' = $skip } $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamProcess]::new($item) } Write-Output $objs } catch { # I catch because using -ErrorAction Stop on the Invoke-RestMethod # was still running the foreach after and reporting useless errors. # This casuses the first error to terminate this execution. _handleException $_ } } } } function Get-VSTeamProfile { [CmdletBinding()] param( # Name is an array so I can pass an array after -Name # I can also use pipe [parameter(Mandatory = $false, Position = 1, ValueFromPipelineByPropertyName = $true)] [string] $Name ) process { if (Test-Path $profilesPath) { try { # We needed to add ForEach-Object to unroll and show the inner type $result = Get-Content $profilesPath | ConvertFrom-Json # convert old URL in profile to new URL if ($result) { $result | ForEach-Object { if ($_.URL -match "(?<protocol>https?\://)?(?<account>[A-Z0-9][-A-Z0-9]*[A-Z0-9])(?<domain>\.visualstudio\.com)") { $_.URL = "https://dev.azure.com/$($matches.account)" } } } if ($Name) { $result = $result | Where-Object Name -eq $Name } if ($result) { $result | ForEach-Object { # Setting the type lets me format it $_.PSObject.TypeNames.Insert(0, 'Team.Profile') if ($_.PSObject.Properties.Match('Token').count -eq 0) { # This is a profile that was created before the module supported # bearer tokens. The rest of the module expects there to be a Token # property. Add one with a value of '' $_ | Add-Member NoteProperty 'Token' '' } $_ } } } catch { # Catch any error and fail to the return empty array below Write-Error "Error ready Profiles file. Use Add-VSTeamProfile to generate new file." } } } } function Get-VSTeamProject { [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(ParameterSetName = 'List')] [ValidateSet('WellFormed', 'CreatePending', 'Deleting', 'New', 'All')] [string] $StateFilter = 'WellFormed', [Parameter(ParameterSetName = 'List')] [int] $Top = 100, [Parameter(ParameterSetName = 'List')] [int] $Skip = 0, [Parameter(ParameterSetName = 'ByID')] [Alias('ProjectID')] [string] $Id, [switch] $IncludeCapabilities ) DynamicParam { # Get-VSTeamProject should never use cache [VSTeamProjectCache]::timestamp = -1 _buildProjectNameDynamicParam -ParameterSetName 'ByName' -ParameterName 'Name' } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["Name"] if ($id) { $ProjectName = $id } if ($ProjectName) { $queryString = @{} if ($includeCapabilities.IsPresent) { $queryString.includeCapabilities = $true } # Call the REST API $resp = _callAPI -Area 'projects' -id $ProjectName ` -Version $([VSTeamVersions]::Core) ` -QueryString $queryString # Storing the object before you return it cleaned up the pipeline. # When I just write the object from the constructor each property # seemed to be written $project = [VSTeamProject]::new($resp) Write-Output $project } else { try { # Call the REST API $resp = _callAPI -Area 'projects' ` -Version $([VSTeamVersions]::Core) ` -QueryString @{ stateFilter = $stateFilter '$top' = $top '$skip' = $skip } $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamProject]::new($item) } Write-Output $objs } catch { # I catch because using -ErrorAction Stop on the Invoke-RestMethod # was still running the foreach after and reporting useless errors. # This casuses the first error to terminate this execution. _handleException $_ } } } } function Get-VSTeamPullRequest { [CmdletBinding(DefaultParameterSetName = "SearchCriteriaWithStatus")] param ( [Alias('PullRequestId')] [Parameter(ParameterSetName = "ById")] [string] $Id, [Parameter(ParameterSetName = "SearchCriteriaWithStatus")] [Parameter(ParameterSetName = "SearchCriteriaWithAll")] [Guid] $RepositoryId, [Parameter(ParameterSetName = "SearchCriteriaWithAll")] [Parameter(ParameterSetName = "SearchCriteriaWithStatus")] [Guid] $SourceRepositoryId, [Parameter(ParameterSetName = "SearchCriteriaWithAll")] [Parameter(ParameterSetName = "SearchCriteriaWithStatus")] [ValidatePattern('^refs/.*')] [string] $SourceBranchRef, [Parameter(ParameterSetName = "SearchCriteriaWithAll")] [Parameter(ParameterSetName = "SearchCriteriaWithStatus")] [ValidatePattern('^refs/.*')] [string] $TargetBranchRef, [Parameter(ParameterSetName = "SearchCriteriaWithStatus")] [ValidateSet("abandoned", "active", "all", "completed", "notSet")] [string] $Status, [Parameter(ParameterSetName = "SearchCriteriaWithAll")] [switch] $All, [Parameter(ParameterSetName = "SearchCriteriaWithAll")] [Parameter(ParameterSetName = "SearchCriteriaWithStatus")] [int] $Top, [Parameter(ParameterSetName = "SearchCriteriaWithAll")] [Parameter(ParameterSetName = "SearchCriteriaWithStatus")] [int] $Skip ) DynamicParam { _buildProjectNameDynamicParam -Mandatory $false } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] try { if ($Id) { if ($ProjectName) { $resp = _callAPI -ProjectName $ProjectName -Area git -Resource pullRequests -Version $([VSTeamVersions]::Git) -Id $Id } else { $resp = _callAPI -Area git -Resource pullRequests -Version $([VSTeamVersions]::Git) -Id $Id } } else { $queryString = @{ 'searchCriteria.sourceRefName' = $SourceBranchRef 'searchCriteria.sourceRepositoryId' = $SourceRepositoryId 'searchCriteria.targetRefName' = $TargetBranchRef 'searchCriteria.status' = if ($All.IsPresent) { 'all' } else { $Status } '$top' = $Top '$skip' = $Skip } if ($RepositoryId) { if ($ProjectName) { $resp = _callAPI -ProjectName $ProjectName -Id "$RepositoryId/pullRequests" -Area git -Resource repositories -Version $([VSTeamVersions]::Git) -QueryString $queryString } else { $resp = _callAPI -Id "$RepositoryId/pullRequests" -Area git -Resource repositories -Version $([VSTeamVersions]::Git) -QueryString $queryString } } else { if ($ProjectName) { $resp = _callAPI -ProjectName $ProjectName -Area git -Resource pullRequests -Version $([VSTeamVersions]::Git) -QueryString $queryString } else { $resp = _callAPI -Area git -Resource pullRequests -Version $([VSTeamVersions]::Git) -QueryString $queryString } } } if ($resp.PSobject.Properties.Name -contains "value") { $pullRequests = $resp.value } else { $pullRequests = $resp } foreach ($respItem in $pullRequests) { _applyTypesToPullRequests -item $respItem } Write-Output $pullRequests } catch { _handleException $_ } } } function Get-VSTeamQueue { [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(ParameterSetName = 'List')] [string] $queueName, [Parameter(ParameterSetName = 'List')] [ValidateSet('None', 'Manage', 'Use')] [string] $actionFilter, [Parameter(ParameterSetName = 'ByID')] [Alias('QueueID')] [string] $id ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($id) { $resp = _callAPI -ProjectName $ProjectName -Id $id -Area distributedtask -Resource queues ` -Version $([VSTeamVersions]::DistributedTask) $item = [VSTeamQueue]::new($resp, $ProjectName) Write-Output $item } else { $resp = _callAPI -ProjectName $projectName -Area distributedtask -Resource queues ` -QueryString @{ queueName = $queueName; actionFilter = $actionFilter } -Version $([VSTeamVersions]::DistributedTask) $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamQueue]::new($item, $ProjectName) } Write-Output $objs } } } function Get-VSTeamRelease { [CmdletBinding(DefaultParameterSetName = 'List')] param( [ValidateSet('environments', 'artifacts', 'approvals', 'none')] [string] $expand, [Parameter(ParameterSetName = 'List')] [ValidateSet('Draft', 'Active', 'Abandoned')] [string] $statusFilter, [Parameter(ParameterSetName = 'List')] [int] $definitionId, [Parameter(ParameterSetName = 'List')] [int] $top, [Parameter(ParameterSetName = 'List')] [string] $createdBy, [Parameter(ParameterSetName = 'List')] [DateTime] $minCreatedTime, [Parameter(ParameterSetName = 'List')] [DateTime] $maxCreatedTime, [Parameter(ParameterSetName = 'List')] [ValidateSet('ascending', 'descending')] [string] $queryOrder, [Parameter(ParameterSetName = 'List')] [string] $continuationToken, [Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'ByIdRaw')] [Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'ByIdJson')] [Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'ByID', ValueFromPipelineByPropertyName = $true)] [Alias('ReleaseID')] [int[]] $id, [Parameter(Mandatory = $true, ParameterSetName = 'ByIdJson')] [switch]$JSON, [Parameter(Mandatory = $true, ParameterSetName = 'ByIdRaw')] [switch]$raw ) DynamicParam { _buildProjectNameDynamicParam -Mandatory $false -Position 1 } process { Write-Debug 'Get-VSTeamRelease Process' # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($id) { foreach ($item in $id) { $resp = _callAPI -SubDomain vsrm -ProjectName $ProjectName -Area release -id $item -Resource releases -Version $([VSTeamVersions]::Release) if ($JSON.IsPresent) { $resp | ConvertTo-Json -Depth 99 } else { if (-not $raw.IsPresent) { # Apply a Type Name so we can use custom format view and custom type extensions _applyTypesToRelease -item $resp } Write-Output $resp } } } else { if ($ProjectName) { $listurl = _buildRequestURI -SubDomain vsrm -ProjectName $ProjectName -Area release -Resource releases -Version $([VSTeamVersions]::Release) } else { $listurl = _buildRequestURI -SubDomain vsrm -Area release -Resource releases -Version $([VSTeamVersions]::Release) } $QueryString = @{ '$top' = $top '$expand' = $expand 'createdBy' = $createdBy 'queryOrder' = $queryOrder 'statusFilter' = $statusFilter 'definitionId' = $definitionId 'minCreatedTime' = $minCreatedTime 'maxCreatedTime' = $maxCreatedTime 'continuationToken' = $continuationToken } # Call the REST API $resp = _callAPI -url $listurl -QueryString $QueryString # Apply a Type Name so we can use custom format view and custom type extensions foreach ($item in $resp.value) { _applyTypesToRelease -item $item } Write-Output $resp.value } } } function Get-VSTeamReleaseDefinition { [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(ParameterSetName = 'List')] [ValidateSet('environments', 'artifacts', 'none')] [string] $Expand = 'none', [Parameter(Mandatory = $true, ParameterSetName = 'ByIdRaw', ValueFromPipelineByPropertyName = $true)] [Parameter(Mandatory = $true, ParameterSetName = 'ByIdJson', ValueFromPipelineByPropertyName = $true)] [Parameter(Mandatory = $true, ParameterSetName = 'ByID', ValueFromPipelineByPropertyName = $true)] [Alias('ReleaseDefinitionID')] [int[]] $Id, [Parameter(Mandatory = $true, ParameterSetName = 'ByIdJson')] [switch]$JSON, [Parameter(Mandatory = $true, ParameterSetName = 'ByIdRaw')] [switch]$raw ) DynamicParam { _buildProjectNameDynamicParam } process { Write-Debug 'Get-VSTeamReleaseDefinition Process' # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($id) { foreach ($item in $id) { $resp = _callAPI -subDomain vsrm -Area release -resource definitions -Version $([VSTeamVersions]::Release) -projectName $projectName -id $item if ($JSON.IsPresent) { $resp | ConvertTo-Json -Depth 99 } else { if (-not $raw.IsPresent) { $item = [VSTeamReleaseDefinition]::new($resp, $ProjectName) Write-Output $item } else { Write-Output $resp } } } } else { $listurl = _buildRequestURI -subDomain vsrm -Area release -resource 'definitions' -Version $([VSTeamVersions]::Release) -projectName $ProjectName if ($expand -ne 'none') { $listurl += "&`$expand=$($expand)" } # Call the REST API $resp = _callAPI -url $listurl $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamReleaseDefinition]::new($item, $ProjectName) } Write-Output $objs } } } function Get-VSTeamResourceArea { [CmdletBinding()] param() # Call the REST API $resp = _callAPI -Resource 'resourceareas' # Apply a Type Name so we can use custom format view and custom type extensions foreach ($item in $resp.value) { _applyTypes -item $item -type 'Team.ResourceArea' } Write-Output $resp.value } function Get-VSTeamSecurityNamespace { [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(ParameterSetName = 'ByNamespaceName', Mandatory = $true)] [string] $Name, [Parameter(ParameterSetName = 'ByNamespaceId', Mandatory = $true)] [ValidateScript({ try { [System.Guid]::Parse($_) | Out-Null $true } catch { $false } })] [string] $Id, [Parameter(ParameterSetName = 'List', Mandatory = $false)] [switch] $LocalOnly ) process { _supportsSecurityNamespace if ($Id) { # Call the REST API $resp = _callAPI -Area 'securitynamespaces' -id $Id ` -Version $([VSTeamVersions]::Core) ` } else { $queryString = @{} if ($LocalOnly.IsPresent) { $queryString.localOnly = $true } $resp = _callAPI -Area 'securitynamespaces' ` -Version $([VSTeamVersions]::Core) ` -QueryString $queryString } Write-Verbose $resp | Select-Object -ExpandProperty value if ($resp.count -le 0) { Write-Output $null } if ($resp.count -gt 1) { # If we only need to find one specific by name if ($Name) { $selected = $resp.value | Where-Object {$_.name -eq $Name} if ($selected) { return [VSTeamSecurityNamespace]::new($selected) } else { return $null } } try { $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamSecurityNamespace]::new($item) } Write-Output $objs } catch { # I catch because using -ErrorAction Stop on the Invoke-RestMethod # was still running the foreach after and reporting useless errors. # This casuses the first error to terminate this execution. _handleException $_ } } else { # Storing the object before you return it cleaned up the pipeline. # When I just write the object from the constructor each property # seemed to be written $acl = [VSTeamSecurityNamespace]::new($resp.value) Write-Output $acl } } } function Get-VSTeamServiceEndpoint { [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(ParameterSetName = 'ByID', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $id ) DynamicParam { _buildProjectNameDynamicParam } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($id) { # Call the REST API $resp = _callAPI -Area 'distributedtask' -Resource 'serviceendpoints' -Id $id ` -Version $([VSTeamVersions]::DistributedTask) -ProjectName $ProjectName _applyTypesToServiceEndpoint -item $resp Write-Output $resp } else { # Call the REST API $resp = _callAPI -ProjectName $ProjectName -Area 'distributedtask' -Resource 'serviceendpoints' ` -Version $([VSTeamVersions]::DistributedTask) # Apply a Type Name so we can use custom format view and custom type extensions foreach ($item in $resp.value) { _applyTypesToServiceEndpoint -item $item } return $resp.value } } } function Get-VSTeamServiceEndpointType { [CmdletBinding()] param( [Parameter(ParameterSetName = 'ByType')] [string] $Type, [Parameter(ParameterSetName = 'ByType')] [string] $Scheme ) Process { if ($Type -ne '' -or $Scheme -ne '') { if ($Type -ne '' -and $Scheme -ne '') { $body = @{ type = $Type scheme = $Scheme } } elseif ($Type -ne '') { $body = @{ type = $Type } } else { $body = @{ scheme = $Scheme } } # Call the REST API $resp = _callAPI -Area 'distributedtask' -Resource 'serviceendpointtypes' ` -Version $([VSTeamVersions]::DistributedTask) -body $body } else { # Call the REST API $resp = _callAPI -Area 'distributedtask' -Resource 'serviceendpointtypes' ` -Version $([VSTeamVersions]::DistributedTask) } # Apply a Type Name so we can use custom format view and custom type extensions foreach ($item in $resp.value) { _applyTypesToServiceEndpointType -item $item } return $resp.value } } function Get-VSTeamTaskGroup { [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(ParameterSetName = 'ByID', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $Id, [Parameter(ParameterSetName = 'ByName', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $Name ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($Id) { $resp = _callAPI -ProjectName $ProjectName -Area distributedtask -Resource taskgroups -Version $([VSTeamVersions]::TaskGroups) -Id $Id -Method Get Write-Output $resp.value } else { $resp = _callAPI -ProjectName $ProjectName -Area distributedtask -Resource taskgroups -Version $([VSTeamVersions]::TaskGroups) -Method Get if ($Name) { if ($resp.value) { foreach ($item in $resp.value) { if ($item.PSObject.Properties.name -contains "name") { if ($Name -eq $item.name) { return $item } } } return $null } else { return $null } } else { foreach ($item in $resp.value) { Write-Output $item } } } } } function Get-VSTeamTfvcBranch { [CmdletBinding()] param( [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Path, [parameter(Mandatory = $false)] [switch] $IncludeChildren = $false, [parameter(Mandatory = $false)] [switch] $IncludeParent = $false, [parameter(Mandatory = $false)] [switch] $IncludeDeleted = $false ) process { foreach ($item in $Path) { $queryString = [ordered]@{ includeChildren = $IncludeChildren; includeParent = $IncludeParent; includeDeleted = $IncludeDeleted; } $resp = _callAPI -Area tfvc -Resource branches -Id $item -QueryString $queryString -Version $([VSTeamVersions]::Tfvc) _applyTypesToTfvcBranch -item $resp Write-Output $resp } } } function Get-VSTeamTfvcRootBranch { [CmdletBinding()] param( [parameter(Mandatory = $false)] [switch] $IncludeChildren = $false, [parameter(Mandatory = $false)] [switch] $IncludeDeleted = $false ) process { $queryString = [ordered]@{ includeChildren = $IncludeChildren; includeDeleted = $IncludeDeleted; } $resp = _callAPI -Area tfvc -Resource branches -QueryString $queryString -Version $([VSTeamVersions]::Tfvc) if ($resp | Get-Member -Name value -MemberType Properties) { foreach ($item in $resp.value) { _applyTypesToTfvcBranch -item $item } Write-Output $resp.value } else { _applyTypesToTfvcBranch -item $resp Write-Output $resp } } } function Get-VSTeamUser { [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(ParameterSetName = 'List')] [ValidateSet('msa','aad','svc','imp','vss')] [string[]] $SubjectTypes, [Parameter(ParameterSetName = 'ByUserDescriptor', Mandatory = $true)] [Alias('UserDescriptor')] [string] $Descriptor ) process { # This will throw if this account does not support the graph API _supportsGraph if ($Descriptor) { # Call the REST API $resp = _callAPI -Area 'graph' -Resource 'users' -id $Descriptor ` -Version $([VSTeamVersions]::Graph) ` -SubDomain 'vssps' # Storing the object before you return it cleaned up the pipeline. # When I just write the object from the constructor each property # seemed to be written $user = [VSTeamUser]::new($resp) Write-Output $user } else { $queryString = @{} if ($SubjectTypes -and $SubjectTypes.Length -gt 0) { $queryString.subjectTypes = $SubjectTypes -join ',' } try { # Call the REST API $resp = _callAPI -Area 'graph' -id 'users' ` -Version $([VSTeamVersions]::Graph) ` -QueryString $queryString ` -SubDomain 'vssps' $objs = @() foreach ($item in $resp.value) { $objs += [VSTeamUser]::new($item) } Write-Output $objs } catch { # I catch because using -ErrorAction Stop on the Invoke-RestMethod # was still running the foreach after and reporting useless errors. # This casuses the first error to terminate this execution. _handleException $_ } } } } function Get-VSTeamUserEntitlement { [CmdletBinding(DefaultParameterSetName = 'List')] param ( [Parameter(ParameterSetName = 'List')] [int] $Top = 100, [Parameter(ParameterSetName = 'List')] [int] $Skip = 0, [Parameter(ParameterSetName = 'List')] [ValidateSet('Projects', 'Extensions', 'Grouprules')] [string[]] $Select, [Parameter(ParameterSetName = 'ByID')] [Alias('UserId')] [string[]] $Id ) process { # Thi swill throw if this account does not support MemberEntitlementManagement _supportsMemberEntitlementManagement if ($Id) { foreach ($item in $Id) { # Build the url to return the single build # Call the REST API $resp = _callAPI -SubDomain 'vsaex' -Version $([VSTeamVersions]::MemberEntitlementManagement) -Resource 'userentitlements' -id $item _applyTypesToUser -item $resp Write-Output $resp } } else { # Build the url to list the teams # $listurl = _buildUserURL $listurl = _buildRequestURI -SubDomain 'vsaex' -Resource 'userentitlements' ` -Version $([VSTeamVersions]::MemberEntitlementManagement) $listurl += _appendQueryString -name "top" -value $top -retainZero $listurl += _appendQueryString -name "skip" -value $skip -retainZero $listurl += _appendQueryString -name "select" -value ($select -join ",") # Call the REST API $resp = _callAPI -url $listurl # Apply a Type Name so we can use custom format view and custom type extensions foreach ($item in $resp.members) { _applyTypesToUser -item $item } Write-Output $resp.members } } } function Get-VSTeamVariableGroup { [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(Position = 0, ParameterSetName = 'ByID', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $Id, [Parameter(Position = 0, ParameterSetName = 'ByName', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $Name ) DynamicParam { _buildProjectNameDynamicParam -Position 1 } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($Id) { # Call the REST API $resp = _callAPI -ProjectName $ProjectName -Area 'distributedtask' -Resource 'variablegroups' ` -Version $([VSTeamVersions]::VariableGroups) -Id $Id _applyTypesToVariableGroup -item $resp Write-Output $resp } else { if ($Name) { $resp = _callAPI -ProjectName $ProjectName -Area 'distributedtask' -Resource 'variablegroups' -Version $([VSTeamVersions]::VariableGroups) -Method Get ` -QueryString @{groupName = $Name} _applyTypesToVariableGroup -item $resp.value Write-Output $resp.value } else { # Call the REST API $resp = _callAPI -ProjectName $ProjectName -Area 'distributedtask' -Resource 'variablegroups' ` -Version $([VSTeamVersions]::VariableGroups) # Apply a Type Name so we can use custom format view and custom type extensions foreach ($item in $resp.value) { _applyTypesToVariableGroup -item $item } return $resp.value } } } } function Get-VSTeamWiql { [CmdletBinding(DefaultParameterSetName = 'ByID')] param( [Parameter(ParameterSetName = 'ByID', Mandatory = $true, Position = 0)] [string] $Id, [Parameter(ParameterSetName = 'ByQuery', Mandatory = $true, Position = 0)] [string] $Query, [Parameter(Mandatory = $true, Position = 1)] [string] $Team, [int] $Top = 100, [Switch] $TimePrecision, [Switch] $Expand ) DynamicParam { #$arrSet = Get-VSTeamProject | Select-Object -ExpandProperty Name _buildProjectNameDynamicParam -mandatory $true #-arrSet $arrSet } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $QueryString = @{ '$top' = $Top timePrecision = $TimePrecision } # Call the REST API if ($Query) { $body = (@{ query = $Query }) | ConvertTo-Json $resp = _callAPI -ProjectName $ProjectName -Team $Team -Area 'wit' -Resource 'wiql' ` -method "POST" -ContentType "application/json" ` -Version $([VSTeamVersions]::Core) ` -Querystring $QueryString ` -Body $body } else { $resp = _callAPI -ProjectName $ProjectName -Team $Team -Area 'wit' -Resource 'wiql' ` -Version $([VSTeamVersions]::Core) -id "$Id" ` -Querystring $QueryString } if ($Expand) { [array]$Ids = $resp.workItems.id $Fields = $resp.columns.referenceName $resp.workItems = @() #splitting id array by 200, since a maximum of 200 ids are allowed per call $countIds = $Ids.Count $resp.workItems = for ($beginRange = 0; $beginRange -lt $countIds; $beginRange += 200) { $endRange = ($beginRange + 199) if ($endRange -gt $countIds) { $idArray = $Ids[$beginRange..($countIds - 1)] } else { $idArray = $Ids[$beginRange..($endRange)] } (Get-VSTeamWorkItem -Fields $Fields -Id $idArray).value } } _applyTypesToWiql -item $resp return $resp } } function Get-VSTeamWorkItem { [CmdletBinding(DefaultParameterSetName = 'ByID')] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [int[]] $Id, [Parameter(ParameterSetName = 'List')] [ValidateSet('fail', 'omit')] [string] $ErrorPolicy = 'omit', [ValidateSet('None', 'Relations', 'Fields', 'Links', 'All')] [string] $Expand = 'None', [string[]] $Fields ) Process { # Call the REST API if ($Id.Length -gt 1) { $resp = _callAPI -Area 'wit' -Resource 'workitems' ` -Version $([VSTeamVersions]::Core) ` -Querystring @{ '$Expand' = $Expand fields = ($Fields -join ',') errorPolicy = $ErrorPolicy ids = ($Id -join ',') } foreach ($item in $resp.value) { _applyTypesToWorkItem -item $item } return $resp.value } else { $a = $Id[0] $resp = _callAPI -Area 'wit' -Resource 'workitems' ` -Version $([VSTeamVersions]::Core) -id "$a" ` -Querystring @{ '$Expand' = $Expand fields = ($Fields -join ',') } _applyTypesToWorkItem -item $resp return $resp } } } function Get-VSTeamWorkItemType { [CmdletBinding(DefaultParameterSetName = 'List')] param() DynamicParam { $dp = _buildProjectNameDynamicParam # If they have not set the default project you can't find the # validateset so skip that check. However, we still need to give # the option to pass a WorkItemType to use. if ($Global:PSDefaultParameterValues["*:projectName"]) { $wittypes = _getWorkItemTypes -ProjectName $Global:PSDefaultParameterValues["*:projectName"] $arrSet = $wittypes } else { Write-Verbose 'Call Set-VSTeamDefaultProject for Tab Complete of WorkItemType' $wittypes = $null $arrSet = $null } $ParameterName = 'WorkItemType' $rp = _buildDynamicParam -ParameterName $ParameterName -arrSet $arrSet -ParameterSetName 'ByType' $dp.Add($ParameterName, $rp) $dp } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $WorkItemType = $PSBoundParameters["WorkItemType"] # Call the REST API if ($WorkItemType) { $resp = _callAPI -ProjectName $ProjectName -Area 'wit' -Resource 'workitemtypes' ` -Version $([VSTeamVersions]::Core) -id $WorkItemType # This call returns JSON with "": which causes the ConvertFrom-Json to fail. # To replace all the "": with "_end": $resp = $resp.Replace('"":', '"_end":') | ConvertFrom-Json _applyTypesWorkItemType -item $resp return $resp } else { $resp = _callAPI -ProjectName $ProjectName -Area 'wit' -Resource 'workitemtypes' ` -Version $([VSTeamVersions]::Core) # This call returns JSON with "": which causes the ConvertFrom-Json to fail. # To replace all the "": with "_end": $resp = $resp.Replace('"":', '"_end":') | ConvertFrom-Json # Apply a Type Name so we can use custom format view and custom type extensions foreach ($item in $resp.value) { _applyTypesWorkItemType -item $item } return $resp.value } } } function Invoke-VSTeamRequest { [CmdletBinding()] param( [string]$resource, [string]$area, [string]$id, [string]$version, [string]$subDomain, [ValidateSet('Get', 'Post', 'Patch', 'Delete', 'Options', 'Put', 'Default', 'Head', 'Merge', 'Trace')] [string]$method, [Parameter(ValueFromPipeline = $true)] [object]$body, [string]$InFile, [string]$OutFile, [switch]$JSON, [string]$ContentType, [string]$Url, [hashtable]$AdditionalHeaders ) DynamicParam { _buildProjectNameDynamicParam -Mandatory $false } process { $params = $PSBoundParameters # We have to remove any extra parameters not used by Invoke-RestMethod $params.Remove('JSON') | Out-Null $output = _callAPI @params if ($JSON.IsPresent) { $output | ConvertTo-Json -Depth 99 } else { $output } } } function Remove-VSTeam { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")] param( [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $true)] [Alias('Name', 'TeamId', 'TeamName')] [string]$Id, [switch]$Force ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($Force -or $PSCmdlet.ShouldProcess($Id, "Delete team")) { # Call the REST API _callAPI -Area 'projects' -Resource "$ProjectName/teams" -Id $Id ` -Method Delete -Version $([VSTeamVersions]::Core) | Out-Null Write-Output "Deleted team $Id" } } } function Remove-VSTeamAccessControlEntry { [CmdletBinding(DefaultParameterSetName = 'byNamespace', SupportsShouldProcess=$true, ConfirmImpact = 'High')] [OutputType([System.String])] param( [Parameter(ParameterSetName = 'byNamespace', Mandatory = $true, ValueFromPipeline = $true)] [VSTeamSecurityNamespace] $securityNamespace, [Parameter(ParameterSetName = 'byNamespaceId', Mandatory = $true)] [guid] $securityNamespaceId, [Parameter(ParameterSetName = 'byNamespace', Mandatory = $true)] [Parameter(ParameterSetName = 'byNamespaceId', Mandatory = $true)] [string] $token, [Parameter(ParameterSetName = 'byNamespace', Mandatory = $true)] [Parameter(ParameterSetName = 'byNamespaceId', Mandatory = $true)] [System.Array] $descriptor ) process { if($securityNamespace) { $securityNamespaceId = ($securityNamespace | Select-Object -ExpandProperty id -ErrorAction SilentlyContinue) } if(($descriptor).count -gt 1) { $descriptor = @() foreach($uniqueDescriptor in $descriptor) { $uniqueDescriptor = ($uniqueDescriptor).split(".")[1] try { $uniqueDescriptor = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("$uniqueDescriptor")) } catch [FormatException]{ Write-Error "Could not convert base64 string to string." continue } $uniqueDescriptor = "Microsoft.TeamFoundation.Identity;"+"$uniqueDescriptor" $descriptor += $uniqueDescriptor } if(($descriptor).count -eq 0) { Write-Error "No valid descriptors provided." return } else { $descriptor = $descriptor -join "," } } else { $descriptor = ($descriptor).split(".")[1] try { $descriptor = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($descriptor)) } catch { trap [FormatException]{} Write-Error "Could not convert base64 string to string." return } $descriptor = "Microsoft.TeamFoundation.Identity;"+"$descriptor" } if($PSCmdlet.ShouldProcess("$token")) { # Call the REST API $resp = _callAPI -method DELETE -Area "accesscontrolentries" -id $securityNamespaceId -ContentType "application/json" -Version $([VSTeamVersions]::Core) -QueryString @{token = $token; descriptors = $descriptor} -ErrorAction SilentlyContinue } switch($resp) { {($resp -eq $true)} { return "Removal of ACE from ACL succeeded." } {($resp -eq $false)} { Write-Error "Removal of ACE from ACL failed. Ensure descriptor and token are correct." return } {($resp -ne $true) -and ($resp -ne $false)} { Write-Error "Unexpected response from REST API." return } } } } function Remove-VSTeamAccessControlList { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High", DefaultParameterSetName = 'ByNamespace')] param( [Parameter(ParameterSetName = 'ByNamespace', Mandatory = $true, ValueFromPipeline = $true)] [VSTeamSecurityNamespace] $SecurityNamespace, [Parameter(ParameterSetName = 'ByNamespaceId', Mandatory = $true)] [ValidateScript({ try { [System.Guid]::Parse($_) | Out-Null $true } catch { $false } })] [string] $SecurityNamespaceId, [Parameter(ParameterSetName = 'ByNamespace', Mandatory = $true)] [Parameter(ParameterSetName = 'ByNamespaceId', Mandatory = $true)] [string[]] $Tokens, [Parameter(ParameterSetName = 'ByNamespace', Mandatory = $false)] [Parameter(ParameterSetName = 'ByNamespaceId', Mandatory = $false)] [switch] $Recurse, [switch] $Force ) process { if ($SecurityNamespace) { $SecurityNamespaceId = $SecurityNamespace.ID } $queryString = @{} if ($Tokens) { $queryString.tokens = $Tokens -join "," } if ($Recurse.IsPresent) { $queryString.recurse = $true } if ($Force -or $pscmdlet.ShouldProcess($queryString.tokens, "Delete ACL")) { # Call the REST API $resp = _callAPI -Area 'accesscontrollists' -id $SecurityNamespaceId -method DELETE ` -Version $([VSTeamVersions]::Core) ` -QueryString $queryString Write-Output $resp } } } function Remove-VSTeamAccount { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param( # Forces the command without confirmation [switch] $Force ) DynamicParam { # Only add this option on Windows Machines if (_isOnWindows) { Write-Verbose 'On a Windows machine' $ParameterName = 'Level' # Create the dictionary $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary # Create the collection of attributes $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] # Create and set the parameters' attributes $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute $ParameterAttribute.Mandatory = $false $ParameterAttribute.HelpMessage = "On Windows machines allows you to store the account information at the process, user or machine level. Not available on other platforms." # Add the attributes to the attributes collection $AttributeCollection.Add($ParameterAttribute) # Generate and set the ValidateSet if (_testAdministrator) { $arrSet = "All", "Process", "User", "Machine" } else { $arrSet = "All", "Process", "User" } $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet) # Add the ValidateSet to the attributes collection $AttributeCollection.Add($ValidateSetAttribute) # Create and return the dynamic parameter $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection) $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter) return $RuntimeParameterDictionary } else { Write-Verbose 'Not on a Windows machine' } } process { if (_isOnWindows) { # Bind the parameter to a friendly variable $Level = $PSBoundParameters[$ParameterName] if (-not $Level) { $Level = "Process" } } else { $Level = "Process" } switch ($Level) { "User" { $whatIf = "user level" } "All" { $whatIf = "all levels" } Default { $whatIf = "$Level level" } } if ($Force -or $pscmdlet.ShouldProcess($whatIf, "Remove Team Account")) { switch ($Level) { "Process" { Write-Verbose "Removing from user level." _clearEnvironmentVariables "Process" } "All" { Write-Verbose "Removing from all levels." Write-Verbose "Removing from proces level." _clearEnvironmentVariables "Process" Write-Verbose "Removing from user level." _clearEnvironmentVariables "User" if (_testAdministrator) { Write-Verbose "Removing from machine level." _clearEnvironmentVariables "Machine" } else { Write-Warning "Must run as administrator to clear machine level." } } Default { Write-Verbose "Removing from $Level level." _clearEnvironmentVariables $Level } } Write-Output "Removed default project and team account information" } } } function Remove-VSTeamAgent { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [int] $PoolId, [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 1)] [Alias('AgentID')] [int[]] $Id, # Forces the command without confirmation [switch] $Force ) process { foreach ($item in $Id) { if ($force -or $pscmdlet.ShouldProcess($item,"Delete agent")) { try { _callAPI -Method Delete -Area "distributedtask/pools/$PoolId" -Resource agents -Id $item -Version $([VSTeamVersions]::DistributedTask) | Out-Null Write-Output "Deleted agent $item" } catch { _handleException $_ } } } } } function Remove-VSTeamBuild { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")] param( [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('BuildID')] [int[]] $Id, [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] foreach ($item in $id) { if ($Force -or $pscmdlet.ShouldProcess($item, "Delete Build")) { try { _callAPI -ProjectName $ProjectName -Area 'build' -Resource 'builds' -id $item ` -Method Delete -Version $([VSTeamVersions]::Build) | Out-Null Write-Output "Deleted build $item" } catch { _handleException $_ } } } } } function Remove-VSTeamBuildDefinition { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [int[]] $Id, # Forces the command without confirmation [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] foreach ($item in $id) { if ($Force -or $pscmdlet.ShouldProcess($item, "Delete Build Definition")) { # Call the REST API _callAPI -Method Delete -ProjectName $ProjectName -Area build -Resource definitions -Id $item -Version $([VSTeamVersions]::Build) | Out-Null Write-Output "Deleted build definition $item" } } } } function Remove-VSTeamBuildTag { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Low")] param( [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [string[]] $Tags, [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('BuildID')] [int[]] $Id, [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { $ProjectName = $PSBoundParameters["ProjectName"] foreach ($item in $id) { if ($Force -or $pscmdlet.ShouldProcess($item, "Remove-VSTeamBuildTag")) { foreach ($tag in $tags) { # Call the REST API _callAPI -ProjectName $projectName -Area 'build' -Resource "builds/$Id/tags" ` -Method Delete -Querystring @{tag = $tag} -Version $([VSTeamVersions]::Build) | Out-Null } } } } } function Remove-VSTeamExtension { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")] param ( [parameter(Mandatory = $true)] [string] $PublisherId, [parameter(Mandatory = $true)] [string] $ExtensionId, [switch] $Force ) if ($Force -or $pscmdlet.ShouldProcess($ExtensionId, "Remove extension")) { $resource = "extensionmanagement/installedextensionsbyname/$PublisherId/$ExtensionId" $resp = _callAPI -Method Delete -SubDomain 'extmgmt' -Resource $resource -Version $([VSTeamVersions]::ExtensionsManagement) Write-Output $resp } } function Remove-VSTeamFeed { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")] param ( [Parameter(ParameterSetName = 'ByID', Position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('FeedId')] [string[]] $Id, # Forces the command without confirmation [switch] $Force ) process { # Thi swill throw if this account does not support feeds _supportsFeeds foreach ($item in $id) { if ($Force -or $pscmdlet.ShouldProcess($item, "Delete Package Feed")) { # Call the REST API _callAPI -subDomain feeds -Method Delete -Id $item -Area packaging -Resource feeds -Version $([VSTeamVersions]::Packaging) | Out-Null Write-Output "Deleted Feed $item" } } } } function Remove-VSTeamGitRepository { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")] param( [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [guid[]] $Id, [switch] $Force ) Process { foreach ($item in $id) { if ($Force -or $pscmdlet.ShouldProcess($item, "Delete Repository")) { try { _callAPI -Method Delete -Id $item -Area git -Resource repositories -Version $([VSTeamVersions]::Git) | Out-Null Write-Output "Deleted repository $item" } catch { _handleException $_ } } } } } function Remove-VSTeamMembership { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")] param( [Parameter(Mandatory = $true)] [string] $MemberDescriptor, [Parameter(Mandatory = $true)] [string] $ContainerDescriptor, [switch] $Force ) process { if ($Force -or $PSCmdlet.ShouldProcess("$MemberDescriptor/$ContainerDescriptor", "Delete Membership")) { return _callMembershipAPI -Id "$MemberDescriptor/$ContainerDescriptor" -Method Delete } } } function Remove-VSTeamPolicy { [CmdletBinding(SupportsShouldProcess = $true)] param( [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [int[]] $Id, [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam -mandatory $true } Process { $ProjectName = $PSBoundParameters["ProjectName"] foreach ($item in $id) { if ($Force -or $pscmdlet.ShouldProcess($item, "Delete Policy")) { try { _callAPI -ProjectName $ProjectName -Method Delete -Id $item -Area policy -Resource configurations -Version $([VSTeamVersions]::Git) | Out-Null Write-Output "Deleted policy $item" } catch { _handleException $_ } } } } } function Remove-VSTeamProfile { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Low")] param( # Name is an array so I can pass an array after -Name # I can also use pipe [parameter(Mandatory = $true, Position = 1, ValueFromPipelineByPropertyName = $true)] [string[]] $Name, [switch] $Force ) begin { $profiles = Get-VSTeamProfile } process { foreach ($item in $Name) { if ($Force -or $pscmdlet.ShouldProcess($item, "Remove-VSTeamProfile")) { # See if this item is already in there $profiles = $profiles | Where-Object Name -ne $item } } } end { $contents = ConvertTo-Json $profiles if ([string]::isnullorempty($contents)) { $contents = '' } Set-Content -Path $profilesPath -Value $contents } } function Remove-VSTeamProject { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")] param( [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam -ParameterName 'Name' -AliasName 'ProjectName' } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["Name"] if ($Force -or $pscmdlet.ShouldProcess($ProjectName, "Delete Project")) { # Call the REST API $resp = _callAPI -Area 'projects' -Id (Get-VSTeamProject $ProjectName).id ` -Method Delete -Version $([VSTeamVersions]::Core) _trackProjectProgress -resp $resp -title 'Deleting team project' -msg "Deleting $ProjectName" # Invalidate any cache of projects. [VSTeamProjectCache]::timestamp = -1 Write-Output "Deleted $ProjectName" } } } function Remove-VSTeamRelease { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [int[]] $Id, # Forces the command without confirmation [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { Write-Debug 'Remove-VSTeamRelease Process' # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] foreach ($item in $id) { if ($force -or $pscmdlet.ShouldProcess($item, "Delete Release")) { Write-Debug 'Remove-VSTeamRelease Call the REST API' try { # Call the REST API _callAPI -Method Delete -SubDomain vsrm -Area release -Resource releases -ProjectName $ProjectName -id $item -Version $([VSTeamVersions]::Release) | Out-Null Write-Output "Deleted release $item" } catch { _handleException $_ } } } } } function Remove-VSTeamReleaseDefinition { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [int[]] $Id, # Forces the command without confirmation [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { Write-Debug 'Remove-VSTeamReleaseDefinition Process' # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] foreach ($item in $id) { if ($force -or $pscmdlet.ShouldProcess($item, "Delete Release Definition")) { _callAPI -Method Delete -subDomain vsrm -Area release -Resource definitions -Version $([VSTeamVersions]::Release) -projectName $ProjectName -id $item | Out-Null Write-Output "Deleted release definition $item" } } } } function Remove-VSTeamServiceEndpoint { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $id, [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] foreach ($item in $id) { if ($Force -or $pscmdlet.ShouldProcess($item, "Delete Service Endpoint")) { # Call the REST API _callAPI -projectName $projectName -Area 'distributedtask' -Resource 'serviceendpoints' -Id $item ` -Method Delete -Version $([VSTeamVersions]::DistributedTask) | Out-Null Write-Output "Deleted service endpoint $item" } } } } function Remove-VSTeamTaskGroup { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Low")] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $Id, [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] foreach ($item in $Id) { if ($Force -or $pscmdlet.ShouldProcess($item, "Delete Task Group")) { # Call the REST API _callAPI -Method Delete -ProjectName $ProjectName -Area distributedtask -Resource taskgroups -Version $([VSTeamVersions]::TaskGroups) -Id $item | Out-Null Write-Output "Deleted task group $item" } } } } function Remove-VSTeamUserEntitlement { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High", DefaultParameterSetName = 'ById')] param( [Parameter(ParameterSetName = 'ById', Mandatory = $True, ValueFromPipelineByPropertyName = $true)] [Alias('UserId')] [string]$Id, [Parameter(ParameterSetName = 'ByEmail', Mandatory = $True, ValueFromPipelineByPropertyName = $true)] [Alias('UserEmail')] [string]$Email, [switch]$Force ) process { # Thi swill throw if this account does not support MemberEntitlementManagement _supportsMemberEntitlementManagement if ($email) { # We have to go find the id $user = Get-VSTeamUserEntitlement | Where-Object email -eq $email if (-not $user) { throw "Could not find user with an email equal to $email" } $id = $user.id } else { $user = Get-VSTeamUserEntitlement -Id $id } if ($Force -or $PSCmdlet.ShouldProcess("$($user.userName) ($($user.email))", "Delete user")) { # Call the REST API _callAPI -Method Delete -SubDomain 'vsaex' -Resource 'userentitlements' -Id $Id -Version $([VSTeamVersions]::MemberEntitlementManagement) | Out-Null Write-Output "Deleted user $($user.userName) ($($user.email))" } } } function Remove-VSTeamVariableGroup { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $id, [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] foreach ($item in $id) { if ($Force -or $pscmdlet.ShouldProcess($item, "Delete Variable Group")) { # Call the REST API _callAPI -projectName $projectName -Area 'distributedtask' -Resource 'variablegroups' -Id $item ` -Method Delete -Version $([VSTeamVersions]::VariableGroups) | Out-Null Write-Output "Deleted variable group $item" } } } } function Remove-VSTeamWorkItem { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High", DefaultParameterSetName = 'ByID')] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [int[]] $Id, [switch] $Destroy, [switch] $Force ) Process { # Call the REST API foreach ($item in $Id) { if ($Force -or $pscmdlet.ShouldProcess($item, "Delete Work Item")) { try { _callAPI -Method Delete -Area wit -Resource workitems ` -Version $([VSTeamVersions]::Core) -id $item ` -Querystring @{ destroy = $Destroy } | Out-Null Write-Output "Deleted Work item with ID $item" } catch { _handleException $_ } } } } } function Set-VSTeamAccount { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Low", DefaultParameterSetName = 'Secure')] param( [parameter(ParameterSetName = 'Windows', Mandatory = $true, Position = 1)] [parameter(ParameterSetName = 'Secure', Mandatory = $true, Position = 1)] [Parameter(ParameterSetName = 'Plain', Mandatory = $true, Position = 1)] [string] $Account, [parameter(ParameterSetName = 'Plain', Mandatory = $true, Position = 2, HelpMessage = 'Personal Access or Bearer Token')] [Alias('Token')] [string] $PersonalAccessToken, [parameter(ParameterSetName = 'Secure', Mandatory = $true, HelpMessage = 'Personal Access or Bearer Token')] [Alias('PAT')] [securestring] $SecurePersonalAccessToken, [parameter(ParameterSetName = 'Windows')] [parameter(ParameterSetName = 'Secure')] [Parameter(ParameterSetName = 'Plain')] [ValidateSet('TFS2017', 'TFS2018', 'AzD2019', 'VSTS', 'AzD')] [string] $Version, [string] $Drive, [parameter(ParameterSetName = 'Secure')] [Parameter(ParameterSetName = 'Plain')] [switch] $UseBearerToken, [switch] $Force ) DynamicParam { # Create the dictionary $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $profileArrSet = Get-VSTeamProfile | Select-Object -ExpandProperty Name if ($profileArrSet) { $profileParam = _buildDynamicParam -ParameterName 'Profile' -ParameterSetName 'Profile' -arrSet $profileArrSet } else { $profileParam = _buildDynamicParam -ParameterName 'Profile' -ParameterSetName 'Profile' } $RuntimeParameterDictionary.Add('Profile', $profileParam) # Only add these options on Windows Machines if (_isOnWindows) { # Generate and set the ValidateSet $arrSet = "Process", "User" if (_testAdministrator) { $arrSet += "Machine" } $levelParam = _buildDynamicParam -ParameterName 'Level' -arrSet $arrSet $RuntimeParameterDictionary.Add('Level', $levelParam) $winAuthParam = _buildDynamicParam -ParameterName 'UseWindowsAuthentication' -Mandatory $true -ParameterSetName 'Windows' -ParameterType ([switch]) $RuntimeParameterDictionary.Add('UseWindowsAuthentication', $winAuthParam) } return $RuntimeParameterDictionary } process { # invalidate cache when changing account/collection # otherwise dynamic parameters being picked for a wrong collection [VSTeamProjectCache]::timestamp = -1 # Bind the parameter to a friendly variable $Profile = $PSBoundParameters['Profile'] if (_isOnWindows) { # Bind the parameter to a friendly variable $Level = $PSBoundParameters['Level'] if (-not $Level) { $Level = "Process" } $UsingWindowsAuth = $PSBoundParameters['UseWindowsAuthentication'] } else { $Level = "Process" } if ($Profile) { $info = Get-VSTeamProfile | Where-Object Name -eq $Profile if ($info) { $encodedPat = $info.Pat $account = $info.URL $version = $info.Version $token = $info.Token } else { Write-Error "The profile provided was not found." return } } else { if ($SecurePersonalAccessToken) { # Convert the securestring to a normal string # this was the one technique that worked on Mac, Linux and Windows $credential = New-Object System.Management.Automation.PSCredential $account, $SecurePersonalAccessToken $_pat = $credential.GetNetworkCredential().Password } else { $_pat = $PersonalAccessToken } # If they only gave an account name add https://dev.azure.com if ($Account -notlike "*/*") { $Account = "https://dev.azure.com/$($Account)" } # If they gave https://xxx.visualstudio.com convert to new URL if ($Account -match "(?<protocol>https?\://)?(?<account>[A-Z0-9][-A-Z0-9]*[A-Z0-9])(?<domain>\.visualstudio\.com)") { $Account = "https://dev.azure.com/$($matches.account)" } if ($UseBearerToken.IsPresent) { $token = $_pat $encodedPat = '' } else { $token = '' $encodedPat = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$_pat")) } # If no SecurePersonalAccessToken is entered, and on windows, are we using default credentials for REST calls if ((!$_pat) -and (_isOnWindows) -and ($UsingWindowsAuth)) { Write-Verbose "Using Default Windows Credentials for authentication; no Personal Access Token required" $encodedPat = '' $token = '' } } if((_isOnWindows) -and ($UsingWindowsAuth) -and $(_isVSTS $Account)) { Write-Error "Windows Auth can only be used with Team Fondation Server or Azure DevOps Server.$([Environment]::NewLine)Provide a Personal Access Token or Bearer Token to connect to Azure DevOps Services." return } if ($Force -or $pscmdlet.ShouldProcess($Account, "Set Account")) { # Piped to null so callers can pipe to Invoke-Expression to mount the drive on one line. Clear-VSTeamDefaultProject *> $null _setEnvironmentVariables -Level $Level -Pat $encodedPat -Acct $account -BearerToken $token -Version $Version Set-VSTeamAPIVersion -Target (_getVSTeamAPIVersion -Instance $account -Version $Version) if ($Drive) { # Assign to null so nothing is writen to output. Write-Output "# To map a drive run the following command or pipe to iex:`nNew-PSDrive -Name $Drive -PSProvider SHiPS -Root 'VSTeam#VSTeamAccount'" } } } } function Set-VSTeamAlias { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Low")] param( [switch] $Force ) if ($Force -or $pscmdlet.ShouldProcess("Set Alias")) { New-Alias ata Set-VSTeamAccount -Scope Global New-Alias sta Set-VSTeamAccount -Scope Global New-Alias gti Get-VSTeamInfo -Scope Global New-Alias ivr Invoke-VSTeamRequest -Scope Global New-Alias Get-ServiceEndpoint Get-VSTeamServiceEndpoint -Scope Global New-Alias Add-AzureRMServiceEndpoint Add-VSTeamAzureRMServiceEndpoint -Scope Global New-Alias Remove-ServiceEndpoint Remove-VSTeamServiceEndpoint -Scope Global New-Alias Add-SonarQubeEndpoint Add-VSTeamSonarQubeEndpoint -Scope Global New-Alias Add-KubernetesEndpoint Add-VSTeamKubernetesEndpoint -Scope Global New-Alias Add-ServiceEndpoint Add-VSTeamServiceEndpoint -Scope Global New-Alias Update-ServiceEndpoint Update-VSTeamServiceEndpoint -Scope Global New-Alias Add-ServiceFabricEndpoint Add-VSTeamServiceFabricEndpoint -Scope Global New-Alias Remove-ServiceFabricEndpoint Remove-VSTeamServiceFabricEndpoint -Scope Global New-Alias Remove-AzureRMServiceEndpoint Remove-VSTeamAzureRMServiceEndpoint -Scope Global New-Alias Remove-SonarQubeEndpoint Remove-VSTeamSonarQubeEndpoint -Scope Global New-Alias Get-Build Get-VSTeamBuild -Scope Global New-Alias Show-Build Show-VSTeamBuild -Scope Global New-Alias Get-BuildLog Get-VSTeamBuildLog -Scope Global New-Alias Get-BuildTag Get-VSTeamBuildTag -Scope Global New-Alias Get-BuildArtifact Get-VSTeamBuildArtifact -Scope Global New-Alias Add-Build Add-VSTeamBuild -Scope Global New-Alias Add-BuildTag Add-VSTeamBuildTag -Scope Global New-Alias Remove-Build Remove-VSTeamBuild -Scope Global New-Alias Remove-BuildTag Remove-VSTeamBuildTag -Scope Global New-Alias Update-Build Update-VSTeamBuild -Scope Global New-Alias Get-BuildDefinition Get-VSTeamBuildDefinition -Scope Global New-Alias Add-BuildDefinition Add-VSTeamBuildDefinition -Scope Global New-Alias Show-BuildDefinition Show-VSTeamBuildDefinition -Scope Global New-Alias Remove-BuildDefinition Remove-VSTeamBuildDefinition -Scope Global New-Alias Show-Approval Show-VSTeamApproval -Scope Global New-Alias Get-Approval Get-VSTeamApproval -Scope Global New-Alias Set-Approval Set-VSTeamApproval -Scope Global New-Alias Get-CloudSubscription Get-VSTeamCloudSubscription -Scope Global New-Alias Get-GitRepository Get-VSTeamGitRepository -Scope Global New-Alias Show-GitRepository Show-VSTeamGitRepository -Scope Global New-Alias Add-GitRepository Add-VSTeamGitRepository -Scope Global New-Alias Remove-GitRepository Remove-VSTeamGitRepository -Scope Global New-Alias Get-Pool Get-VSTeamPool -Scope Global New-Alias Get-Project Get-VSTeamProject -Scope Global New-Alias Show-Project Show-VSTeamProject -Scope Global New-Alias Update-Project Update-VSTeamProject -Scope Global New-Alias Add-Project Add-VSTeamProject -Scope Global New-Alias Remove-Project Remove-VSTeamProject -Scope Global New-Alias Get-Queue Get-VSTeamQueue -Scope Global New-Alias Get-ReleaseDefinition Get-VSTeamReleaseDefinition -Scope Global New-Alias Show-ReleaseDefinition Show-VSTeamReleaseDefinition -Scope Global New-Alias Add-ReleaseDefinition Add-VSTeamReleaseDefinition -Scope Global New-Alias Remove-ReleaseDefinition Remove-VSTeamReleaseDefinition -Scope Global New-Alias Get-Release Get-VSTeamRelease -Scope Global New-Alias Show-Release Show-VSTeamRelease -Scope Global New-Alias Add-Release Add-VSTeamRelease -Scope Global New-Alias Remove-Release Remove-VSTeamRelease -Scope Global New-Alias Set-ReleaseStatus Set-VSTeamReleaseStatus -Scope Global New-Alias Add-ReleaseEnvironment Add-VSTeamReleaseEnvironment -Scope Global New-Alias Get-TeamInfo Get-VSTeamInfo -Scope Global New-Alias Add-TeamAccount Set-VSTeamAccount -Scope Global New-Alias Remove-TeamAccount Remove-VSTeamAccount -Scope Global New-Alias Get-TeamOption Get-VSTeamOption -Scope Global New-Alias Get-TeamResourceArea Get-VSTeamResourceArea -Scope Global New-Alias Clear-DefaultProject Clear-VSTeamDefaultProject -Scope Global New-Alias Set-DefaultProject Set-VSTeamDefaultProject -Scope Global New-Alias Get-TeamMember Get-VSTeamMember -Scope Global New-Alias Get-Team Get-VSTeam -Scope Global New-Alias Add-Team Add-VSTeam -Scope Global New-Alias Update-Team Update-VSTeam -Scope Global New-Alias Remove-Team Remove-VSTeam -Scope Global New-Alias Add-Profile Add-VSTeamProfile -Scope Global New-Alias Remove-Profile Remove-VSTeamProfile -Scope Global New-Alias Get-Profile Get-VSTeamProfile -Scope Global New-Alias Set-APIVersion Set-VSTeamAPIVersion -Scope Global New-Alias Add-UserEntitlement Add-VSTeamUserEntitlement -Scope Global New-Alias Remove-UserEntitlement Remove-VSTeamUserEntitlement -Scope Global New-Alias Get-UserEntitlement Get-VSTeamUserEntitlement -Scope Global New-Alias Update-UserEntitlement Update-VSTeamUserEntitlement -Scope Global New-Alias Set-EnvironmentStatus Set-VSTeamEnvironmentStatus -Scope Global New-Alias Get-ServiceEndpointType Get-VSTeamServiceEndpointType -Scope Global New-Alias Update-BuildDefinition Update-VSTeamBuildDefinition -Scope Global New-Alias Get-TfvcRootBranch Get-VSTeamTfvcRootBranch -Scope Global New-Alias Get-TfvcBranch Get-VSTeamTfvcBranch -Scope Global New-Alias Get-WorkItemType Get-VSTeamWorkItemType -Scope Global New-Alias Add-WorkItem Add-VSTeamWorkItem -Scope Global New-Alias Get-WorkItem Get-VSTeamWorkItem -Scope Global New-Alias Remove-WorkItem Remove-VSTeamWorkItem -Scope Global New-Alias Show-WorkItem Show-VSTeamWorkItem -Scope Global New-Alias Get-Policy Get-VSTeamPolicy -Scope Global New-Alias Get-PolicyType Get-VSTeamPolicyType -Scope Global New-Alias Add-Policy Add-VSTeamPolicy -Scope Global New-Alias Update-Policy Update-VSTeamPolicy -Scope Global New-Alias Remove-Policy Remove-VSTeamPolicy -Scope Global New-Alias Get-GitRef Get-VSTeamGitRef -Scope Global New-Alias Get-Agent Get-VSTeamAgent -Scope Global New-Alias Remove-Agent Remove-VSTeamAgent -Scope Global New-Alias Enable-Agent Enable-VSTeamAgent -Scope Global New-Alias Disable-Agent Disable-VSTeamAgent -Scope Global New-Alias Update-Profile Update-VSTeamProfile -Scope Global New-Alias Get-APIVersion Get-VSTeamAPIVersion -Scope Global New-Alias Add-NuGetEndpoint Add-VSTeamNuGetEndpoint -Scope Global New-Alias Get-Feed Get-VSTeamFeed -Scope Global New-Alias Add-Feed Add-VSTeamFeed -Scope Global New-Alias Show-Feed Show-VSTeamFeed -Scope Global New-Alias Remove-Feed Remove-VSTeamFeed -Scope Global New-Alias Get-PullRequest Get-VSTeamPullRequest -Scope Global New-Alias Show-PullRequest Show-VSTeamPullRequest -Scope Global New-Alias Add-Extension Add-VSTeamExtension -Scope Global New-Alias Get-Extension Get-VSTeamExtension -Scope Global New-Alias Update-Extension Update-VSTeamExtension -Scope Global New-Alias Remove-Extension Remove-VSTeamExtension -Scope Global New-Alias Update-WorkItem Update-VSTeamWorkItem -Scope Global New-Alias Get-JobRequest Get-VSTeamJobRequest -Scope Global New-Alias Update-ReleaseDefinition Update-VSTeamReleaseDefinition -Scope Global } } function Set-VSTeamAPIVersion { [CmdletBinding(DefaultParameterSetName = 'Target', SupportsShouldProcess = $true, ConfirmImpact = "Low")] param( [parameter(ParameterSetName = 'Target', Mandatory = $false, Position = 0)] [ValidateSet('TFS2017', 'TFS2018', 'AzD2019', 'VSTS', 'AzD')] [string] $Target = 'TFS2017', [parameter(ParameterSetName = 'Service', Mandatory = $true, Position = 0)] [ValidateSet('Build', 'Release', 'Core', 'Git', 'DistributedTask', 'VariableGroups', 'Tfvc', 'Packaging', 'MemberEntitlementManagement', 'ExtensionsManagement', 'ServiceFabricEndpoint', 'Graph', 'TaskGroups')] [string] $Service, [parameter(ParameterSetName = 'Service', Mandatory = $true, Position = 1)] [string] $Version, [switch] $Force ) if ($Force -or $pscmdlet.ShouldProcess($Target, "Set-VSTeamAPIVersion")) { if ($PSCmdlet.ParameterSetName -eq 'Service') { switch ($Service) { 'Build' { [VSTeamVersions]::Build = $Version } 'Release' { [VSTeamVersions]::Release = $Version } 'Core' { [VSTeamVersions]::Core = $Version } 'Git' { [VSTeamVersions]::Git = $Version } 'DistributedTask' { [VSTeamVersions]::DistributedTask = $Version } 'VariableGroups' { [VSTeamVersions]::VariableGroups = $Version } 'Tfvc' { [VSTeamVersions]::Tfvc = $Version } 'Packaging' { [VSTeamVersions]::Packaging = $Version } 'MemberEntitlementManagement' { [VSTeamVersions]::MemberEntitlementManagement = $Version } 'ExtensionsManagement' { [VSTeamVersions]::ExtensionsManagement = $Version } 'ServiceFabricEndpoint' { [VSTeamVersions]::ServiceFabricEndpoint = $Version } 'Graph' { [VSTeamVersions]::Graph = $Version } 'TaskGroups' { [VSTeamVersions]::TaskGroups = $Version } } } else { switch ($Target) { 'AzD2019' { [VSTeamVersions]::Version = 'AzD2019' [VSTeamVersions]::Git = '5.0' [VSTeamVersions]::Core = '5.0' [VSTeamVersions]::Build = '5.0' [VSTeamVersions]::Release = '5.0' [VSTeamVersions]::DistributedTask = '5.0' [VSTeamVersions]::VariableGroups = '5.0' [VSTeamVersions]::Tfvc = '5.0' [VSTeamVersions]::Packaging = '' [VSTeamVersions]::MemberEntitlementManagement = '' [VSTeamVersions]::ServiceFabricEndpoint = '5.0' [VSTeamVersions]::ExtensionsManagement = '5.0' [VSTeamVersions]::Graph = '' } 'TFS2018' { [VSTeamVersions]::Version = 'TFS2018' [VSTeamVersions]::Git = '3.2' [VSTeamVersions]::Core = '3.2' [VSTeamVersions]::Build = '3.2' [VSTeamVersions]::Release = '4.0-preview' [VSTeamVersions]::DistributedTask = '4.0-preview' [VSTeamVersions]::VariableGroups = '4.0-preview' [VSTeamVersions]::Tfvc = '3.2' [VSTeamVersions]::Packaging = '' [VSTeamVersions]::TaskGroups = '4.0-preview' [VSTeamVersions]::MemberEntitlementManagement = '' [VSTeamVersions]::ServiceFabricEndpoint = '3.2' [VSTeamVersions]::ExtensionsManagement = '3.2-preview' [VSTeamVersions]::Graph = '' } 'TFS2017' { [VSTeamVersions]::Version = 'TFS2017' [VSTeamVersions]::Git = '3.0' [VSTeamVersions]::Core = '3.0' [VSTeamVersions]::Build = '3.0' [VSTeamVersions]::Release = '3.0-preview' [VSTeamVersions]::DistributedTask = '3.0-preview' [VSTeamVersions]::VariableGroups = '3.2-preview.1' [VSTeamVersions]::Tfvc = '3.0' [VSTeamVersions]::Packaging = '' [VSTeamVersions]::TaskGroups = '3.2-preview.1' [VSTeamVersions]::MemberEntitlementManagement = '' [VSTeamVersions]::ServiceFabricEndpoint = '' [VSTeamVersions]::ExtensionsManagement = '3.0-preview' [VSTeamVersions]::Graph = '' } Default { [VSTeamVersions]::Version = $Target [VSTeamVersions]::Git = '5.1-preview' [VSTeamVersions]::Core = '5.0' [VSTeamVersions]::Build = '5.1-preview' [VSTeamVersions]::Release = '5.1-preview' [VSTeamVersions]::DistributedTask = '5.0-preview' [VSTeamVersions]::VariableGroups = '5.0-preview.1' [VSTeamVersions]::Tfvc = '5.0' [VSTeamVersions]::Packaging = '5.1-preview' [VSTeamVersions]::TaskGroups = '5.1-preview.1' [VSTeamVersions]::MemberEntitlementManagement = '5.1-preview' # This version is never passed to the API but is used to evaluate # if Service Fabric is enabled for the account. Just set it to # match Distributed Task for AzD [VSTeamVersions]::ServiceFabricEndpoint = '5.0-preview' [VSTeamVersions]::ExtensionsManagement = '5.1-preview' [VSTeamVersions]::Graph = '5.1-preview' } } } } Write-Verbose [VSTeamVersions]::Version Write-Verbose "Git: $([VSTeamVersions]::Git)" Write-Verbose "Core: $([VSTeamVersions]::Core)" Write-Verbose "Build: $([VSTeamVersions]::Build)" Write-Verbose "Release: $([VSTeamVersions]::Release)" Write-Verbose "DistributedTask: $([VSTeamVersions]::DistributedTask)" Write-Verbose "VariableGroups: $([VSTeamVersions]::VariableGroups)" Write-Verbose "Tfvc: $([VSTeamVersions]::Tfvc)" Write-Verbose "Packaging: $([VSTeamVersions]::Packaging)" Write-Verbose "TaskGroups: $([VSTeamVersions]::TaskGroups)" Write-Verbose "MemberEntitlementManagement: $([VSTeamVersions]::MemberEntitlementManagement)" Write-Verbose "ServiceFabricEndpoint: $([VSTeamVersions]::ServiceFabricEndpoint)" Write-Verbose "ExtensionsManagement: $([VSTeamVersions]::ExtensionsManagement)" Write-Verbose "Graph: $([VSTeamVersions]::Graph)" } function Set-VSTeamApproval { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [int[]] $Id, [Parameter(Mandatory = $true)] [ValidateSet('Approved', 'Rejected', 'Pending', 'ReAssigned')] [string] $Status, [string] $Approver, [string] $Comment, # Forces the command without confirmation [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { Write-Debug 'Set-VSTeamApproval Process' # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $body = '{ "status": "' + $status + '", "approver": "' + $approver + '", "comments": "' + $comment + '" }' Write-Verbose $body foreach ($item in $id) { if ($force -or $pscmdlet.ShouldProcess($item, "Set Approval Status")) { Write-Debug 'Set-VSTeamApproval Call the REST API' try { # Call the REST API _callAPI -Method Patch -SubDomain vsrm -ProjectName $ProjectName -Area release -Resource approvals ` -Id $item -Version $([VSTeamVersions]::Release) -body $body -ContentType 'application/json' | Out-Null Write-Output "Approval $item status changed to $status" } catch { _handleException $_ } } } } } function Set-VSTeamDefaultProject { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")] [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Low")] param([switch] $Force) DynamicParam { $dp = _buildProjectNameDynamicParam -ParameterName "Project" # Only add these options on Windows Machines if (_isOnWindows) { $ParameterName = 'Level' # Create the collection of attributes $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] # Create and set the parameters' attributes $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute $ParameterAttribute.Mandatory = $false $ParameterAttribute.HelpMessage = "On Windows machines allows you to store the default project at the process, user or machine level. Not available on other platforms." # Add the attributes to the attributes collection $AttributeCollection.Add($ParameterAttribute) # Generate and set the ValidateSet if (_testAdministrator) { $arrSet = "Process", "User", "Machine" } else { $arrSet = "Process", "User" } $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet) # Add the ValidateSet to the attributes collection $AttributeCollection.Add($ValidateSetAttribute) # Create and return the dynamic parameter $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection) $dp.Add($ParameterName, $RuntimeParameter) } return $dp } begin { # Bind the parameter to a friendly variable $Project = $PSBoundParameters["Project"] if (_isOnWindows) { $Level = $PSBoundParameters[$ParameterName] } } process { if ($Force -or $pscmdlet.ShouldProcess($Project, "Set-VSTeamDefaultProject")) { if (_isOnWindows) { if (-not $Level) { $Level = "Process" } # You always have to set at the process level or they will Not # be seen in your current session. $env:TEAM_PROJECT = $Project [VSTeamVersions]::DefaultProject = $Project [System.Environment]::SetEnvironmentVariable("TEAM_PROJECT", $Project, $Level) } $Global:PSDefaultParameterValues["*:projectName"] = $Project } } } function Set-VSTeamEnvironmentStatus { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [Alias('Id')] [int[]] $EnvironmentId, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [int] $ReleaseId, [Parameter(Mandatory = $true, Position = 0)] [ValidateSet('canceled', 'inProgress', 'notStarted', 'partiallySucceeded', 'queued', 'rejected', 'scheduled', 'succeeded', 'undefined')] [Alias('EnvironmentStatus')] [string] $Status, [string] $Comment, [datetime] $ScheduledDeploymentTime, # Forces the command without confirmation [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam -Position 1 } Process { Write-Debug 'Set-VSTeamEnvironmentStatus Process' # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $body = ConvertTo-Json ([PSCustomObject]@{status = $Status; comment = $Comment; scheduledDeploymentTime = $ScheduledDeploymentTime}) foreach ($item in $EnvironmentId) { if ($force -or $pscmdlet.ShouldProcess($item, "Set Status on Environment")) { Write-Debug 'Set-VSTeamEnvironmentStatus Call the REST API' try { # Call the REST API _callAPI -Method Patch -SubDomain vsrm -Area release -Resource "releases/$ReleaseId/environments" -projectName $ProjectName -id $item ` -body $body -ContentType 'application/json' -Version $([VSTeamVersions]::Release) | Out-Null Write-Output "Environment $item status changed to $status" } catch { _handleException $_ } } } } } function Set-VSTeamPermissionInheritance { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] [OutputType([System.String])] param( [Parameter(Mandatory, ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true)] [string] $Name, [Parameter(Mandatory)] [ValidateSet('Repository', 'BuildDefinition', 'ReleaseDefinition')] [string] $ResourceType, [Parameter(Mandatory)] [bool] $NewState, # Forces the command without confirmation [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam -mandatory $true } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] Write-Verbose "Creating VSTeamPermissionInheritance" $item = [VSTeamPermissionInheritance]::new($ProjectName, $Name, $ResourceType) $token = $item.Token $version = $item.Version $projectID = $item.ProjectID $securityNamespaceID = $item.SecurityNamespaceID Write-Verbose "Token = $token" Write-Verbose "Version = $Version" Write-Verbose "ProjectID = $ProjectID" Write-Verbose "SecurityNamespaceID = $SecurityNamespaceID" if ($force -or $PSCmdlet.ShouldProcess($Name, "Set Permission Inheritance")) { # The case of the state is important. It must be lowercase. $body = @" { "contributionIds":["ms.vss-admin-web.security-view-update-data-provider"], "dataProviderContext": { "properties": { "changeInheritance":true, "permissionSetId":"$securityNamespaceID", "permissionSetToken":"$token", "inheritPermissions":$($NewState.ToString().ToLower()) } } } "@ # Call the REST API to change the inheritance state $resp = _callAPI -method POST -area "Contribution" -resource "HierarchyQuery" -id $projectID -Version $version -ContentType "application/json" -Body $body } Write-Verbose "Result: $(ConvertTo-Json -InputObject $resp -Depth 100)" if (($resp | Select-Object -ExpandProperty dataProviders | Select-Object -ExpandProperty 'ms.vss-admin-web.security-view-update-data-provider' | Select-Object -ExpandProperty statusCode) -eq "204") { Return "Inheritance successfully changed for $ResourceType $Name." } else { Write-Error "Inheritance change failed for $ResourceType $Name." Return } } } function Set-VSTeamReleaseStatus { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [int[]] $Id, [ValidateSet('Active', 'Abandoned')] [string] $Status, # Forces the command without confirmation [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { Write-Debug 'Set-VSTeamReleaseStatus Process' # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $body = '{ "id": ' + $id + ', "status": "' + $status + '" }' foreach ($item in $id) { if ($force -or $pscmdlet.ShouldProcess($item, "Set status on Release")) { Write-Debug 'Set-VSTeamReleaseStatus Call the REST API' try { # Call the REST API _callAPI -Method Patch -SubDomain vsrm -Area release -Resource releases -projectName $ProjectName -id $item ` -body $body -ContentType 'application/json' -Version $([VSTeamVersions]::Release) | Out-Null Write-Output "Release $item status changed to $status" } catch { _handleException $_ } } } } } function Show-VSTeam { [CmdletBinding()] param () process { _hasAccount Show-Browser "$(_getInstance)" } } function Show-VSTeamApproval { [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [Alias('Id')] [int] $ReleaseDefinitionId ) DynamicParam { _buildProjectNameDynamicParam } Process { Write-Debug 'Show-VSTeamApproval Process' # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] Show-Browser "$(_getInstance)/$ProjectName/_release?releaseId=$ReleaseDefinitionId" } } function Show-VSTeamBuild { [CmdletBinding(DefaultParameterSetName = 'ByID')] param ( [Parameter(ParameterSetName = 'ByID', ValueFromPipelineByPropertyName = $true)] [Alias('BuildID')] [int[]] $Id ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] Show-Browser "$(_getInstance)/$ProjectName/_build/index?buildId=$Id" } } function Show-VSTeamBuildDefinition { [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(ParameterSetName = 'List')] [string] $Filter, [Parameter(ParameterSetName = 'List')] [ValidateSet('Mine', 'All', 'Queued', 'XAML')] [string] $Type = 'All', [Parameter(ParameterSetName = 'ByID', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [Alias('BuildDefinitionID')] [int[]] $Id, [Parameter(ParameterSetName = 'List')] [string] $Path = '\' ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] # Build the url $url = "$(_getInstance)/$ProjectName/_build" if ($id) { $url += "/index?definitionId=$id" } else { switch ($type) { 'Mine' { $url += '/index?_a=mine&path=' } 'XAML' { $url += '/xaml&path=' } 'Queued' { $url += '/index?_a=queued&path=' } Default { # All $url += '/index?_a=allDefinitions&path=' } } # Make sure path starts with \ if ($Path[0] -ne '\') { $Path = '\' + $Path } $url += [System.Web.HttpUtility]::UrlEncode($Path) } Show-Browser $url } } function Show-VSTeamFeed { [CmdletBinding()] param( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [Alias('ID')] [string] $Name ) process { _hasAccount Show-Browser "$(_getInstance)/_packaging?feed=$Name&_a=feed" } } function Show-VSTeamGitRepository { [CmdletBinding()] param ( [Parameter(ValueFromPipelineByPropertyName = $true)] [string] $RemoteUrl ) DynamicParam { _buildProjectNameDynamicParam -mandatory $false } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($RemoteUrl) { Show-Browser $RemoteUrl } else { Show-Browser "$(_getInstance)/_git/$ProjectName" } } } function Show-VSTeamProject { [CmdletBinding(DefaultParameterSetName = 'ByName')] param( [Parameter(ParameterSetName = 'ByID')] [Alias('ProjectID')] [string] $Id ) DynamicParam { _buildProjectNameDynamicParam -ParameterSetName 'ByName' -ParameterName 'Name' -AliasName 'ProjectName' } process { _hasAccount # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["Name"] if ($id) { $ProjectName = $id } Show-Browser "$(_getInstance)/$ProjectName" } } function Show-VSTeamPullRequest { [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [Alias('PullRequestId')] [int] $Id ) process { try { $pullRequest = Get-VSTeamPullRequest -PullRequestId $Id $projectName = [uri]::EscapeDataString($pullRequest.repository.project.name) $repositoryId = $pullRequest.repositoryName Show-Browser "$(_getInstance)/$projectName/_git/$repositoryId/pullrequest/$Id" } catch { _handleException $_ } } } function Show-VSTeamRelease { [CmdletBinding(DefaultParameterSetName = 'ById')] param( [Parameter(ParameterSetName = 'ByID', ValueFromPipelineByPropertyName = $true, Mandatory = $true, Position = 1)] [Alias('ReleaseID')] [int] $id ) DynamicParam { _buildProjectNameDynamicParam } process { Write-Debug 'Show-VSTeamRelease Process' if ($id -lt 1) { Throw "$id is not a valid id. Value must be greater than 0." } # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] # Build the url Show-Browser "$(_getInstance)/$ProjectName/_release?releaseId=$id" } } function Show-VSTeamReleaseDefinition { [CmdletBinding()] param( [Parameter(ParameterSetName = 'ByID', ValueFromPipelineByPropertyName = $true)] [Alias('ReleaseDefinitionID')] [int] $Id ) DynamicParam { _buildProjectNameDynamicParam } process { Write-Debug 'Show-VSTeamReleaseDefinition Process' # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] # Build the url $url = "$(_getInstance)/$ProjectName/_release" if ($id) { $url += "?definitionId=$id" } Show-Browser $url } } function Show-VSTeamWorkItem { [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [Alias('WorkItemID')] [int] $Id ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] Show-Browser "$(_getInstance)/$ProjectName/_workitems/edit/$Id" } } function Test-VSTeamMembership { [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = "MemberDescriptor")] [string] $MemberDescriptor, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = "ContainerDescriptor")] [string] $ContainerDescriptor ) process { Set-StrictMode -Version Latest $PrevWarningPreference = $WarningPreference try { $WarningPreference = "SilentlyContinue" # avoid 404 warning, since that indicates it doesn't exist $null = _callMembershipAPI -Id "$MemberDescriptor/$ContainerDescriptor" -Method Head return $true } catch { $WarningPreference = $PrevWarningPreference $e = $_ try { if ($e.Exception -and $e.Exception.Response -and $e.Exception.Response.StatusCode -eq [System.Net.HttpStatusCode]::NotFound) { return $false } } catch { Write-Warning "Nested exception $_" } throw $e } finally { $WarningPreference = $PrevWarningPreference } } } function Test-VSTeamYamlPipeline { [CmdletBinding(DefaultParameterSetName = 'WithFilePath')] param( [Parameter(ParameterSetName = 'WithFilePath', Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 1)] [Parameter(ParameterSetName = 'WithYamlOverride', Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 1)] [Int32] $PipelineId, [Parameter(ParameterSetName = 'WithFilePath', Mandatory = $false)] [string] $FilePath, [Parameter(ParameterSetName = 'WithYamlOverride', Mandatory = $false)] [string] $YamlOverride ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $body = @{ PreviewRun = $true } if ($FilePath) { $body.YamlOverride = [string](Get-Content -raw $FilePath) } elseif ($YamlOverride) { $body.YamlOverride = $YamlOverride } try { # Call the REST API $resp = _callAPI -ProjectName $ProjectName -Area 'pipelines' -Resource "$PipelineId" -id "runs" ` -Method Post -ContentType 'application/json; charset=utf-8' -Body ($body | ConvertTo-Json) ` -Version $([VSTeamVersions]::Build) } catch { if ($PSItem -match 'PipelineValidationException') { Write-Error (($PSItem | ConvertFrom-Json).message -replace '/azure-pipelines.yml( ?: ?)? ?', '') return } else { throw } } _applyTypesToYamlPipelineResultType -item $resp return $resp } } function Update-VSTeam { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param( [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $true)] [Alias('TeamName', 'TeamId', 'TeamToUpdate', 'Id')] [string]$Name, [string]$NewTeamName, [string]$Description, [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if (-not $NewTeamName -and -not $Description) { throw 'You must provide a new team name or description, or both.' } if ($Force -or $pscmdlet.ShouldProcess($Name, "Update-VSTeam")) { if (-not $NewTeamName) { $body = '{"description": "' + $Description + '" }' } if (-not $Description) { $body = '{ "name": "' + $NewTeamName + '" }' } if ($NewTeamName -and $Description) { $body = '{ "name": "' + $NewTeamName + '", "description": "' + $Description + '" }' } # Call the REST API $resp = _callAPI -Area 'projects' -Resource "$ProjectName/teams" -Id $Name ` -Method Patch -ContentType 'application/json' -Body $body -Version $([VSTeamVersions]::Core) # Storing the object before you return it cleaned up the pipeline. # When I just write the object from the constructor each property # seemed to be written $team = [VSTeamTeam]::new($resp, $ProjectName) Write-Output $team } } } function Update-VSTeamAgent { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [int] $PoolId, [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 1)] [Alias('AgentID')] [int[]] $Id, [switch] $Force ) process { foreach ($item in $Id) { try { if ($Force -or $pscmdlet.ShouldProcess($item, "Update-VSTeamAgent")) { _callAPI -Method Post -Area "distributedtask/pools/$PoolId" -Resource messages -QueryString @{agentId = $item} -Version $([VSTeamVersions]::DistributedTask) -ContentType "application/json" | Out-Null Write-Output "Update agent $item" } } catch { _handleException $_ } } } } function Update-VSTeamBuild { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param( [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('BuildID')] [Int] $Id, [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [bool] $KeepForever, [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string] $BuildNumber, [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { $ProjectName = $PSBoundParameters["ProjectName"] if ($Force -or $pscmdlet.ShouldProcess($Id, "Update-VSTeamBuild")) { $body = '{' $items = New-Object System.Collections.ArrayList if ($null -ne $KeepForever) { $items.Add("`"keepForever`": $($KeepForever.ToString().ToLower())") > $null } if ($null -ne $buildNumber -and $buildNumber.Length -gt 0) { $items.Add("`"buildNumber`": `"$BuildNumber`"") > $null } if ($null -ne $items -and $items.count -gt 0) { $body += ($items -join ", ") } $body += '}' # Call the REST API _callAPI -ProjectName $ProjectName -Area 'build' -Resource 'builds' -Id $Id ` -Method Patch -ContentType 'application/json' -body $body -Version $([VSTeamVersions]::Build) | Out-Null } } } function Update-VSTeamBuildDefinition { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium", DefaultParameterSetName = 'JSON')] Param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [int] $Id, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'File')] [string] $InFile, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'JSON')] [string] $BuildDefinition, # Forces the command without confirmation [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($Force -or $pscmdlet.ShouldProcess($Id, "Update Build Definition")) { # Call the REST API if ($InFile) { _callAPI -Method Put -ProjectName $ProjectName -Area build -Resource definitions -Id $Id -Version $([VSTeamVersions]::Build) -InFile $InFile -ContentType 'application/json' | Out-Null } else { _callAPI -Method Put -ProjectName $ProjectName -Area build -Resource definitions -Id $Id -Version $([VSTeamVersions]::Build) -Body $BuildDefinition -ContentType 'application/json' | Out-Null } } } } function Update-VSTeamExtension { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param ( [parameter(Mandatory = $true)] [string] $PublisherId, [parameter(Mandatory = $true)] [string] $ExtensionId, [parameter(Mandatory = $true)] [ValidateSet('none', 'disabled')] [string] $ExtensionState, [switch] $Force ) if ($Force -or $pscmdlet.ShouldProcess($ExtensionId, "Update extension")) { $obj = @{ extensionId = $ExtensionId publisherId = $PublisherId installState = @{ flags = $ExtensionState } } $body = $obj | ConvertTo-Json $resp = _callAPI -Method Patch -body $body -SubDomain 'extmgmt' -Resource 'extensionmanagement/installedextensions' -Version $([VSTeamVersions]::ExtensionsManagement) -ContentType "application/json" $item = [VSTeamExtension]::new($resp) Write-Output $item } } function Update-VSTeamPolicy { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param( [Parameter(Mandatory = $true)] [int] $id, [Parameter(Mandatory = $false)] [guid] $type, [switch] $enabled, [switch] $blocking, [Parameter(Mandatory = $true)] [hashtable] $settings, [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam -mandatory $true } process { $ProjectName = $PSBoundParameters["ProjectName"] if (-not $type) { $policy = Get-VSTeamPolicy -ProjectName $ProjectName -Id $id | Select-Object -First 1 $type = $policy.type.id } $body = @{ isEnabled = $enabled.IsPresent; isBlocking = $blocking.IsPresent; type = @{ id = $type } settings = $settings } | ConvertTo-Json -Depth 10 -Compress try { if ($Force -or $pscmdlet.ShouldProcess($id, "Update Policy")) { # Call the REST API $resp = _callAPI -ProjectName $ProjectName -Area 'policy' -id $id -Resource 'configurations' ` -Method Put -ContentType 'application/json' -Body $body -Version $([VSTeamVersions]::Git) Write-Output $resp } } catch { _handleException $_ } } } function Update-VSTeamProfile { [CmdletBinding(DefaultParameterSetName = 'Secure', SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param( [parameter(ParameterSetName = 'Plain', Mandatory = $true, HelpMessage = 'Personal Access Token')] [string] $PersonalAccessToken, [parameter(ParameterSetName = 'Secure', Mandatory = $true, HelpMessage = 'Personal Access Token')] [securestring] $SecurePersonalAccessToken, [switch] $Force ) DynamicParam { # Create the dictionary $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $profileArrSet = Get-VSTeamProfile | Select-Object -ExpandProperty Name if ($profileArrSet) { $profileParam = _buildDynamicParam -ParameterName 'Name' -Mandatory $true -Position 0 -arrSet $profileArrSet } else { $profileParam = _buildDynamicParam -ParameterName 'Name' -Mandatory $true -Position 0 } $RuntimeParameterDictionary.Add('Name', $profileParam) return $RuntimeParameterDictionary } process { $Name = $PSBoundParameters['Name'] if ($Force -or $pscmdlet.ShouldProcess($Name, "Update-VSTeamProfile")) { if ($SecurePersonalAccessToken) { # Even when promoted for a Secure Personal Access Token you can just # press enter. This leads to an empty PAT so error below. # Convert the securestring to a normal string # this was the one technique that worked on Mac, Linux and Windows $_pat = _convertSecureStringTo_PlainText -SecureString $SecurePersonalAccessToken } else { $_pat = $PersonalAccessToken } $token = '' $authType = 'Pat' $encodedPat = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":$_pat")) $profile = Get-VSTeamProfile | Where-Object Name -eq $Name if ($profile) { # See if this item is already in there # I am testing URL because the user may provide a different # name and I don't want two with the same URL. # The @() forces even 1 item to an array # Now get an array of all profiles but this one and update this one. $profiles = @(Get-VSTeamProfile | Where-Object Name -ne $Name) $newProfile = [PSCustomObject]@{ Name = $Name URL = $profile.URL Type = $authType Pat = $encodedPat Token = $token Version = $profile.Version } $profiles += $newProfile $contents = ConvertTo-Json $profiles Set-Content -Path $profilesPath -Value $contents } else { # This will happen when they don't have any profiles. Write-Warning 'Profile not found' } } } } function Update-VSTeamProject { [CmdletBinding(DefaultParameterSetName = 'ByName', SupportsShouldProcess = $true, ConfirmImpact = "High")] param( [string] $NewName = '', [string] $NewDescription = '', [switch] $Force, [Parameter(ParameterSetName = 'ByID', ValueFromPipelineByPropertyName = $true)] [string] $Id ) DynamicParam { _buildProjectNameDynamicParam -ParameterName 'Name' -AliasName 'ProjectName' -ParameterSetName 'ByName' -Mandatory $false } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["Name"] if ($id) { $ProjectName = $id } else { $id = (Get-VSTeamProject $ProjectName).id } if ($newName -eq '' -and $newDescription -eq '') { # There is nothing to do Write-Verbose 'Nothing to update' return } if ($Force -or $pscmdlet.ShouldProcess($ProjectName, "Update Project")) { # At the end we return the project and need it's name # this is used to track the final name. $finalName = $ProjectName if ($newName -ne '' -and $newDescription -ne '') { $finalName = $newName $msg = "Changing name and description" $body = '{"name": "' + $newName + '", "description": "' + $newDescription + '"}' } elseif ($newName -ne '') { $finalName = $newName $msg = "Changing name" $body = '{"name": "' + $newName + '"}' } else { $msg = "Changing description" $body = '{"description": "' + $newDescription + '"}' } # Call the REST API $resp = _callAPI -Area 'projects' -id $id ` -Method Patch -ContentType 'application/json' -body $body -Version $([VSTeamVersions]::Core) _trackProjectProgress -resp $resp -title 'Updating team project' -msg $msg # Invalidate any cache of projects. [VSTeamProjectCache]::timestamp = -1 # Return the project now that it has been updated return Get-VSTeamProject -Id $finalName } } } function Update-VSTeamPullRequest { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High", DefaultParameterSetName = 'Draft')] param( [Parameter(ValueFromPipelineByPropertyName = $true, Mandatory = $true, Position = 0)] [Alias('Id')] [Guid] $RepositoryId, [Parameter(Mandatory = $true)] [int] $PullRequestId, [Parameter(ParameterSetName = "Status", Mandatory = $true)] [ValidateSet("abandoned", "active", "completed", "notSet")] [string] $Status, [Parameter(ParameterSetName = "EnableAutoComplete", Mandatory = $true)] [Switch] $EnableAutoComplete, [Parameter(ParameterSetName = "EnableAutoComplete", Mandatory = $true)] [VSTeamUser] $AutoCompleteIdentity, [Parameter(ParameterSetName = "DisableAutoComplete", Mandatory = $true)] [Switch] $DisableAutoComplete, [Parameter(ParameterSetName = "Draft", Mandatory = $false)] [switch] $Draft, [switch] $Force ) process { if ($Force -or $pscmdlet.ShouldProcess($PullRequestId, "Update Pull Request ID")) { if ($Draft.IsPresent) { $body = '{"isDraft": true }' } else { $body = '{"isDraft": false }' } if ($EnableAutoComplete.IsPresent) { $body = '{"autoCompleteSetBy": "' + $AutoCompleteIdentity.Descriptor + '"}' } if ($DisableAutoComplete.IsPresent) { $body = '{"autoCompleteSetBy": null}' } if ($Status) { $body = '{"status": "' + $Status + '"}' } # Call the REST API $resp = _callAPI -Area git -Resource repositories -iD "$RepositoryId/pullrequests/$PullRequestId" ` -Method Patch -ContentType 'application/json' -body $body -Version $([VSTeamVersions]::Git) _applyTypesToPullRequests -item $resp Write-Output $resp } } } function Update-VSTeamRelease { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [int] $Id, [Parameter(Mandatory = $true)] [PSCustomObject] $Release, [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $body = $Release | ConvertTo-Json -Depth 99 if ($Force -or $pscmdlet.ShouldProcess($Id, "Update Release")) { # Call the REST API $resp = _callAPI -ProjectName $projectName -SubDomain vsrm -Area release -Resource releases -Id $id ` -Method Put -ContentType 'application/json' -body $body -Version $([VSTeamVersions]::Release) Write-Output $resp } } } function Update-VSTeamReleaseDefinition { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium", DefaultParameterSetName = 'JSON')] Param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'File')] [string] $InFile, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'JSON')] [string] $ReleaseDefinition, # Forces the command without confirmation [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($Force -or $pscmdlet.ShouldProcess('', "Update Release Definition")) { # Call the REST API if ($InFile) { _callAPI -Method Put -ProjectName $ProjectName -SubDomain vsrm -Area Release -Resource definitions -Version $([VSTeamVersions]::Release) -InFile $InFile -ContentType 'application/json' | Out-Null } else { _callAPI -Method Put -ProjectName $ProjectName -SubDomain vsrm -Area Release -Resource definitions -Version $([VSTeamVersions]::Release) -Body $ReleaseDefinition -ContentType 'application/json' | Out-Null } } } } function Update-VSTeamServiceEndpoint { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $id, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [hashtable] $object, [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] $body = $object | ConvertTo-Json if ($Force -or $pscmdlet.ShouldProcess($id, "Update Service Endpoint")) { # Call the REST API $resp = _callAPI -ProjectName $projectName -Area 'distributedtask' -Resource 'serviceendpoints' -Id $id ` -Method Put -ContentType 'application/json' -body $body -Version $([VSTeamVersions]::DistributedTask) _trackServiceEndpointProgress -projectName $projectName -resp $resp -title 'Updating Service Endpoint' -msg "Updating $id" return Get-VSTeamServiceEndpoint -ProjectName $ProjectName -id $id } } } function Update-VSTeamTaskGroup { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Low")] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $Id, [Parameter(ParameterSetName = 'ByFile', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $InFile, [Parameter(ParameterSetName = 'ByBody', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $Body, [switch] $Force ) DynamicParam { _buildProjectNameDynamicParam } process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ($Force -or $pscmdlet.ShouldProcess("Update Task Group")) { if ($InFile) { $resp = _callAPI -Method Put -ProjectName $ProjectName -Area distributedtask -Resource taskgroups -Version $([VSTeamVersions]::TaskGroups) -InFile $InFile -ContentType 'application/json' -Id $Id } else { $resp = _callAPI -Method Put -ProjectName $ProjectName -Area distributedtask -Resource taskgroups -Version $([VSTeamVersions]::TaskGroups) -Body $Body -ContentType 'application/json' -Id $Id } } return $resp } } function Update-VSTeamUserEntitlement { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High", DefaultParameterSetName = 'ByEmailLicenseOnly')] param ( [Parameter(ParameterSetName = 'ByIdLicenseOnly', Mandatory = $True, ValueFromPipelineByPropertyName = $true)] [Parameter(ParameterSetName = 'ByIdWithSource', Mandatory = $True, ValueFromPipelineByPropertyName = $true)] [Alias('UserId')] [string]$Id, [Parameter(ParameterSetName = 'ByEmailLicenseOnly', Mandatory = $True, ValueFromPipelineByPropertyName = $true)] [Parameter(ParameterSetName = 'ByEmailWithSource', Mandatory = $True, ValueFromPipelineByPropertyName = $true)] [Alias('UserEmail')] [string]$Email, [Parameter(ParameterSetName = 'ByIdLicenseOnly', Mandatory = $true)] [Parameter(ParameterSetName = 'ByIdWithSource')] [Parameter(ParameterSetName = 'ByEmailLicenseOnly', Mandatory = $true)] [Parameter(ParameterSetName = 'ByEmailWithSource')] [ValidateSet('Advanced', 'EarlyAdopter', 'Express', 'None', 'Professional', 'StakeHolder')] [string]$License, [ValidateSet('account', 'auto', 'msdn', 'none', 'profile', 'trial')] [Parameter(ParameterSetName = 'ByIdWithSource')] [Parameter(ParameterSetName = 'ByEmailWithSource')] [string]$LicensingSource, [ValidateSet('eligible', 'enterprise', 'none', 'platforms', 'premium', 'professional', 'testProfessional', 'ultimate')] [Parameter(ParameterSetName = 'ByIdWithSource')] [Parameter(ParameterSetName = 'ByEmailWithSource')] [string]$MSDNLicenseType, [switch]$Force ) process { # This will throw if this account does not support MemberEntitlementManagement _supportsMemberEntitlementManagement if ($email) { # We have to go find the id $user = Get-VSTeamUserEntitlement -Top 10000 | Where-Object email -eq $email if (-not$user) { throw "Could not find user with an email equal to $email" } $id = $user.id } else { $user = Get-VSTeamUserEntitlement -Id $id } $licenseTypeOriginal = $user.accessLevel.accountLicenseType $licenseSourceOriginal = $user.accessLevel.licensingSource $msdnLicenseTypeOriginal = $user.accessLevel.msdnLicenseType $newLicenseType = if ($License) { $License } else { $licenseTypeOriginal } $newLicenseSource = if ($LicensingSource) { $LicensingSource } else { $licenseSourceOriginal } $newMSDNLicenseType = if ($MSDNLicenseType) { $MSDNLicenseType } else { $msdnLicenseTypeOriginal } $obj = @{ from = "" op = "replace" path = "/accessLevel" value = @{ accountLicenseType = $newLicenseType licensingSource = $newLicenseSource msdnLicenseType = $newMSDNLicenseType } } $body = ConvertTo-Json -InputObject @($obj) if ($Force -or $PSCmdlet.ShouldProcess("$( $user.userName ) ($( $user.email ))", "Update user")) { # Call the REST API _callAPI -Method Patch -Body $body -SubDomain 'vsaex' -Resource 'userentitlements' -Id $id -Version $([VSTeamVersions]::MemberEntitlementManagement) -ContentType 'application/json-patch+json' | Out-Null Write-Output "Updated user license for $( $user.userName ) ($( $user.email )) from LicenseType: ($licenseTypeOriginal) to ($newLicenseType)" Write-Output "Updated user license for $( $user.userName ) ($( $user.email )) from LicenseSource: ($licenseSourceOriginal) to ($newLicenseSource)" Write-Output "Updated user license for $( $user.userName ) ($( $user.email )) from MSDNLicenseType: ($msdnLicenseTypeOriginal) to ($newMSDNLicenseType)" } } } function Update-VSTeamVariableGroup { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $Id, [Parameter(ParameterSetName = 'ByHashtable', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $Name, [Parameter(ParameterSetName = 'ByHashtable', Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string] $Description, [Parameter(ParameterSetName = 'ByHashtable', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [hashtable] $Variables, [Parameter(ParameterSetName = 'ByBody', Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $Body, [switch] $Force ) DynamicParam { $dp = _buildProjectNameDynamicParam if ([VSTeamVersions]::Version -ne "TFS2017" -and $PSCmdlet.ParameterSetName -eq "ByHashtable") { $ParameterName = 'Type' $rp = _buildDynamicParam -ParameterName $ParameterName -arrSet ('Vsts', 'AzureKeyVault') -Mandatory $true $dp.Add($ParameterName, $rp) $ParameterName = 'ProviderData' $rp = _buildDynamicParam -ParameterName $ParameterName -Mandatory $false -ParameterType ([hashtable]) $dp.Add($ParameterName, $rp) } return $dp } Process { # Bind the parameter to a friendly variable $ProjectName = $PSBoundParameters["ProjectName"] if ([string]::IsNullOrWhiteSpace($Body)) { $bodyAsHashtable = @{ name = $Name description = $Description variables = $Variables } if ([VSTeamVersions]::Version -ne "TFS2017") { $Type = $PSBoundParameters['Type'] $bodyAsHashtable.Add("type", $Type) $ProviderData = $PSBoundParameters['ProviderData'] if ($null -ne $ProviderData) { $bodyAsHashtable.Add("providerData", $ProviderData) } } $body = $bodyAsHashtable | ConvertTo-Json } if ($Force -or $pscmdlet.ShouldProcess($Id, "Update Variable Group")) { # Call the REST API $resp = _callAPI -ProjectName $projectName -Area 'distributedtask' -Resource 'variablegroups' -Id $Id ` -Method Put -ContentType 'application/json' -body $body -Version $([VSTeamVersions]::VariableGroups) Write-Verbose $resp return Get-VSTeamVariableGroup -ProjectName $ProjectName -Id $Id } } } function Update-VSTeamWorkItem { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Medium")] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [int] $Id, [Parameter(Mandatory = $false)] [string]$Title, [Parameter(Mandatory = $false)] [string]$Description, [Parameter(Mandatory = $false)] [string]$IterationPath, [Parameter(Mandatory = $false)] [string]$AssignedTo, [Parameter(Mandatory = $false)] [hashtable]$AdditionalFields, [switch] $Force ) Process { # Constructing the contents to be send. # Empty parameters will be skipped when converting to json. [Array]$body = @( @{ op = "add" path = "/fields/System.Title" value = $Title } @{ op = "add" path = "/fields/System.Description" value = $Description } @{ op = "add" path = "/fields/System.IterationPath" value = $IterationPath } @{ op = "add" path = "/fields/System.AssignedTo" value = $AssignedTo }) | Where-Object { $_.value } #this loop must always come after the main work item fields defined in the function parameters if ($AdditionalFields) { foreach ($fieldName in $AdditionalFields.Keys) { #check that main properties are not added into the additional fields hashtable $foundFields = $body | Where-Object { $null -ne $_ -and $_.path -like "*$fieldName" } if ($null -ne $foundFields) { throw "Found duplicate field '$fieldName' in parameter AdditionalFields, which is already a parameter. Please remove it." } else { $body += @{ op = "add" path = "/fields/$fieldName" value = $AdditionalFields[$fieldName] } } } } # It is very important that even if the user only provides # a single value above that the item is an array and not # a single object or the call will fail. # You must call ConvertTo-Json passing in the value and not # not using pipeline. # https://stackoverflow.com/questions/18662967/convertto-json-an-array-with-a-single-item $json = ConvertTo-Json @($body) -Compress # Call the REST API if ($Force -or $pscmdlet.ShouldProcess($Id, "Update-WorkItem")) { $resp = _callAPI -Area 'wit' -Resource 'workitems' ` -Version $([VSTeamVersions]::Core) -id $Id -Method Patch ` -ContentType 'application/json-patch+json' -Body $json _applyTypesToWorkItem -item $resp return $resp } } } |