Azure DevOps — Gestion des tickets et équipes en PowerShell
Introduction
Faitza_azdevops.ps1 expose sept fonctions pour piloter Azure DevOps
via l'API REST : création et lecture de work items, recherche WIQL, gestion des
commentaires, changement de statut et récupération des membres d'équipe.
Toutes les fonctions utilisent Get-Faitza_Modul_Headers -resource "azdevops"
pour l'authentification Bearer.
Les fonctions utilisent Get-Faitza_Modul_Headers -resource "azdevops"
pour obtenir un token valide. Voir :
Token Bearer pour les APIs Microsoft en PowerShell.
L'organisation Azure DevOps cible est FAITZA.
New-Faitza_azdevops_ticket
Crée un work item Azure DevOps via un PATCH JSON. Supporte les types
Task, Bug, User Story, etc.
Retourne l'objet complet du ticket avec une propriété GuiUrl ajoutée.
function New-Faitza_azdevops_ticket {
[CmdletBinding()]
param (
$azdev_projet = "Infrastructure",
$type = "Task",
$title,
$description,
$assignedto,
[string[]]$tags
)
try {
Write-Host "$($PSStyle.Background.Red)>>> New-Faitza_azdevops_ticket <<<$($PSStyle.Reset)"
if ([string]::IsNullOrWhiteSpace($title)) { throw "Il manque le title -title" }
if ([string]::IsNullOrWhiteSpace($description)) { throw "Il manque la description -description" }
$headers = Get-Faitza_Modul_Headers -resource "azdevops"
$headers["Content-Type"] = "application/json-patch+json"
$patch = @(
@{ op = "add"; path = "/fields/System.Title"; value = $title },
@{ op = "add"; path = "/fields/System.Description"; value = $description }
)
if ($assignedto) { $patch += @{ op = "add"; path = "/fields/System.AssignedTo"; value = $assignedto } }
if ($tags) { $patch += @{ op = "add"; path = "/fields/System.Tags"; value = ($tags -join ";") } }
$uri = "https://dev.azure.com/FAITZA/$azdev_projet/_apis/wit/workitems/`$$($type)?api-version=7.1"
$response = Invoke-RestMethod -Method Post -Uri $uri -Headers $headers -Body ($patch | ConvertTo-Json -Depth 10) -ErrorAction Stop
if (-not $response.id) { throw "Reponse API invalide" }
Write-Host "Ticket cree ID $($response.id)"
$guiUrl = "https://dev.azure.com/FAITZA/$azdev_projet/_workitems/edit/$($response.id)/"
$response | Add-Member -MemberType NoteProperty -Name "GuiUrl" -Value $guiUrl -Force
return $response
} catch {
throw "Erreur New-Faitza_azdevops_ticket : $_"
} finally {
Write-Host "$($PSStyle.Background.Red)<<< New-Faitza_azdevops_ticket >>>$($PSStyle.Reset)"
}
}
Exemple d'utilisation
$ticket = New-Faitza_azdevops_ticket `
-azdev_projet "Infrastructure" `
-type "Task" `
-title "Audit des comptes AD inactifs" `
-description "<p>Lister et désactiver les comptes sans connexion depuis 90 jours.</p>" `
-assignedto "[email protected]" `
-tags @("AD", "securite", "audit")
Write-Host "Ticket $($ticket.id) : $($ticket.GuiUrl)"
Read-Faitza_azdevops_ticket
Lit les détails d'un work item et ses commentaires. Retourne un objet
@{ ticket = ...; commentaires = [...] }.
function Read-Faitza_azdevops_ticket {
[CmdletBinding()]
param ($project = "Infrastructure", $id)
try {
Write-Host "$($PSStyle.Background.Red)>>> Read-Faitza_azdevops_ticket <<<$($PSStyle.Reset)"
if ([string]::IsNullOrWhiteSpace($id)) { throw "Il manque l'id du ticket (-id)" }
$headers = Get-Faitza_Modul_Headers -resource "azdevops" -contentType "jsonpatch"
$resp = Invoke-RestMethod -Method Get -Uri "https://dev.azure.com/FAITZA/$project/_apis/wit/workitems/$($id)?api-version=7.1" -Headers $headers -ErrorAction Stop
$resp_comments = Invoke-RestMethod -Method Get -Uri "https://dev.azure.com/FAITZA/$project/_apis/wit/workitems/$($id)/comments?api-version=7.1-preview.3" -Headers $headers -ErrorAction Stop
if (-not $resp -or -not $resp.id) { throw "Aucun ticket trouve pour: $id" }
$formattedComments = $resp_comments.comments | ForEach-Object {
[pscustomobject]@{ Author = $_.createdBy.displayName; Date = $_.createdDate; Comment = $_.text }
}
return [pscustomobject]@{
ticket = [pscustomobject]@{
Id = $resp.id
WorkItemType = $resp.fields."System.WorkItemType"
Title = $resp.fields."System.Title"
State = $resp.fields."System.State"
AssignedTo = $resp.fields."System.AssignedTo".displayName
Tags = $resp.fields."System.Tags"
Description = $resp.fields."System.Description"
Comments = $resp_comments.comments
}
commentaires = $formattedComments
}
} catch {
throw "Erreur Read-Faitza_azdevops_ticket : $_"
} finally {
Write-Host "$($PSStyle.Background.Red)<<< Read-Faitza_azdevops_ticket >>>$($PSStyle.Reset)"
}
}
Exemple d'utilisation
$result = Read-Faitza_azdevops_ticket -project "Infrastructure" -id 42
Write-Host "Titre : $($result.ticket.Title)"
Write-Host "Statut : $($result.ticket.State)"
$result.commentaires | Format-Table Author, Date, Comment
Find-Faitza_azdevops_ticket
Recherche des tickets via une requête WIQL. Filtre par titre (-title),
statut (-state) ou les deux. Exclut automatiquement les tickets
Closed si aucun statut n'est précisé. Retourne la liste des IDs.
function Find-Faitza_azdevops_ticket {
[CmdletBinding()]
param ($project = "Infrastructure", $operator = "CONTAINS", $title, $state)
try {
Write-Host "$($PSStyle.Background.Red)>>> Find-Faitza_azdevops_ticket <<<$($PSStyle.Reset)"
if (-not $title -and -not $state) { throw "Il manque des parametres : vous devez fournir un -title, un -state, ou les deux." }
$headers = Get-Faitza_Modul_Headers -resource "azdevops"
$queryConditions = @("[System.TeamProject] = '$project'")
if ($title) { $queryConditions += "[System.Title] $operator '$($title.Replace("'", "''"))'" }
if ($state) { $queryConditions += "[System.State] = '$($state.Replace("'", "''"))'" } else { $queryConditions += "[System.State] <> 'Closed'" }
$whereClause = $queryConditions -join "`n AND "
$wiql = @{ query = "SELECT [System.Id] FROM WorkItems WHERE $whereClause" }
$resp = Invoke-RestMethod -Method Post -Uri "https://dev.azure.com/FAITZA/$project/_apis/wit/wiql?api-version=7.1" -Headers $headers -Body ($wiql | ConvertTo-Json -Depth 5) -ErrorAction Stop
if (-not $resp.workItems -or $resp.workItems.Count -eq 0) { Write-Host "Aucun ticket trouve avec ces criteres."; return $null }
$results = @($resp.workItems | ForEach-Object { $_.id })
Write-Host "$($results.Count) ticket(s) trouve(s) : $results"
return $results
} catch {
throw "Erreur Find-Faitza_azdevops_ticket : $_"
} finally {
Write-Host "$($PSStyle.Background.Red)<<< Find-Faitza_azdevops_ticket >>>$($PSStyle.Reset)"
}
}
Exemple d'utilisation
# Chercher par titre
$ids = Find-Faitza_azdevops_ticket -title "audit"
# Chercher par statut
$ids = Find-Faitza_azdevops_ticket -state "Active"
# Combiner les deux
$ids = Find-Faitza_azdevops_ticket -title "AD" -state "Active"
# Lire chaque ticket trouve
foreach ($id in $ids) {
$ticket = Read-Faitza_azdevops_ticket -id $id
Write-Host "$($ticket.ticket.Id) — $($ticket.ticket.Title)"
}
Find-Faitza_azdevops_user
Recherche un utilisateur dans l'organisation Azure DevOps via l'API VSSPS identities.
Retourne l'ID, le display name, l'UPN et le HTML de mention (@mention).
function Find-Faitza_azdevops_user {
[CmdletBinding()]
param ($identity)
try {
Write-Host "$($PSStyle.Background.Red)>>> Find-Faitza_azdevops_user <<<$($PSStyle.Reset)"
if ([string]::IsNullOrWhiteSpace($identity)) { throw "Il manque l'identite a chercher (-identity)" }
$headers = Get-Faitza_Modul_Headers -resource "azdevops"
$identity_encoded = [uri]::EscapeDataString($identity)
$uri = "https://vssps.dev.azure.com/FAITZA/_apis/identities?searchFilter=General&filterValue=$identity_encoded&queryMembership=None&api-version=7.1"
$resp = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -ErrorAction Stop
if (-not $resp.value -or $resp.count -eq 0) { throw "Aucun utilisateur trouve pour: $identity" }
$results = foreach ($user in $resp.value) {
[pscustomobject]@{
Id = $user.id
Provider = $user.providerDisplayName
DisplayName = $user.customDisplayName
UniqueName = $user.uniqueName
IsActive = $user.isActive
IsContainer = $user.isContainer
Url = $user.url
MentionHtml = "<a href='#' data-vss-mention='version:2.0,$($user.id)'>@$($user.customDisplayName)</a>"
}
}
$results | Select-Object Id, DisplayName, UniqueName, IsActive | Format-Table -AutoSize
return $results
} catch {
throw "Erreur Find-Faitza_azdevops_user : $_"
} finally {
Write-Host "$($PSStyle.Background.Red)<<< Find-Faitza_azdevops_user >>>$($PSStyle.Reset)"
}
}
Exemple d'utilisation
$users = Find-Faitza_azdevops_user -identity "[email protected]"
$user = $users[0]
Write-Host "ID : $($user.Id) — Mention : $($user.MentionHtml)"
Get-Faitza_azdevops_TeamMembers
Retourne la liste des membres d'une équipe dans un projet Azure DevOps.
function Get-Faitza_azdevops_TeamMembers {
[CmdletBinding()]
param ($project, $team)
try {
Write-Host "$($PSStyle.Background.Red)>>> Get-Faitza_azdevops_TeamMembers <<<$($PSStyle.Reset)"
if ([string]::IsNullOrWhiteSpace($project)) { throw "Il manque le projet (-project)" }
if ([string]::IsNullOrWhiteSpace($team)) { throw "Il manque l'equipe (-team)" }
$headers = Get-Faitza_Modul_Headers -resource "azdevops"
$project_encoded = [uri]::EscapeDataString($project)
$team_encoded = [uri]::EscapeDataString($team)
$uri = "https://dev.azure.com/FAITZA/_apis/projects/$project_encoded/teams/$team_encoded/members?api-version=7.1"
$resp = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -ErrorAction Stop
if (-not $resp.value -or $resp.count -eq 0) { Write-Host "Aucun membre trouve pour l'equipe '$team' dans le projet '$project'."; return @() }
$results = foreach ($member in $resp.value) {
[pscustomobject]@{ DisplayName = $member.identity.displayName; UniqueName = $member.identity.uniqueName; Id = $member.identity.id }
}
Write-Host "Nombre de membres trouves : $($results.Count)"
return $results
} catch {
throw "Erreur Get-Faitza_azdevops_TeamMembers : $_"
} finally {
Write-Host "$($PSStyle.Background.Red)<<< Get-Faitza_azdevops_TeamMembers >>>$($PSStyle.Reset)"
}
}
Exemple d'utilisation
$membres = Get-Faitza_azdevops_TeamMembers -project "Infrastructure" -team "Infrastructure Team"
$membres | Format-Table DisplayName, UniqueName
Add-Faitza_azdevops_TicketComment
Ajoute un commentaire à un work item via le champ System.History.
function Add-Faitza_azdevops_TicketComment {
[CmdletBinding()]
param ($id, $comment, $azdev_projet = "Infrastructure")
try {
Write-Host "$($PSStyle.Background.Red)>>> Add-Faitza_azdevops_TicketComment <<<$($PSStyle.Reset)"
if ([string]::IsNullOrWhiteSpace($id)) { throw "Il manque l'id du ticket (-id)" }
if ([string]::IsNullOrWhiteSpace($comment)) { throw "Il manque le commentaire (-comment)" }
$headers = Get-Faitza_Modul_Headers -resource "azdevops"
$headers["Content-Type"] = "application/json-patch+json"
$patch = @(@{ op = "add"; path = "/fields/System.History"; value = $comment })
$uri = "https://dev.azure.com/FAITZA/$azdev_projet/_apis/wit/workitems/$id`?api-version=7.1"
$response = Invoke-RestMethod -Method Patch -Uri $uri -Headers $headers -Body (ConvertTo-Json -InputObject $patch -Depth 10) -ErrorAction Stop
if (-not $response.id -or $response.id -ne $id) { throw "Reponse API invalide" }
Write-Host "Commentaire ajoute au ticket $id"
return $true
} catch {
throw "Erreur Add-Faitza_azdevops_TicketComment : $_"
} finally {
Write-Host "$($PSStyle.Background.Red)<<< Add-Faitza_azdevops_TicketComment >>>$($PSStyle.Reset)"
}
}
Exemple d'utilisation
Add-Faitza_azdevops_TicketComment `
-id 42 `
-comment "Audit termine : 12 comptes desactives." `
-azdev_projet "Infrastructure"
Set-Faitza_azdevops_Ticket
Modifie le statut d'un work item (Active, Resolved,
Closed, etc.).
function Set-Faitza_azdevops_Ticket {
[CmdletBinding()]
param ($id, $state, $azdev_projet = "Infrastructure")
try {
Write-Host "$($PSStyle.Background.Red)>>> Set-Faitza_azdevops_Ticket <<<$($PSStyle.Reset)"
if ([string]::IsNullOrWhiteSpace($id)) { throw "Il manque l'id du ticket (-id)" }
if ([string]::IsNullOrWhiteSpace($state)) { throw "Il manque le statut (-state)" }
$headers = Get-Faitza_Modul_Headers -resource "azdevops"
$headers["Content-Type"] = "application/json-patch+json"
$patch = @(@{ op = "add"; path = "/fields/System.State"; value = $state })
$uri = "https://dev.azure.com/FAITZA/$azdev_projet/_apis/wit/workitems/$id`?api-version=7.1"
$response = Invoke-RestMethod -Method Patch -Uri $uri -Headers $headers -Body (ConvertTo-Json -InputObject $patch -Depth 10) -ErrorAction Stop
if (-not $response.id -or $response.id -ne $id) { throw "Reponse API invalide" }
Write-Host "Statut du ticket $id modifie vers $state"
return $true
} catch {
throw "Erreur Set-Faitza_azdevops_Ticket : $_"
} finally {
Write-Host "$($PSStyle.Background.Red)<<< Set-Faitza_azdevops_Ticket >>>$($PSStyle.Reset)"
}
}
Exemple d'utilisation
Set-Faitza_azdevops_Ticket -id 42 -state "Resolved"
Set-Faitza_azdevops_Ticket -id 42 -state "Closed"
// Commentaires
Aucun commentaire pour l'instant.