Skip to content

BestPractices

Michael Zanatta edited this page Aug 13, 2026 · 1 revision

Best Practices Guide

This guide provides best practices and recommendations for using AzureDevOpsDscNative effectively in production environments.

Table of Contents

  1. Configuration Management
  2. Security Best Practices
  3. Performance Optimization
  4. Error Handling & Troubleshooting
  5. Large-Scale Deployments
  6. Testing & Validation
  7. Maintenance & Updates

Configuration Management

1. Organize Configurations by Environment

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.ps1

2. Use Configuration Data Files

Separate 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 $data

3. Implement Idempotency Correctly

Ensure 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
            }
        }
    }
}

4. Use DependsOn for Resource Ordering

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'
        }
    }
}

5. Version Your Configurations

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
#>

Security Best Practices

1. Never Hardcode Credentials

# 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
    }
}

2. Use PsDscRunAsCredential for Sensitive Operations

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
        }
    }
}

3. Implement Role-Based Access Control (RBAC)

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'
        }
    }
}

4. Audit and Monitor Configuration Changes

# Enable DSC logging
Enable-DscDebug -Force

# Check configuration status
Get-DscConfigurationStatus -All

# Review compliance
Get-DscConfigurationStatus | Where-Object Type -eq 'Consistency'

5. Implement Least Privilege

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
        }
    }
}

Performance Optimization

1. Batch Related Resources

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'
            }
        }
    }
}

2. Use Parallel Processing Where Appropriate

# 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'
        }
    }
}

3. Implement Caching

# 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]
}

4. Monitor Resource Performance

# Measure configuration execution time
$startTime = Get-Date
$config | Start-DscConfiguration -Wait -Verbose
$endTime = Get-Date

Write-Host "Configuration took $($endTime - $startTime) to complete"

Error Handling & Troubleshooting

1. Implement Error Handling

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
}

2. Enable Verbose Logging

# Enable verbose output for troubleshooting
$config | Start-DscConfiguration -Wait -Verbose

# Check DSC event log
Get-WinEvent -LogName 'DSC/Operational' | Select-Object TimeCreated, Message | Out-GridView

3. Test Before Deploying

Configuration 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

Large-Scale Deployments

1. Modularize Configurations

# 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'
    }
}

2. Use Composite Resources

# 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'
    }
}

3. Implement Progressive Rollout

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
    }
}

Testing & Validation

1. Unit Testing DSC Resources

# 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

2. Integration Testing

# 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'
    }
}

Maintenance & Updates

1. Update Module Regularly

# 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

2. Document Configuration Changes

# 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
#>

3. Implement Configuration Drift Monitoring

# 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
}

4. Backup Configurations

# 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')"

Summary Checklist

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

Clone this wiki locally