-
Notifications
You must be signed in to change notification settings - Fork 0
BestPractices
Michael Zanatta edited this page Aug 13, 2026
·
1 revision
This guide provides best practices and recommendations for using AzureDevOpsDscNative effectively in production environments.
- Configuration Management
- Security Best Practices
- Performance Optimization
- Error Handling & Troubleshooting
- Large-Scale Deployments
- Testing & Validation
- Maintenance & Updates
Separate configurations for different environments:
# Structure example
.
├── Configurations
│ ├── Dev
│ │ ├── BaseConfig.ps1
│ │ └── Services.ps1
│ ├── Staging
│ │ ├── BaseConfig.ps1
│ │ └── Services.ps1
│ └── Production
│ ├── BaseConfig.ps1
│ └── Services.ps1
├── Common
│ └── SharedFunctions.ps1
└── Deploy.ps1Separate data from configuration logic:
# ConfigurationData.psd1
@{
AllNodes = @(
@{
NodeName = 'localhost'
Environment = 'Production'
OrganizationName = 'ProdOrg'
Projects = @(
@{ Name = 'Project1'; Template = 'Agile' }
@{ Name = 'Project2'; Template = 'Scrum' }
)
}
)
}
# Configuration.ps1
Configuration DeployAzureDevOps {
Param([hashtable]$ConfigurationData)
Import-DscResource -ModuleName 'AzureDevOpsDscNative'
Node $AllNodes.NodeName {
foreach ($project in $Node.Projects) {
AzDoProject "Project_$($project.Name)" {
Ensure = 'Present'
ProjectName = $project.Name
ProcessTemplate = $project.Template
SourceControlType = 'Git'
Visibility = 'Private'
}
}
}
}
# Usage
$data = Import-PowerShellDataFile -Path ConfigurationData.psd1
DeployAzureDevOps -ConfigurationData $dataEnsure configurations are idempotent (safe to run multiple times):
# Good: Idempotent
Configuration IdempotentConfig {
Import-DscResource -ModuleName 'AzureDevOpsDscNative'
Node localhost {
AzDoProject 'MyProject' {
Ensure = 'Present'
ProjectName = 'MyProject'
SourceControlType = 'Git'
ProcessTemplate = 'Agile'
Visibility = 'Private'
}
# This will only be applied if project is present
AzDoProjectGroup 'ProjectAdmins' {
Ensure = 'Present'
ProjectName = 'MyProject'
GroupName = 'Project Admins'
DependsOn = '[AzDoProject]MyProject'
}
}
}
# Bad: Not idempotent - will fail if run twice
Configuration NonIdempotent {
Node localhost {
Script CreateProject {
SetScript = {
# Direct API call without idempotence checking
}
}
}
}Explicitly define resource dependencies:
Configuration WithDependencies {
Import-DscResource -ModuleName 'AzureDevOpsDscNative'
Node localhost {
# Create project first
AzDoProject 'MyProject' {
Ensure = 'Present'
ProjectName = 'MyProject'
SourceControlType = 'Git'
ProcessTemplate = 'Agile'
Visibility = 'Private'
}
# Create repo only after project exists
AzDoGitRepository 'MainRepo' {
Ensure = 'Present'
ProjectName = 'MyProject'
RepositoryName = 'MainRepository'
DependsOn = '[AzDoProject]MyProject'
}
# Configure permissions only after repo exists
AzDoGitPermission 'RepoAccess' {
RepositoryName = 'MainRepository'
ProjectName = 'MyProject'
IdentityName = 'Project Admins'
PermissionName = 'Contribute'
Allow = $true
DependsOn = '[AzDoGitRepository]MainRepo'
}
}
}Use version control for all configurations:
# Version configuration files
git tag -a v1.0.0 -m "Initial DSC configuration"
# Document changes
<#
v1.0.0 - Initial Release
- Basic project setup
- Team management
- Repository configuration
v1.1.0 - Added Pipeline Support
- Pipeline creation
- Environment management
- Check configuration
#># Bad: Credentials in configuration
Configuration BadCredentials {
Node localhost {
# NEVER DO THIS
$token = 'your-pat-token-hardcoded'
}
}
# Good: Use secure storage
Configuration GoodCredentials {
Node localhost {
# Retrieve from secure storage
$token = Get-Secret -Name 'AzureDevOpsPAT' -AsPlainText
}
}Configuration SecureExecution {
Import-DscResource -ModuleName 'AzureDevOpsDscNative'
Node localhost {
# Run with specific credential
AzDoProject 'MyProject' {
Ensure = 'Present'
ProjectName = 'MyProject'
SourceControlType = 'Git'
ProcessTemplate = 'Agile'
Visibility = 'Private'
PsDscRunAsCredential = $credential
}
}
}Configuration RBACSetup {
Import-DscResource -ModuleName 'AzureDevOpsDscNative'
Node localhost {
# Create role-specific groups
AzDoOrganizationGroup 'Developers' {
Ensure = 'Present'
GroupName = 'Developers'
GroupDescription = 'Development team members'
}
AzDoOrganizationGroup 'Admins' {
Ensure = 'Present'
GroupName = 'Admins'
GroupDescription = 'Azure DevOps administrators'
}
# Assign minimal required permissions
AzDoGroupPermission 'DeveloperPermissions' {
GroupName = 'Developers'
PermissionName = 'Create Repository'
Allow = $true
DependsOn = '[AzDoOrganizationGroup]Developers'
}
AzDoGroupPermission 'AdminPermissions' {
GroupName = 'Admins'
PermissionName = 'Administer'
Allow = $true
DependsOn = '[AzDoOrganizationGroup]Admins'
}
}
}# Enable DSC logging
Enable-DscDebug -Force
# Check configuration status
Get-DscConfigurationStatus -All
# Review compliance
Get-DscConfigurationStatus | Where-Object Type -eq 'Consistency'Configuration LeastPrivilege {
Import-DscResource -ModuleName 'AzureDevOpsDscNative'
Node localhost {
# Grant only necessary permissions
AzDoGitPermission 'ReadOnlyAccess' {
RepositoryName = 'MainRepository'
ProjectName = 'MyProject'
IdentityName = 'Readers'
PermissionName = 'GenericRead'
Allow = $true
}
AzDoGitPermission 'ContributorAccess' {
RepositoryName = 'MainRepository'
ProjectName = 'MyProject'
IdentityName = 'Contributors'
PermissionName = 'Contribute'
Allow = $true
}
}
}Group related resource configurations:
Configuration OptimizedBatching {
Import-DscResource -ModuleName 'AzureDevOpsDscNative'
Node localhost {
# Create all projects together
$projects = @('Project1', 'Project2', 'Project3')
foreach ($projectName in $projects) {
AzDoProject "Project_$projectName" {
Ensure = 'Present'
ProjectName = $projectName
SourceControlType = 'Git'
ProcessTemplate = 'Agile'
Visibility = 'Private'
}
}
}
}# Configure independent resources in parallel
Configuration ParallelConfiguration {
Import-DscResource -ModuleName 'AzureDevOpsDscNative'
Node localhost {
# These can run in parallel (no dependencies)
AzDoProject 'Project1' {
Ensure = 'Present'
ProjectName = 'Project1'
SourceControlType = 'Git'
ProcessTemplate = 'Agile'
Visibility = 'Private'
}
AzDoProject 'Project2' {
Ensure = 'Present'
ProjectName = 'Project2'
SourceControlType = 'Git'
ProcessTemplate = 'Scrum'
Visibility = 'Private'
}
# These must wait for projects above (have dependencies)
AzDoGitRepository 'Repo1' {
Ensure = 'Present'
ProjectName = 'Project1'
RepositoryName = 'Repository1'
DependsOn = '[AzDoProject]Project1'
}
}
}# Cache organization information to avoid repeated API calls
$script:orgCache = @{}
function Get-CachedOrganization {
param([string]$OrgName)
if (-not $script:orgCache.Contains($OrgName)) {
# Fetch from API and cache
$script:orgCache[$OrgName] = Get-AzDevOpsOrganization -Name $OrgName
}
return $script:orgCache[$OrgName]
}# Measure configuration execution time
$startTime = Get-Date
$config | Start-DscConfiguration -Wait -Verbose
$endTime = Get-Date
Write-Host "Configuration took $($endTime - $startTime) to complete"Configuration WithErrorHandling {
Import-DscResource -ModuleName 'AzureDevOpsDscNative'
Node localhost {
AzDoProject 'MyProject' {
Ensure = 'Present'
ProjectName = 'MyProject'
SourceControlType = 'Git'
ProcessTemplate = 'Agile'
Visibility = 'Private'
ErrorAction = 'Stop'
}
}
}
# Execute with error handling
try {
$config | Start-DscConfiguration -Wait -Verbose -ErrorAction Stop
}
catch {
Write-Error "DSC configuration failed: $_"
# Implement recovery logic
}# Enable verbose output for troubleshooting
$config | Start-DscConfiguration -Wait -Verbose
# Check DSC event log
Get-WinEvent -LogName 'DSC/Operational' | Select-Object TimeCreated, Message | Out-GridViewConfiguration TestConfiguration {
Import-DscResource -ModuleName 'AzureDevOpsDscNative'
Node localhost {
# Your configuration here
}
}
# Test without applying changes
Test-DscConfiguration -Path ./TestConfiguration -Verbose
# Check what would change
Compare-DscConfiguration -ReferenceConfiguration ./TestConfiguration# Resource modules for reuse
function New-ProjectConfiguration {
param(
[string]$ProjectName,
[string]$ProcessTemplate
)
AzDoProject "Project_$ProjectName" {
Ensure = 'Present'
ProjectName = $ProjectName
SourceControlType = 'Git'
ProcessTemplate = $ProcessTemplate
Visibility = 'Private'
}
}
# Use in main configuration
Configuration LargeScaleDeployment {
Import-DscResource -ModuleName 'AzureDevOpsDscNative'
Node localhost {
New-ProjectConfiguration -ProjectName 'Frontend' -ProcessTemplate 'Agile'
New-ProjectConfiguration -ProjectName 'Backend' -ProcessTemplate 'Scrum'
New-ProjectConfiguration -ProjectName 'DevOps' -ProcessTemplate 'Agile'
}
}# CompleteProjectSetup.psd1 - Composite resource
@{
RootModule = 'CompleteProjectSetup.psm1'
ModuleVersion = '1.0.0'
CompanyName = 'Your Company'
FunctionsToExport = @()
DscResourcesToExport = @('CompleteProjectSetup')
}
# CompleteProjectSetup.psm1
Configuration CompleteProjectSetup {
[DscResource()]
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[String]$ProjectName
)
Import-DscResource -ModuleName 'AzureDevOpsDscNative'
# Complete project setup with all standard resources
AzDoProject $ProjectName {
Ensure = 'Present'
ProjectName = $ProjectName
SourceControlType = 'Git'
ProcessTemplate = 'Agile'
Visibility = 'Private'
}
}Configuration ProgressiveRollout {
param(
[ValidateSet('Dev', 'Staging', 'Production')]
[string]$Environment
)
# Different configurations per environment
if ($Environment -eq 'Dev') {
# Limited setup for dev
}
elseif ($Environment -eq 'Staging') {
# Staging setup
}
else {
# Full production setup
}
}# Create Pester tests for configurations
Describe 'Azure DevOps DSC Configuration' {
It 'Should create project' {
# Mock the Azure DevOps API
Mock Get-DscResource { return $true }
# Test your configuration
{ MyConfiguration | Start-DscConfiguration -Wait } | Should -Not -Throw
}
}
# Run tests
Invoke-Pester -Path .\ConfigurationTests.psd1 -Verbose# Test against actual Azure DevOps instance
Describe 'Azure DevOps Integration' {
It 'Should create and verify project' {
$config | Start-DscConfiguration -Wait
# Verify the resource was created
Get-AzDoProject -ProjectName 'TestProject' | Should -Not -BeNullOrEmpty
}
AfterAll {
# Clean up test resources
Remove-AzDoProject -ProjectName 'TestProject'
}
}# Check for module updates
Find-Module AzureDevOpsDscNative | Select-Object Name, Version
# Update to latest version
Update-Module -Name AzureDevOpsDscNative
# Verify update
Get-Module AzureDevOpsDscNative -ListAvailable | Sort-Object Version# Keep detailed changelog
<#
CHANGELOG.md
## [2.0.0] - 2025-01-15
### Added
- Support for new pipeline features
- Environment permissions management
### Changed
- Updated authentication module
- Improved error messages
### Deprecated
- Legacy authentication method
### Fixed
- Bug in permission assignment
- Resource naming issue
#># Check for configuration drift
Get-DscConfigurationStatus
# Monitor compliance over time
$status = Get-DscConfigurationStatus
if ($status.ResourcesNotInDesiredState.Count -gt 0) {
Write-Warning "Configuration drift detected"
# Take corrective action
Start-DscConfiguration -Path ./Configuration -Wait
}# Regular backups of configurations
$backupPath = "C:\Backups\DSC\$(Get-Date -Format 'yyyyMMdd')"
Copy-Item -Path 'C:\DSC\Configurations' -Destination $backupPath -Recurse
# Version control
git commit -m "Configuration backup $(Get-Date -Format 'yyyy-MM-dd')"Configuration Management
- Organize configurations by environment
- Use configuration data files
- Implement idempotency
- Define dependencies explicitly
- Version configurations
Security
- Never hardcode credentials
- Use secure credential storage
- Implement RBAC
- Audit changes
- Apply least privilege
Performance
- Batch related resources
- Use parallel processing
- Implement caching
- Monitor performance
Reliability
- Handle errors properly
- Enable logging
- Test before deployment
- Progressive rollout
- Monitor drift
Maintenance
- Keep module updated
- Document changes
- Monitor compliance
- Regular backups