Azure DevOps Export Import query to different project - tfs
Tried searching if there's any out of the box method to export import queries in new projects. Seems like there isn't any.
Can it be achieved by code? If yes, would like to know how.
Appreciate any tips.
Regards,
You can use the rest api to read and create queries: Queries
Powershell example to export queries into local folder:
$user = ""
$token = "<pat>" #https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page
$teamProject = "team_project_name"
$orgUrl = "https://dev.azure.com/<org>"
$sourceQueryFolder = "Shared Queries/Change Management"
$targetLocalFolder = "c:/temp/Change Management Queries"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$queriesUrl = "$orgUrl/$teamProject/_apis/wit/queries/$sourceQueryFolder"+"?`$depth=1&`$expand=all&api-version=5.0"
function InvokeGetRequest ($GetUrl)
{
return Invoke-RestMethod -Uri $GetUrl -Method Get -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
}
$resQuries = InvokeGetRequest $queriesUrl
if (![System.IO.Directory]::Exists($targetLocalFolder))
{
New-Item -Path $targetLocalFolder -ItemType "directory"
}
if ($resQuries.isFolder -and $resQuries.hasChildren)
{
foreach($item in $resQuries.children)
{
if (!$item.isFolder)
{
$queryJson = "{`"name`":`"{queryname}`", `"wiql`":`"{querywiql}`"}"
$queryJson = $queryJson -replace "{queryname}", $item.name
$queryJson = $queryJson -replace "{querywiql}", $item.wiql
$filepath = "$targetLocalFolder/" + $item.name
Set-Content -Path $filepath -Value $queryJson
}
}
}
Powershell example to import queries from local folder:
$user = ""
$token = "<pat>" #https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page
$teamProject = "team_project_name"
$orgUrl = "https://dev.azure.com/<org>"
$sourceLocalFolder = "c:/temp/Change Management Queries"
$targetQueryFolder = "Shared Queries/Change Management Imported" #should exist
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$queriesUrl = "$orgUrl/$teamProject/_apis/wit/queries/$targetQueryFolder"+"?&api-version=5.0"
function InvokePostRequest ($PostUrl, $body)
{
return Invoke-RestMethod -Uri $PostUrl -Method Post -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Body $body
}
$files = Get-ChildItem -File -Path $sourceLocalFolder
foreach($wiqlfile in $files)
{
$wiqlBody = Get-Content $wiqlfile
InvokePostRequest $queriesUrl $wiqlBody
}
Example to copy a query folder content from one team project into another one in the same organization through rest API:
$user = ""
$token = "<pat>" #https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page
$teamProjectSource = "source_team_project_name"
$teamProjectTarget = "target_team_project_name"
$orgUrl = "https://dev.azure.com/<org>"
$sourceQueryFolder = "Shared Queries/Change Management"
$targetQueryFolder = "Shared Queries/Change Management" #should exist
$queryObject = [PSCustomObject]#{
name = $null
wiql = $null
columns = $null
sortColumns = $null
}
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$queriesPostUrl = "$orgUrl/$teamProjectTarget/_apis/wit/queries/$targetQueryFolder"+"?api-version=5.0"
$queriesGettUrl = "$orgUrl/$teamProjectSource/_apis/wit/queries/$sourceQueryFolder"+"?`$depth=1&`$expand=all&api-version=5.0"
function InvokeGetRequest ($GetUrl)
{
return Invoke-RestMethod -Uri $GetUrl -Method Get -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
}
function InvokePostRequest ($PostUrl, $body)
{
return Invoke-RestMethod -Uri $PostUrl -Method Post -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Body $body
}
$resQuries = InvokeGetRequest $queriesGettUrl
if ($resQuries.isFolder -and $resQuries.hasChildren)
{
foreach($item in $resQuries.children)
{
if (!$item.isFolder)
{
$queryObject.name = $item.name
$queryObject.wiql = $item.wiql
$queryObject.columns = $item.columns
$queryObject.sortcolumns = $item.sortcolumns
$wiqlbody = ConvertTo-Json $queryObject -Depth 10
InvokePostRequest $queriesPostUrl $wiqlBody
}
}
}
You can use out of box function to export and import queries. Visual Studio and Team Explorer contain that.
Go to the Queries Tab:
Edit query
Save as
Select another project
Related
Getting Error while updating environments level variable on Azure devOps release
I am trying to update the Environment level variable on Azure DevOps Release using below code. $url = "$(System.TeamFoundationServerUri)$(System.TeamProjectId)/_apis/Release/releases/$(Release.ReleaseId)/environments/$(RELEASE.ENVIRONMENTID)?api-version=7.0" Write-Host "URL: $url" $pipeline = Invoke-RestMethod -Uri $url -Headers #{ Authorization = "Bearer $(System.AccessToken)" # Provided by ADO thanks to OAuth checkbox } $pipeline.variables.Root.value = 'Test' $T1 = [pscustomobject] #{ scheduledDeploymentTime = $null ; comment = $null ; variables = $pipeline.variables } $json = #($T1) | ConvertTo-Json -Depth 99 Write-Host $json Invoke-RestMethod -Uri $url -Method PATCH -Body $json -ContentType "application/json" -Headers #{Authorization = "Bearer $(System.AccessToken)"} Error I am getting: enter image description here. What am I doing wrong?
Azure HTTP Trigger. How to avoid everytime the login
I have an Azure HTTP trigger function. And it all works, except that I am executing everytime the slow Connect-ExchangeOnline -Credential $Credential How can I re-use the security token so it is only once slow. And instead of using a normal login account, can I also use an applicationID and secret? using namespace System.Net param($Request, $TriggerMetadata) $body = #{} $user = "xxx#contoso.com" $password = "example_password" $securePassword = $password | ConvertTo-SecureString -AsPlainText -Force $Credential = new-Object System.Management.Automation.PSCredential($user,$securePassword) try { Connect-ExchangeOnline -Credential $Credential $filter = $Request.Body $wildCard = $filter.wildCard $SharedMailboxes = Get-Mailbox -RecipientTypeDetails SharedMailbox -ResultSize:1000 $wildcard| Select-Object Identity,User,AccessRights,SamaccountName, PrimarySmtpAddress,City ,UsageLocation,IsDirSynced, DisplayName,HiddenFromAddressListsEnabled, GrantSendOnBehalfTo, ExmployeeID $body.values = $SharedMailboxes } catch { Write-Error $_.Exception.Message $body.error = $_.Exception.Message } finally { Disconnect-ExchangeOnline -Confirm:$false } Push-OutputBinding -Name Response -Value ([HttpResponseContext]#{ StatusCode = [HttpStatusCode]::OK Body = $body })
Ms Graph RestAPI create team 404
the first try catch works, he is adding the ms graph AD group in office365. But the second try catch (converting the group to a Team does not work. I receive an 404 error?? The groupID exists on the server I notice. Whats going wrong to get an 404? I did add a secret token on the azure control panel. The script has the token, appid and tenantid in live time. also: the tenant has graph roles like group.ReadWriteAll. same for Teams and Directories. Clear-Host $env:graphApiDemoAppId = "" # Replace with your Azure AD app id $env:graphApiDemoAppSecret = "" # Replace with your Azure AD app secret $env:tenantId = "" # Replace with your Azure AD tenant ID $oauthUri = "https://login.microsoftonline.com/$env:tenantId/oauth2/v2.0/token" # Create token request body $tokenBody = #{ client_id = $env:graphApiDemoAppId client_secret = $env:graphApiDemoAppSecret scope = "https://graph.microsoft.com/.default" grant_type = "client_credentials" } # Retrieve access token $tokenRequest = Invoke-RestMethod -Uri $oauthUri -Method POST -ContentType "application/x-www-form-urlencoded" -Body $tokenBody -UseBasicParsing # Save access token $accessToken = ($tokenRequest).access_token $headers = #{ "Authorization" = "Bearer $accessToken" "Content-type" = "application/json" } try { # Create group request body $groupName = "Test_Kenvh16" $groupBodyParams = #{ displayName = $groupName description = $groupName mailNickName = $groupName groupTypes = #("Unified") mailEnabled = $true securityEnabled = $false visibility = "Private" } $groupBody = ConvertTo-Json -InputObject $groupBodyParams $newGroup = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/groups" -Method POST -Headers $headers -Body $groupBody $groupId = $newGroup.id Write-Host "group created:" $groupName "id:" $groupId try { #convert group to team.. $teamBodyParams = #{ memberSettings = #{ allowCreateUpdateChannels = $true } messagingSettings = #{ allowUserEditMessages = $true allowUserDeleteMessages = $true } funSettings = #{ allowGiphy = $true giphyContentRating = "strict" } } $teamBody = ConvertTo-Json -InputObject $teamBodyParams $teamUri = "https://graph.microsoft.com/v1.0/groups/" + $groupId + "/team" $newTeam = Invoke-RestMethod -Uri $teamUri -Method POST -Headers $headers -Body $teamBody $teamId = $newTeam.id } catch { Write-Host "createTeam ExceptionMessage:" $_.Exception.Message Write-Host "createTeam StatusCode:" $_.Exception.Response.StatusCode.value__ Write-Host "createTeam StatusDescription:" $_.Exception.Response.StatusDescription } } catch { Write-Host "createGroup ExceptionMessage:" $_.Exception.Message Write-Host "createGroup StatusCode:" $_.Exception.Response.StatusCode.value__ Write-Host "createGroup StatusDescription:" $_.Exception.Response.StatusDescription }
How can I parse returned ODATA into an array?
When I issue: $uri = "https://graph.microsoft.com/v1.0/users/jane.doe#blah.com/contacts?`$filter=emailAddresses/any(a:a/address eq 'fred.bloggs#blah.com')" $method = "GET" $query = Invoke-WebRequest -Method $method -Uri $uri -Headers #{Authorization = "Bearer $token"} -ErrorAction Stop $querystring = $query.Content | out-string | out-host I get back the following 3 records: {"#odata.context":"https://graph.microsoft.com/v1.0/$metadata#users('jane.doe%40blah.com')/contacts","value":[{"#odata.etag":"W/\"EQAAABYAAADSyGTyvqlwS5n00f5wZ/+rAAApDC6/\"", "id":"AAMkADViZDA1ZTI5LTg0NWEtNGJhYy05YzA3LWI3MjUxNzA1MGUyOABGAAAAAADU7_adBLD4RZAfnn8KRZ6vBwDSyGTyvqlwS5n00f5wZ-_rAAAAAAEOAADSyGTyvqlwS5n00f5wZ-_rAAApEyC7AAA=","createdDateTime":"2019-09-09T1 3:39:27Z","lastModifiedDateTime":"2019-09-09T13:39:28Z","changeKey":"EQAAABYAAADSyGTyvqlwS5n00f5wZ/+rAAApDC6/","categories":[],"parentFolderId":"AQMkADViZDA1ZTI5LTg0NWEtNGJhYy05YzA3LWI3MjUxNz A1MGUyOAAuAAAD1O-mnQSw_EWQH55-CkWerwEA0shk8r6pcEuZ9NH_cGf-qwAAAgEOAAAA","birthday":null,"fileAs":"","displayName":"Fred Bloggs","givenName":"Fred","initials":null,"middleName":null,"nickName" :null,"surname":"Bloggs","title":null,"yomiGivenName":null,"yomiSurname":null,"yomiCompanyName":null,"generation":null,"imAddresses":[],"jobTitle":null,"companyName":null,"department":null,"o fficeLocation":null,"profession":null,"businessHomePage":null,"assistantName":null,"manager":null,"homePhones":[],"mobilePhone":null,"businessPhones":["+1 732 555 0103"],"spouseName":null,"pe rsonalNotes":"Note 3","children":[],"emailAddresses":[{"name":"Fred Bloggs","address":"fred.bloggs#blah.com"}],"homeAddress":{},"businessAddress":{},"otherAddress":{}},{"#odata.etag":"W/\"EQA AABYAAADSyGTyvqlwS5n00f5wZ/+rAAApDC62\"","id":"AAMkADViZDA1ZTI5LTg0NWEtNGJhYy05YzA3LWI3MjUxNzA1MGUyOABGAAAAAADU7_adBLD4RZAfnn8KRZ6vBwDSyGTyvqlwS5n00f5wZ-_rAAAAAAEOAADSyGTyvqlwS5n00f5wZ-_rAAAp EyC6AAA=","createdDateTime":"2019-09-09T13:39:15Z","lastModifiedDateTime":"2019-09-09T13:39:15Z","changeKey":"EQAAABYAAADSyGTyvqlwS5n00f5wZ/+rAAApDC62","categories":[],"parentFolderId":"AQMkA DViZDA1ZTI5LTg0NWEtNGJhYy05YzA3LWI3MjUxNzA1MGUyOAAuAAAD1O-mnQSw_EWQH55-CkWerwEA0shk8r6pcEuZ9NH_cGf-qwAAAgEOAAAA","birthday":null,"fileAs":"","displayName":"Fred Bloggs","givenName":"Fred","in itials":null,"middleName":null,"nickName":null,"surname":"Bloggs","title":null,"yomiGivenName":null,"yomiSurname":null,"yomiCompanyName":null,"generation":null,"imAddresses":[],"jobTitle":nul l,"companyName":null,"department":null,"officeLocation":null,"profession":null,"businessHomePage":null,"assistantName":null,"manager":null,"homePhones":[],"mobilePhone":null,"businessPhones": ["+1 732 555 0102"],"spouseName":null,"personalNotes":"Note 2","children":[],"emailAddresses":[{"name":"Fred Bloggs","address":"fred.bloggs#blah.com"}],"homeAddress":{},"businessAddress":{}," otherAddress":{}},{"#odata.etag":"W/\"EQAAABYAAADSyGTyvqlwS5n00f5wZ/+rAAApDC6r\"","id":"AAMkADViZDA1ZTI5LTg0NWEtNGJhYy05YzA3LWI3MjUxNzA1MGUyOABGAAAAAADU7_adBLD4RZAfnn8KRZ6vBwDSyGTyvqlwS5n00f5 wZ-_rAAAAAAEOAADSyGTyvqlwS5n00f5wZ-_rAAApEyC5AAA=","createdDateTime":"2019-09-09T13:38:47Z","lastModifiedDateTime":"2019-09-09T13:38:48Z","changeKey":"EQAAABYAAADSyGTyvqlwS5n00f5wZ/+rAAApDC6r ","categories":[],"parentFolderId":"AQMkADViZDA1ZTI5LTg0NWEtNGJhYy05YzA3LWI3MjUxNzA1MGUyOAAuAAAD1O-mnQSw_EWQH55-CkWerwEA0shk8r6pcEuZ9NH_cGf-qwAAAgEOAAAA","birthday":null,"fileAs":"","displayN ame":"Fred Bloggs","givenName":"Fred","initials":null,"middleName":null,"nickName":null,"surname":"Bloggs","title":null,"yomiGivenName":null,"yomiSurname":null,"yomiCompanyName":null,"generat ion":null,"imAddresses":[],"jobTitle":null,"companyName":null,"department":null,"officeLocation":null,"profession":null,"businessHomePage":null,"assistantName":null,"manager":null,"homePhones ":[],"mobilePhone":null,"businessPhones":["+1 732 555 0101"],"spouseName":null,"personalNotes":"Note 1","children":[],"emailAddresses":[{"name":"Fred Bloggs","address":"fred.bloggs#blah.com"} ],"homeAddress":{},"businessAddress":{},"otherAddress":{}}]} Is there a preferred way to parse this into an array with a row for each record? Thanks.
Using PowerShell, you can convert the response to an object using the ConvertFrom-Json cmdlet
One option would be to utilize ConvertFrom-Json which converts JSON string to a custom object, for example: $uri = "https://graph.microsoft.com/v1.0/users/" $resp = Invoke-WebRequest -Method "GET" -Uri $uri -Headers #{Authorization = "Bearer $token"} $data = $resp.Content | ConvertFrom-Json $data.value | ForEach-Object { #enumerate collection Write-Host $_.userPrincipalName } Another option is utilize Invoke-RestMethod instead of Invoke-WebRequest which auto converts JSON string to a custom object: $uri = "https://graph.microsoft.com/v1.0/users/" $data = Invoke-RestMethod -Headers #{Authorization = "Bearer $token"} -Method GET -Uri $uri $data.value | ForEach-Object { #enumerate collection Write-Host $_.userPrincipalName }
TFS 2017 Update 3.1 Release approver report/history
Please help in how to get the Release approver list for each release definition in TFS 2017 update 3.1. Thanks & Regards
You can call the REST API (Definitions - Get) to retrieve the approver list. Below PowerShell script can get the Release approver list for each release definition: (Just replace the parameters accordingly) Param( [string]$baseurl = "http://SERVER:8080/tfs/DefaultCollection", [string]$projectName = "0511ScrumTFVC", [string]$user = "Domain\user", [string]$token = "password/PAT" ) # Base64-encodes the Personal Access Token (PAT) appropriately $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token))) $releasesuri = "$baseurl/$projectName/_apis/release/definitions" $releasesresult = Invoke-RestMethod -Uri $releasesuri -Method Get -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} $redids = $releasesresult.value.id foreach ($redid in $redids) { $uri = "$baseurl/$projectName/_apis/release/definitions/$redid" $approvers = Invoke-RestMethod -Uri $uri -Method Get -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} $preApprovers = $approvers.environments.preDeployApprovals.approvals.approver.displayName $postApprovers = $approvers.environments.postDeployApprovals.approvals.approver.displayName write-host "Release ID: $redid - preApprovers:" foreach ($preApprover in $preApprovers) { write-host $preApprover } write-host "`nRelease ID: $redid - postApprovers:" foreach ($postApprover in $postApprovers) { write-host $postApprover } }