Public/Azure/Automation/Copy-AzAutomationRunbook.ps1

<#
    .SYNOPSIS
    Copies all runbooks from a source Azure Automation account to a destination account.
 
    .DESCRIPTION
    This function exports all runbooks from a source Azure Automation account and imports them
    into a destination Azure Automation account within the same resource group.
 
    .PARAMETER SourceAutomationAccount
    The name of the source Azure Automation account to export runbooks from.
 
    .PARAMETER DestinationAutomationAccount
    The name of the destination Azure Automation account to import runbooks into.
 
    .PARAMETER ResourceGroup
    The name of the resource group containing both Automation accounts.
 
    .PARAMETER TempFolder
    (Optional) The temporary folder path used to store exported runbooks. Defaults to a timestamped folder in the system temp directory.
    Note: Only auto-generated folders are deleted at the end. If you provide an existing folder, its contents are NOT cleaned up.
 
    .EXAMPLE
    Copy-AzAutomationRunbook -SourceAutomationAccount 'newauto' -DestinationAutomationAccount 'newauto1' -ResourceGroup 'my-rg'
 
    Copies all runbooks from 'newauto' to 'newauto1'.
 
    .EXAMPLE
    Copy-AzAutomationRunbook -SourceAutomationAccount 'newauto' -DestinationAutomationAccount 'newauto1' -ResourceGroup 'my-rg' -TempFolder 'C:\Temp\Runbooks'
 
    Copies all runbooks using a custom temporary folder.
 
    .LINK
    https://ps365.clidsys.com/docs/commands/Copy-AzAutomationRunbook
#>


function Copy-AzAutomationRunbook {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$SourceAutomationAccount,

        [Parameter(Mandatory = $true)]
        [string]$DestinationAutomationAccount,

        [Parameter(Mandatory = $true)]
        [string]$ResourceGroup,

        [Parameter(Mandatory = $false)]
        [string]$TempFolder
    )

    $tempFolderCreated = $false
    if (-not $TempFolder) {
        $TempFolder = Join-Path $env:TEMP "AzAutomationRunbooks_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
        $tempFolderCreated = $true
    }

    $isConnected = $null -ne (Get-AzContext -ErrorAction SilentlyContinue)

    if (-not $isConnected) {
        Write-Verbose 'Connecting to Azure...'
        Connect-AzAccount
    }

    # Create temp folder if it doesn't exist
    if (-not (Test-Path $TempFolder)) {
        $null = New-Item -ItemType Directory -Path $TempFolder -Force
        $tempFolderCreated = $true
        Write-Verbose "Created temp folder: $TempFolder"
    }

    # Get all runbooks from source account
    Write-Verbose "Retrieving runbooks from source account: $SourceAutomationAccount"
    $runbooks = Get-AzAutomationRunbook -AutomationAccountName $SourceAutomationAccount -ResourceGroupName $ResourceGroup

    if (-not $runbooks) {
        Write-Warning "No runbooks found in source account '$SourceAutomationAccount'."
        if ($tempFolderCreated -and (Test-Path $TempFolder)) {
            Remove-Item -Path $TempFolder -Recurse -Force -ErrorAction SilentlyContinue
        }
        return
    }

    Write-Host "$($runbooks.Count) runbook(s) found in '$SourceAutomationAccount'" -ForegroundColor Cyan

    # Export runbooks from source
    $exportedRunbooks = [System.Collections.Generic.List[PSCustomObject]]@()

    $i = 0
    foreach ($runbook in $runbooks) {
        $i++
        Write-Host "($i/$($runbooks.Count)) Exporting: $($runbook.Name)" -ForegroundColor Cyan -NoNewline

        try {
            Export-AzAutomationRunbook -ResourceGroupName $ResourceGroup -AutomationAccountName $SourceAutomationAccount -Name $runbook.Name -OutputFolder $TempFolder -Force
            $exportedFile = Get-ChildItem -Path $TempFolder -Filter "$($runbook.Name).*" | Select-Object -First 1
            Write-Host ' OK' -ForegroundColor Green

            $exportedRunbooks.Add([PSCustomObject]@{
                Name     = $runbook.Name
                Type     = $runbook.RunbookType
                Path     = $exportedFile.FullName
                Exported = $true
                Imported = $null
            })
        }
        catch {
            Write-Host ' KO' -ForegroundColor Red
            Write-Warning "Failed to export '$($runbook.Name)': $($_.Exception.Message)"

            $exportedRunbooks.Add([PSCustomObject]@{
                Name     = $runbook.Name
                Type     = $runbook.RunbookType
                Path     = $null
                Exported = $false
                Imported = $null
            })
        }
    }

    # Import runbooks into destination
    Write-Host "`nImporting runbooks into '$DestinationAutomationAccount'..." -ForegroundColor Cyan

    $j = 0
    foreach ($runbook in $exportedRunbooks | Where-Object { $_.Exported }) {
        $j++
        Write-Host "($j/$($exportedRunbooks.Where({$_.Exported}).Count)) Importing: $($runbook.Name)" -ForegroundColor Cyan -NoNewline

        try {
            Import-AzAutomationRunbook -Path $runbook.Path -ResourceGroupName $ResourceGroup -AutomationAccountName $DestinationAutomationAccount -Name $runbook.Name -Type $runbook.Type -Force -ErrorAction Stop
            $runbook.Imported = $true
            Write-Host ' OK' -ForegroundColor Green
        }
        catch {
            $runbook.Imported = $false
            Write-Host ' KO' -ForegroundColor Red
            Write-Warning "Failed to import '$($runbook.Name)': $($_.Exception.Message)"
        }
    }

    # Summary
    $exportSuccess = ($exportedRunbooks | Where-Object { $_.Exported }).Count
    $exportFail    = ($exportedRunbooks | Where-Object { -not $_.Exported }).Count
    $importSuccess = ($exportedRunbooks | Where-Object { $_.Imported -eq $true }).Count
    $importFail    = ($exportedRunbooks | Where-Object { $_.Imported -eq $false }).Count

    Write-Host "`n--- Summary ---" -ForegroundColor Cyan
    Write-Host "Exported: $exportSuccess/$($runbooks.Count)" -ForegroundColor $(if ($exportFail -eq 0) { 'Green' } else { 'Yellow' })
    Write-Host "Imported: $importSuccess/$exportSuccess" -ForegroundColor $(if ($importFail -eq 0) { 'Green' } else { 'Yellow' })

    if ($exportFail -gt 0) {
        Write-Host "Export failures ($exportFail):" -ForegroundColor Red
        $exportedRunbooks | Where-Object { -not $_.Exported } | ForEach-Object {
            Write-Host " - $($_.Name)" -ForegroundColor Red
        }
    }
    if ($importFail -gt 0) {
        Write-Host "Import failures ($importFail):" -ForegroundColor Red
        $exportedRunbooks | Where-Object { $_.Imported -eq $false } | ForEach-Object {
            Write-Host " - $($_.Name)" -ForegroundColor Red
        }
    }

    # Cleanup temp folder (only if it was auto-generated by this function)
    if ($tempFolderCreated -and (Test-Path $TempFolder)) {
        Write-Verbose "Cleaning up temp folder: $TempFolder"
        Remove-Item -Path $TempFolder -Recurse -Force -ErrorAction SilentlyContinue
    }
}