Advanced PowerShell script to export and import Azure DevOps work items (Epics, Features, PBIs, Tasks, User Stories, Bugs) to/from a CSV file with full support for creation and update (upsert), unlimited item retrieval, and advanced validation.
- Complete Retrieval: No more 80-item limit! Retrieves ALL work items from the project.
- Robust Method: Advanced pagination system with fallback by ID ranges.
- Optimized Performance: Batch processing of 200 items with intelligent error handling.
- Simulation Mode (
-WhatIf): Test your imports without making any changes. - Force Mode (
-Force): Automatic import without confirmation. - Analysis-Only Mode (
-ShowSummaryOnly): Analyze the CSV without executing the import.
- Detailed Summary: Visual tables of planned operations (creations/updates).
- Advanced Validation: Complete CSV verification with error detection.
- Flexible Decimal Format: Supports both commas AND periods for numeric values.
First time using it? Run the setup script:
.\Setup.ps1This script will automatically guide you through configuring Azure DevOps and creating your first exports/imports.
- Log in to Azure DevOps.
- Click on your profile β Personal Access Tokens.
- Create a new token with the following permissions:
- Work Items: Read & Write
- Project and Team: Read
- Copy the token (it will not be displayed again).
- PowerShell 5.1 or higher.
Invoke-RestMethodmodule (included by default).
π Use the automatic configuration script for your first use:
.\Setup.ps1This interactive script will guide you to:
- β Verify PowerShell prerequisites.
- β Test the connection to Azure DevOps.
- β
Automatically create the
.patfile to store your token. - β
Generate the
config.ps1file with your parameters. - β Provide ready-to-use commands.
- Organization: Name of your Azure DevOps organization.
- Project: Name of the project.
- Action:
ExportorImport.
- PersonalAccessToken: Your access token (optional if
.patfile is present). - CsvFilePath: Path to the CSV file (default:
workitems.csv). - Verbose: Detailed operation logs.
The script automatically searches for the token in the following order:
- Parameter: Token provided via
-PersonalAccessToken. - .pat File: Searches in the current directory:
personal-access-token.pat.pat
To create a .pat file:
"your_token_here" | Out-File -FilePath "personal-access-token.pat" -Encoding UTF8# Export ALL work items from the project (no more 80-item limit)
.\AzureDevOpsItemsImporter.ps1 -Organization "myorg" -Project "myproject" -Action Export -CsvFilePath "full-export.csv".\AzureDevOpsItemsImporter.ps1 -Organization "myorg" -Project "myproject" -PersonalAccessToken "your_token" -Action Export -CsvFilePath "export.csv"# ALWAYS test with -WhatIf before the real import
.\AzureDevOpsItemsImporter.ps1 -Organization "myorg" -Project "myproject" -Action Import -CsvFilePath "upsert.csv" -WhatIf# Analyze the CSV file without making any changes
.\AzureDevOpsItemsImporter.ps1 -Organization "myorg" -Project "myproject" -Action Import -CsvFilePath "upsert.csv" -ShowSummaryOnly# Import with manual confirmation
.\AzureDevOpsItemsImporter.ps1 -Organization "myorg" -Project "myproject" -Action Import -CsvFilePath "upsert.csv"# Import without confirmation (use with caution!)
.\AzureDevOpsItemsImporter.ps1 -Organization "myorg" -Project "myproject" -Action Import -CsvFilePath "upsert.csv" -ForceThe upsert feature allows you to automatically create new work items or update existing work items in the same CSV file.
The script now displays a detailed summary before each import:
=== IMPORT SUMMARY ===
π File Analysis: upsert.csv (25 work items)
π PLANNED CREATIONS (3 work items):
βββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ¬ββββββββββββββ¬βββββββββββββββββββββββ
β Type β Title β State β AssignedTo β
βββββββββββββββββββΌβββββββββββββββββββββββββββββββββΌββββββββββββββΌβββββββββββββββββββββββ€
β Task β New API Task β New β dev@company.com β
β Bug β Fix login bug β New β qa@company.com β
β Feature β New feature β New β pm@company.com β
βββββββββββββββββββ΄βββββββββββββββββββββββββββββββββ΄ββββββββββββββ΄βββββββββββββββββββββββ
π PLANNED UPDATES (2 work items):
ββββββββ¬βββββββββββββββ¬βββββββββββββββββββββββββββββββββ¬ββββββββββββββ¬βββββββββββββββββββββββ
β ID β Type β Title β State β AssignedTo β
ββββββββΌβββββββββββββββΌβββββββββββββββββββββββββββββββββΌββββββββββββββΌβββββββββββββββββββββββ€
β 1001 β Epic β Updated Epic β Active β manager@company.com β
β 1002 β Task β Updated Task β Active β dev@company.com β
ββββββββ΄βββββββββββββββ΄βββββββββββββββββββββββββββββββββ΄ββββββββββββββ΄βββββββββββββββββββββββ
β
SUMMARY:
β’ Creations: 3 work items
β’ Updates: 2 work items
β’ Errors: 0
β’ Warnings: 0
- To CREATE: Leave the
Idfield empty or set it to0. - To UPDATE: Specify the
Idof the existing work item.
Id,Type,Title,State,AssignedTo,Description
,Task,New Task,New,user@company.com,Automatically created task
0,Bug,New Bug,New,dev@company.com,Detected bug
1001,Epic,Updated Epic,Active,manager@company.com,Updated epicπ See the Complete Upsert Guide for more details
| Column | Required | Description | Format |
|---|---|---|---|
| Id | β | Numeric ID of the work item | Integer or empty for creation |
| Type | β | Epic, Feature, Product Backlog Item, etc. | Text |
| Title | β | Title of the work item | Text |
| State | β | Status (New, Active, Resolved, etc.) | Text |
| AssignedTo | β | Assigned person (full name or email) | Text |
| Description | β | Detailed description | Text (HTML automatically converted) |
| RemainingWork | β | Remaining work | Decimal (comma OR period accepted) |
| Tags | β | Tags separated by semicolons | Text |
| IterationPath | β | Iteration path | Text |
| AreaPath | β | Area path | Text |
The script now supports both formats for numeric values:
- French Format:
0,52,751,25 - English Format:
0.52.751.25
Conversion is automatic to the format required by the Azure DevOps API.
Id,Type,Title,State,AssignedTo,Description,RemainingWork,Tags,IterationPath
1234,Task,Implement API,Active,john.doe@company.com,Develop the REST API,0.5,backend;api,Project\Sprint 1
5678,Bug,Fix login bug,New,jane.smith@company.com,Login not working,2.25,bug;urgent,Project\Sprint 1
,Feature,New Feature,New,pm@company.com,Feature to be created,8,new;feature,Project\Sprint 2
0,Epic,New Epic,New,manager@company.com,Epic to be created,,,Project\Release 1Note: Values like 0,5 and 2,25 are automatically converted to 0.5 and 2.25 for the Azure DevOps API.
- β Verifies connection to Azure DevOps.
- β Complete CSV format validation with line-by-line analysis.
- β Checks required and optional columns.
- β Validates data types (numbers, email formats, etc.).
- β Supports both French (comma) and English (period) decimal formats.
- β Checks the existence of work items before modification.
- β Full stop on error with detailed diagnostics.
- Preliminary Analysis: CSV validation + visual summary.
- Simulation Mode (
-WhatIf): Full test without modification. - Analysis-Only Mode (
-ShowSummaryOnly): Analysis without execution.
- If even one error is detected in the CSV, the import is completely canceled.
- Detailed display of all errors found with line numbers.
- Color-coded logs for easier tracking and debugging.
- Precise error messages with correction suggestions.
# First, run the setup script
.\Setup.ps1# Export ALL work items (no more 80-item limit)
.\AzureDevOpsItemsImporter.ps1 -Organization "contoso" -Project "WebApp" -Action Export -CsvFilePath "full-export.csv"# Analysis only (no modification)
.\AzureDevOpsItemsImporter.ps1 -Organization "contoso" -Project "WebApp" -Action Import -CsvFilePath "modifications.csv" -ShowSummaryOnly
# Test in simulation
.\AzureDevOpsItemsImporter.ps1 -Organization "contoso" -Project "WebApp" -Action Import -CsvFilePath "modifications.csv" -WhatIf
# Real import with confirmation
.\AzureDevOpsItemsImporter.ps1 -Organization "contoso" -Project "WebApp" -Action Import -CsvFilePath "modifications.csv" -Verbose# Import without confirmation (for automated scripts)
.\AzureDevOpsItemsImporter.ps1 -Organization "contoso" -Project "WebApp" -Action Import -CsvFilePath "modifications.csv" -Force# Create the file with your token
"ghp_1234567890abcdef..." | Out-File -FilePath "personal-access-token.pat" -Encoding UTF8 -NoNewline
# Verify the file was created
Get-Content "personal-access-token.pat"- β
.patfiles are automatically excluded by.gitignore. - β Never commit tokens to source code.
- β Use tokens with minimal required permissions.
- β Regularly regenerate tokens.
- Store your tokens in local
.patfiles. - Use explicit file names (e.g.,
azure-devops-prod.pat). - Set an expiration date on your tokens.
- Revoke unused tokens.
- HTML descriptions are converted to plain text during export.
- Only standard work item types are supported (Epic, Feature, PBI, Task, User Story, Bug).
- Attachments are not managed.
- β No limit on the number of exported work items (80-item limit fixed).
- Batch processing of 200 work items for export.
- Automatic pause every 10 batches to avoid API overload.
- Fallback method by ID ranges in case of API issues.
- PAT tokens must have Work Items (Read & Write) and Project (Read) permissions.
- Secure storage of tokens in
.patfiles excluded from Git.
Interactive configuration script for first use:
.\Setup.ps1Validation script to analyze an exported CSV file:
.\ValidateExport.ps1 -CsvFile "export.csv"Complete guide to using the upsert feature (create + update):
- CSV format for creation and update.
- Practical usage examples.
- Best practices and troubleshooting.
# ALWAYS use -WhatIf before the real import
.\AzureDevOpsItemsImporter.ps1 -Organization "myorg" -Project "myproject" -Action Import -CsvFilePath "file.csv" -WhatIf- Verify that the
.patfile exists and contains the correct token. - Confirm that the token has not expired.
- Ensure the token has the correct permissions.
- Verify your access token.
- Confirm the organization and project names (case-sensitive).
- Ensure the token has the correct permissions.
- Use the test script:
.\TestConnection.ps1 -Organization "myorg" -Project "myproject" -Token "mytoken".