diff --git a/.docs/Get-VSTeamWiql.md b/.docs/Get-VSTeamWiql.md
new file mode 100644
index 000000000..cd593f990
--- /dev/null
+++ b/.docs/Get-VSTeamWiql.md
@@ -0,0 +1,93 @@
+
+
+# Get-VSTeamWiqlItem
+
+## SYNOPSIS
+
+
+
+## SYNTAX
+
+## DESCRIPTION
+
+
+
+## EXAMPLES
+
+### -------------------------- EXAMPLE 1 --------------------------
+
+```PowerShell
+PS C:\> Get-VSTeamWiql -Query "Select [System.Id], [System.Title], [System.State] From WorkItems" -Team "MyProject Team" -Project "MyProject" -Expand
+```
+
+This command gets work items via a WIQL query and expands the return work items with only the selected fields System.Id, System.Title and System.State.
+
+### -------------------------- EXAMPLE 2 --------------------------
+
+```PowerShell
+PS C:\> Get-VSTeamWiql -Query "Select [System.Id], [System.Title], [System.State] From WorkItems" -Team "MyProject Team" -Project "MyProject"
+```
+
+This command gets work items via a WIQL query and returns the WIQL query result with only work item IDs.
+
+## PARAMETERS
+
+### -Id
+
+The id query to return work items for. This is the ID of any saved query within a team in a project
+
+```yaml
+Type: Int32
+Parameter Sets: ByID
+Required: True
+```
+
+### -Query
+
+The WIQL query. For the syntax check [the official documentation](https://docs.microsoft.com/en-us/azure/devops/boards/queries/wiql-syntax?view=azure-devops).
+
+```yaml
+Type: String
+Parameter Sets: ByQuery
+Required: True
+```
+
+### -Top
+
+The max number of results to return.
+
+```yaml
+Type: String
+Required: False
+Default value: 100
+```
+
+### -TimePrecision
+
+Whether or not to use time precision.
+
+```yaml
+Type: Switch
+```
+
+### -Expand
+
+The expand the work items with the selected attributes in the WIQL query.
+
+```yaml
+Type: Switch
+```
+
+## INPUTS
+
+### System.String
+
+ProjectName
+
+## OUTPUTS
+
+## NOTES
+
+If you do not set the default project by called Set-VSTeamDefaultProject before calling Get-VSTeamWiql you will have to type in the names.
+
+## RELATED LINKS
diff --git a/.docs/synopsis/Get-VSTeamWiql.md b/.docs/synopsis/Get-VSTeamWiql.md
new file mode 100644
index 000000000..fe760e523
--- /dev/null
+++ b/.docs/synopsis/Get-VSTeamWiql.md
@@ -0,0 +1 @@
+Returns work items from the given WIQL query or a saved query by ID from your projects team.
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0a187dbb1..ec999799c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changelog
+## 6.4.0
+
+Added Get-VSTeamWiql to get work items via [WIQL](https://docs.microsoft.com/en-us/rest/api/azure/devops/wit/wiql?view=azure-devops-rest-5.1) and also to expand the returned work items with all fields selected.
+
## 6.3.6
Merged [Pull Request](https://github.com/DarqueWarrior/vsteam/pull/200) from [Chris Gardner](https://github.com/ChrisLGardner) which included the following:
diff --git a/Source/Private/applyTypes.ps1 b/Source/Private/applyTypes.ps1
index 91bf9324f..8e55440f5 100644
--- a/Source/Private/applyTypes.ps1
+++ b/Source/Private/applyTypes.ps1
@@ -25,6 +25,13 @@ function _applyTypesToWorkItem {
}
}
+function _applyTypesToWiql {
+ param($item)
+ if ($item) {
+ $item.PSObject.TypeNames.Insert(0, 'Team.Wiql')
+ }
+}
+
function _applyTypesToUser {
param(
[Parameter(Mandatory = $true)]
diff --git a/Source/Private/common.ps1 b/Source/Private/common.ps1
index b756b75de..464a236b3 100644
--- a/Source/Private/common.ps1
+++ b/Source/Private/common.ps1
@@ -65,6 +65,7 @@ function _hasAccount {
function _buildRequestURI {
[CmdletBinding()]
param(
+ [string]$team,
[string]$resource,
[string]$area,
[string]$id,
@@ -90,6 +91,10 @@ function _buildRequestURI {
$sb.Append("/$projectName") | Out-Null
}
+ if ($team) {
+ $sb.Append("/$team") | Out-Null
+ }
+
$sb.Append("/_apis/") | Out-Null
if ($area) {
@@ -588,8 +593,9 @@ function _callAPI {
[object]$body,
[string]$InFile,
[string]$OutFile,
- [string]$ContentType,
+ [string]$ContentType,
[string]$ProjectName,
+ [string]$Team,
[string]$Url,
[object]$QueryString
)
@@ -628,7 +634,7 @@ function _callAPI {
}
# We have to remove any extra parameters not used by Invoke-RestMethod
- $extra = 'Area', 'Resource', 'SubDomain', 'Id', 'Version', 'JSON', 'ProjectName', 'Url', 'QueryString'
+ $extra = 'Area', 'Resource', 'SubDomain', 'Id', 'Version', 'JSON', 'ProjectName', 'Team', 'Url', 'QueryString'
foreach ($e in $extra) { $params.Remove($e) | Out-Null }
try {
diff --git a/Source/Public/Get-VSTeamWiql.ps1 b/Source/Public/Get-VSTeamWiql.ps1
new file mode 100644
index 000000000..c0b5b24ca
--- /dev/null
+++ b/Source/Public/Get-VSTeamWiql.ps1
@@ -0,0 +1,81 @@
+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 -Ids $idArray).value
+ }
+
+ }
+
+ _applyTypesToWiql -item $resp
+
+ return $resp
+ }
+}
\ No newline at end of file
diff --git a/Source/VSTeam.psd1 b/Source/VSTeam.psd1
index 68c96ca65..746cdda3b 100644
--- a/Source/VSTeam.psd1
+++ b/Source/VSTeam.psd1
@@ -12,7 +12,7 @@
RootModule = 'VSTeam.psm1'
# Version number of this module.
- ModuleVersion = '6.3.6'
+ ModuleVersion = '6.4.0'
# Supported PSEditions
# CompatiblePSEditions = @()
diff --git a/Source/formats/Team.Wiql.ListView.ps1xml b/Source/formats/Team.Wiql.ListView.ps1xml
new file mode 100644
index 000000000..cdde42ec8
--- /dev/null
+++ b/Source/formats/Team.Wiql.ListView.ps1xml
@@ -0,0 +1,28 @@
+
+
+
+
+ Team.Wiql.ListView
+
+ Team.Wiql
+
+
+
+
+
+
+ queryType
+
+
+ WorkItemIDs
+
+
+ workItems
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/formats/Team.Wiql.TableView.ps1xml b/Source/formats/Team.Wiql.TableView.ps1xml
new file mode 100644
index 000000000..c8c54361a
--- /dev/null
+++ b/Source/formats/Team.Wiql.TableView.ps1xml
@@ -0,0 +1,39 @@
+
+
+
+
+ Team.Wiql.TableView
+
+ Team.Wiql
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ queryType
+
+
+ WorkItemIDs
+
+
+ workItems
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/formats/_formats.json b/Source/formats/_formats.json
index 009abec4a..c965e5393 100644
--- a/Source/formats/_formats.json
+++ b/Source/formats/_formats.json
@@ -89,6 +89,8 @@
"Team.PSDrive.Leaf.Default.TableView.ps1xml",
"Team.WorkItemType.TableView.ps1xml",
"Team.WorkItemType.ListView.ps1xml",
+ "Team.Wiql.TableView.ps1xml",
+ "Team.Wiql.ListView.ps1xml",
"Team.WorkItem.TableView.ps1xml",
"Team.WorkItem.ListView.ps1xml",
"Team.JobRequest.TableView.ps1xml"
diff --git a/Source/types/Team.Wiql.ps1xml b/Source/types/Team.Wiql.ps1xml
new file mode 100644
index 000000000..fab3e0d4d
--- /dev/null
+++ b/Source/types/Team.Wiql.ps1xml
@@ -0,0 +1,49 @@
+
+
+
+ Team.Wiql
+
+
+ QueryType
+ $this.PSObject.Properties['queryType'].Value
+
+
+ QueryResultType
+ $this.PSObject.Properties['queryResultType'].Value
+
+
+ AsOf
+ $this.PSObject.Properties['asOf'].Value
+
+
+ Columns
+ $this.PSObject.Properties['columns'].Value
+
+
+ SortColumns
+ $this.PSObject.Properties['sortColumns'].Value
+
+
+ WorkItemIDs
+ [int[]]$this.PSObject.Properties['workItems'].Value.id
+
+
+ WorkItems
+ $this.PSObject.Properties['workItems'].Value
+
+
+ PSStandardMembers
+
+
+ DefaultDisplayPropertySet
+
+ queryType
+ WorkItemIDs
+ workItems
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/unit/test/wiql.Tests.ps1 b/unit/test/wiql.Tests.ps1
new file mode 100644
index 000000000..16739121d
--- /dev/null
+++ b/unit/test/wiql.Tests.ps1
@@ -0,0 +1,168 @@
+Set-StrictMode -Version Latest
+
+InModuleScope VSTeam {
+ [VSTeamVersions]::Account = 'https://dev.azure.com/test'
+
+ Describe 'wiql' {
+ # Mock the call to Get-Projects by the dynamic parameter for ProjectName
+ Mock Invoke-RestMethod { return @() } -ParameterFilter {
+ $Uri -like "*_apis/projects*"
+ }
+
+ . "$PSScriptRoot\mocks\mockProjectNameDynamicParamNoPSet.ps1"
+
+ $workItem = @{
+ id = 47
+ url = "https://dev.azure.com/test/_apis/wit/workItems/47"
+ }
+
+ $column = @{
+ referenceName = "System.Id"
+ name = "ID"
+ url = "https://dev.azure.com/razorspoint-test/_apis/wit/fields/System.Id"
+ }
+
+ $sortColumn = @{
+ field = $column
+ descending = $false
+ }
+
+ $wiqlResult = @{
+ querytype = "flat"
+ queryTypeResult = "worItem"
+ asOf = "2019-10-03T18:35:09.117Z"
+ columns = @($column)
+ sortColumns = @($sortColumn)
+ workItems = @($workItem,$workItem)
+ }
+
+ $expandedWorkItems = @{
+ count = 1
+ value = @($workItem,$workItem)
+ }
+
+ Context 'Get-Wiql' {
+ Mock Invoke-RestMethod {
+ # If this test fails uncomment the line below to see how the mock was called.
+ Write-Host $args
+
+ return $wiqlResult
+ }
+
+ # function is mocked because it is used when switch 'Expanded' is being used.
+ Mock Get-VSTeamWorkItem {
+ # If this test fails uncomment the line below to see how the mock was called.
+ #Write-Host $args
+
+ return $expandedWorkItems
+ }
+
+ It 'Get work items with custom WIQL query' {
+ $Global:PSDefaultParameterValues.Remove("*:projectName")
+ $wiqlQuery = "Select [System.Id], [System.Title], [System.State] From WorkItems"
+ Get-VSTeamWiql -ProjectName "test" -Team "test team" -Query $wiqlQuery
+
+ Assert-MockCalled Invoke-RestMethod -Exactly -Scope It -Times 1 -ParameterFilter {
+ $Method -eq 'Post' -and
+ $Body -like '`{*' -and # Make sure the body is an object
+ $Body -like "*[System.Id]*" -and
+ $Body -like "*[System.Title]*" -and
+ $Body -like "*[System.State]*" -and
+ $Body -like '*`}' -and # Make sure the body is an object
+ $ContentType -eq 'application/json' -and
+ $Uri -eq "https://dev.azure.com/test/test/test team/_apis/wit/wiql/?api-version=$([VSTeamVersions]::Core)&`$top=100"
+ }
+ }
+
+ It 'Get work items with custom WIQL query with -Top 250' {
+ $Global:PSDefaultParameterValues.Remove("*:projectName")
+ $wiqlQuery = "Select [System.Id], [System.Title], [System.State] From WorkItems"
+ Get-VSTeamWiql -ProjectName "test" -Team "test team" -Query $wiqlQuery -Top 250
+
+ Assert-MockCalled Invoke-RestMethod -Exactly -Scope It -Times 1 -ParameterFilter {
+ $Method -eq 'Post' -and
+ $Body -like '`{*' -and # Make sure the body is an object
+ $Body -like "*[System.Id]*" -and
+ $Body -like "*[System.Title]*" -and
+ $Body -like "*[System.State]*" -and
+ $Body -like '*`}' -and # Make sure the body is an object
+ $ContentType -eq 'application/json' -and
+ $Uri -eq "https://dev.azure.com/test/test/test team/_apis/wit/wiql/?api-version=$([VSTeamVersions]::Core)&`$top=250"
+ }
+ }
+
+ It 'Get work items with custom WIQL query with -Top 0' {
+ $Global:PSDefaultParameterValues.Remove("*:projectName")
+ $wiqlQuery = "Select [System.Id], [System.Title], [System.State] From WorkItems"
+ Get-VSTeamWiql -ProjectName "test" -Team "test team" -Query $wiqlQuery -Top 0
+
+ Assert-MockCalled Invoke-RestMethod -Exactly -Scope It -Times 1 -ParameterFilter {
+ $Method -eq 'Post' -and
+ $Body -like '`{*' -and # Make sure the body is an object
+ $Body -like "*[System.Id]*" -and
+ $Body -like "*[System.Title]*" -and
+ $Body -like "*[System.State]*" -and
+ $Body -like '*`}' -and # Make sure the body is an object
+ $ContentType -eq 'application/json' -and
+ $Uri -eq "https://dev.azure.com/test/test/test team/_apis/wit/wiql/?api-version=$([VSTeamVersions]::Core)"
+ }
+ }
+
+ It 'Get work items with custom WIQL query with expanded work items' {
+ $Global:PSDefaultParameterValues.Remove("*:projectName")
+ $wiqlQuery = "Select [System.Id], [System.Title], [System.State] From WorkItems"
+ Get-VSTeamWiql -ProjectName "test" -Team "test team" -Query $wiqlQuery -Expand
+
+ Assert-MockCalled Invoke-RestMethod -Exactly -Scope It -Times 1 -ParameterFilter {
+ $Method -eq 'Post' -and
+ $Body -like '`{*' -and # Make sure the body is an object
+ $Body -like "*[System.Id]*" -and
+ $Body -like "*[System.Title]*" -and
+ $Body -like "*[System.State]*" -and
+ $Body -like '*`}' -and # Make sure the body is an object
+ $ContentType -eq 'application/json' -and
+ $Uri -eq "https://dev.azure.com/test/test/test team/_apis/wit/wiql/?api-version=$([VSTeamVersions]::Core)&`$top=100"
+ }
+ }
+
+ It 'Get work items with custom WIQL query with time precision' {
+ $Global:PSDefaultParameterValues.Remove("*:projectName")
+ $wiqlQuery = "Select [System.Id], [System.Title], [System.State] From WorkItems"
+ Get-VSTeamWiql -ProjectName "test" -Team "test team" -Query $wiqlQuery -TimePrecision
+
+ Assert-MockCalled Invoke-RestMethod -Exactly -Scope It -Times 1 -ParameterFilter {
+ $Method -eq 'Post' -and
+ $Body -like '`{*' -and # Make sure the body is an object
+ $Body -like "*[System.Id]*" -and
+ $Body -like "*[System.Title]*" -and
+ $Body -like "*[System.State]*" -and
+ $Body -like '*`}' -and # Make sure the body is an object
+ $ContentType -eq 'application/json' -and
+ $Uri -like "*timePrecision=True*"
+ $Uri -like "*`$top=100*"
+ $Uri -like "https://dev.azure.com/test/test/test team/_apis/wit/wiql/?api-version=$([VSTeamVersions]::Core)*"
+ }
+ }
+
+ It 'Get work items with query ID query' {
+ $Global:PSDefaultParameterValues.Remove("*:projectName")
+ Get-VSTeamWiql -ProjectName "test" -Team "test team" -Id 1
+
+ Assert-MockCalled Invoke-RestMethod -Exactly -Scope It -Times 1 -ParameterFilter {
+ $Uri -eq "https://dev.azure.com/test/test/test team/_apis/wit/wiql/1?api-version=$([VSTeamVersions]::Core)&`$top=100"
+ }
+ }
+
+ It 'Get work items with query ID query with expanded work items' {
+ $Global:PSDefaultParameterValues.Remove("*:projectName")
+ Get-VSTeamWiql -ProjectName "test" -Team "test team" -Id 1 -Expand
+
+ Assert-MockCalled Invoke-RestMethod -Exactly -Scope It -Times 1 -ParameterFilter {
+ $Uri -eq "https://dev.azure.com/test/test/test team/_apis/wit/wiql/1?api-version=$([VSTeamVersions]::Core)&`$top=100"
+ }
+ }
+
+
+ }
+ }
+}
\ No newline at end of file