- Pre-Deployment Checklist
- Infrastructure Setup
- Security Configuration
- Application Deployment
- Integration Setup
- Testing & Validation
- Go-Live Process
- Post-Deployment
- Adobe Admin Console - System Administrator role
- Azure AD - Global Administrator or Application Administrator
- Windows Server - Local Administrator rights
- Network - Firewall rules configured for Adobe APIs
- DNS - Ability to create/modify records if needed
- Adobe Organization ID
- Technical Account credentials
- API Client ID and Secret
- Private key for JWT signing
- Azure AD Tenant ID
- Service account credentials
Production Environment:
Primary Server:
OS: Windows Server 2019/2022
CPU: 8 cores minimum
RAM: 32GB
Storage: 500GB SSD
Network: 1Gbps
Backup Server:
OS: Windows Server 2019/2022
CPU: 4 cores
RAM: 16GB
Storage: 500GB SSD
Database:
Type: SQL Server 2019+ or PostgreSQL 13+
Storage: 100GB minimum
Backup: Daily automated backups# 1. Enable required Windows features
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
Install-WindowsFeature -Name Web-Server, Web-Common-Http, Web-Security, Web-App-Dev
# 2. Install IIS for monitoring dashboard (optional)
Install-WindowsFeature -Name IIS-WebServerRole, IIS-WebServer
# 3. Configure Windows Firewall
New-NetFirewallRule -DisplayName "Adobe API HTTPS" -Direction Outbound -Protocol TCP -RemotePort 443 -Action Allow
New-NetFirewallRule -DisplayName "Monitoring Dashboard" -Direction Inbound -Protocol TCP -LocalPort 8080 -Action Allow
# 4. Set execution policy
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine -Force
# 5. Install required software
# PowerShell 7
Invoke-WebRequest -Uri https://aka.ms/install-powershell.ps1 -UseBasicParsing | Invoke-Expression
# Python 3.11+
Invoke-WebRequest -Uri https://www.python.org/ftp/python/3.11.0/python-3.11.0-amd64.exe -OutFile python-installer.exe
Start-Process -FilePath .\python-installer.exe -ArgumentList "/quiet InstallAllUsers=1 PrependPath=1" -Wait
# Git
winget install --id Git.Git -e --source winget# 1. Clone repository
git clone https://github.com/wesellis/adobe-enterprise-automation.git
cd adobe-enterprise-automation
# 2. Install PowerShell modules
Install-Module -Name Microsoft.Graph -RequiredVersion 2.0.0 -Force
Install-Module -Name Az -RequiredVersion 10.0.0 -Force
Install-Module -Name PSLogging -Force
Install-Module -Name ImportExcel -Force
# 3. Setup Python environment
python -m venv venv
.\venv\Scripts\Activate.ps1
pip install -r requirements.txt
# 4. Create directory structure
$dirs = @(
"C:\AdobeAutomation\Config",
"C:\AdobeAutomation\Logs",
"C:\AdobeAutomation\Scripts",
"C:\AdobeAutomation\Reports",
"C:\AdobeAutomation\Temp",
"C:\AdobeAutomation\Backup"
)
$dirs | ForEach-Object { New-Item -ItemType Directory -Path $_ -Force }# Generate certificate for JWT signing
$cert = New-SelfSignedCertificate `
-Subject "CN=Adobe Automation Service" `
-KeyAlgorithm RSA `
-KeyLength 2048 `
-KeyExportPolicy Exportable `
-NotAfter (Get-Date).AddYears(2) `
-CertStoreLocation "Cert:\LocalMachine\My"
# Export private key
$password = ConvertTo-SecureString -String "YourSecurePassword" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath "C:\AdobeAutomation\Config\adobe-cert.pfx" -Password $password
# Convert to PEM format for Adobe API
openssl pkcs12 -in adobe-cert.pfx -out private.key -nodes -nocerts# Create encrypted configuration
$config = @{
Adobe = @{
OrgId = "YOUR_ORG_ID@AdobeOrg"
ClientId = "YOUR_CLIENT_ID"
ClientSecret = ConvertTo-SecureString "YOUR_SECRET" -AsPlainText -Force | ConvertFrom-SecureString
TechAccountId = "YOUR_TECH_ID@techacct.adobe.com"
PrivateKeyPath = "C:\AdobeAutomation\Config\private.key"
}
Azure = @{
TenantId = "YOUR_TENANT_ID"
ClientId = "YOUR_APP_ID"
ClientSecret = ConvertTo-SecureString "YOUR_AZURE_SECRET" -AsPlainText -Force | ConvertFrom-SecureString
}
Database = @{
ConnectionString = ConvertTo-SecureString "Server=localhost;Database=AdobeAutomation;Integrated Security=true" -AsPlainText -Force | ConvertFrom-SecureString
}
}
# Save encrypted configuration
$config | Export-Clixml -Path "C:\AdobeAutomation\Config\config.xml"
# Set ACL permissions
$acl = Get-Acl "C:\AdobeAutomation\Config"
$acl.SetAccessRuleProtection($true, $false)
$adminRule = New-Object System.Security.AccessControl.FileSystemAccessRule("BUILTIN\Administrators", "FullControl", "Allow")
$serviceRule = New-Object System.Security.AccessControl.FileSystemAccessRule("NT SERVICE\AdobeAutomation", "ReadAndExecute", "Allow")
$acl.SetAccessRule($adminRule)
$acl.SetAccessRule($serviceRule)
Set-Acl "C:\AdobeAutomation\Config" $acl-- Create database
CREATE DATABASE AdobeAutomation;
GO
USE AdobeAutomation;
GO
-- Create tables
CREATE TABLE Users (
Id INT IDENTITY(1,1) PRIMARY KEY,
Email NVARCHAR(255) UNIQUE NOT NULL,
FirstName NVARCHAR(100),
LastName NVARCHAR(100),
AdobeUserId NVARCHAR(255),
Status NVARCHAR(50),
CreatedDate DATETIME DEFAULT GETDATE(),
ModifiedDate DATETIME DEFAULT GETDATE(),
LastSyncDate DATETIME
);
CREATE TABLE LicenseAssignments (
Id INT IDENTITY(1,1) PRIMARY KEY,
UserId INT FOREIGN KEY REFERENCES Users(Id),
ProductName NVARCHAR(255),
AssignedDate DATETIME DEFAULT GETDATE(),
RemovedDate DATETIME NULL,
Status NVARCHAR(50)
);
CREATE TABLE AuditLog (
Id INT IDENTITY(1,1) PRIMARY KEY,
Action NVARCHAR(100),
TargetUser NVARCHAR(255),
PerformedBy NVARCHAR(255),
Timestamp DATETIME DEFAULT GETDATE(),
Details NVARCHAR(MAX),
Result NVARCHAR(50)
);
CREATE TABLE SystemConfig (
Key NVARCHAR(100) PRIMARY KEY,
Value NVARCHAR(MAX),
ModifiedDate DATETIME DEFAULT GETDATE()
);
-- Create indexes
CREATE INDEX IX_Users_Email ON Users(Email);
CREATE INDEX IX_Users_Status ON Users(Status);
CREATE INDEX IX_LicenseAssignments_UserId ON LicenseAssignments(UserId);
CREATE INDEX IX_AuditLog_Timestamp ON AuditLog(Timestamp);# Deploy main automation module
Copy-Item -Path ".\creative-cloud\*" -Destination "C:\AdobeAutomation\Scripts\" -Recurse
Copy-Item -Path ".\python-automation\*" -Destination "C:\AdobeAutomation\Scripts\Python\" -Recurse
# Create scheduled tasks
$taskActions = @(
@{
Name = "Adobe User Sync"
Script = "C:\AdobeAutomation\Scripts\Sync-AdobeUsers.ps1"
Schedule = "Daily at 2:00 AM"
},
@{
Name = "License Optimization"
Script = "C:\AdobeAutomation\Scripts\Optimize-Licenses.ps1"
Schedule = "Weekly on Sunday at 3:00 AM"
},
@{
Name = "Health Check"
Script = "C:\AdobeAutomation\Scripts\Test-SystemHealth.ps1"
Schedule = "Every 15 minutes"
}
)
foreach ($task in $taskActions) {
$action = New-ScheduledTaskAction -Execute "PowerShell.exe" `
-Argument "-ExecutionPolicy Bypass -File `"$($task.Script)`""
$trigger = switch -Regex ($task.Schedule) {
"Daily" { New-ScheduledTaskTrigger -Daily -At 2:00AM }
"Weekly" { New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At 3:00AM }
"Every 15" { New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 15) }
}
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable
Register-ScheduledTask -TaskName $task.Name -Action $action -Trigger $trigger -Principal $principal -Settings $settings
}# Create Windows Service for monitoring
$serviceName = "AdobeAutomationMonitor"
$servicePath = "C:\AdobeAutomation\Scripts\MonitoringService.exe"
New-Service -Name $serviceName `
-BinaryPathName $servicePath `
-DisplayName "Adobe Automation Monitor" `
-Description "Monitors Adobe automation processes and health" `
-StartupType Automatic
# Configure service recovery
sc.exe failure $serviceName reset=86400 actions=restart/60000/restart/60000/restart/60000
# Start service
Start-Service -Name $serviceName# Connect to Azure AD
Connect-MgGraph -Scopes "User.Read.All", "Group.Read.All", "Application.ReadWrite.All"
# Create application registration
$app = New-MgApplication -DisplayName "Adobe Automation Service" `
-SignInAudience "AzureADMyOrg" `
-RequiredResourceAccess @{
ResourceAppId = "00000003-0000-0000-c000-000000000000" # Microsoft Graph
ResourceAccess = @(
@{Id = "df021288-bdef-4463-88db-98f22de89214"; Type = "Role"} # User.Read.All
@{Id = "62a82d76-70ea-41e2-9197-370581804d09"; Type = "Role"} # Group.Read.All
)
}
# Create service principal
$sp = New-MgServicePrincipal -AppId $app.AppId
# Grant admin consent
$graphSp = Get-MgServicePrincipal -Filter "appId eq '00000003-0000-0000-c000-000000000000'"
$graphSp.AppRoles | ForEach-Object {
if ($_.Value -in @("User.Read.All", "Group.Read.All")) {
New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id `
-PrincipalId $sp.Id `
-ResourceId $graphSp.Id `
-AppRoleId $_.Id
}
}# Test Adobe API connection
function Test-AdobeConnection {
$config = Import-Clixml -Path "C:\AdobeAutomation\Config\config.xml"
# Generate JWT
$jwt = New-AdobeJWT -Config $config.Adobe
# Exchange for access token
$tokenResponse = Invoke-RestMethod -Uri "https://ims-na1.adobelogin.com/ims/exchange/jwt" `
-Method POST `
-Body @{
client_id = $config.Adobe.ClientId
client_secret = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($config.Adobe.ClientSecret))
jwt_token = $jwt
}
if ($tokenResponse.access_token) {
Write-Host "✅ Adobe API connection successful" -ForegroundColor Green
# Test user endpoint
$headers = @{
"Authorization" = "Bearer $($tokenResponse.access_token)"
"X-Api-Key" = $config.Adobe.ClientId
}
$users = Invoke-RestMethod -Uri "https://usermanagement.adobe.io/v2/usermanagement/users/$($config.Adobe.OrgId)" `
-Headers $headers `
-Method GET
Write-Host "✅ Found $($users.users.Count) users in Adobe organization" -ForegroundColor Green
return $true
}
return $false
}
# Run test
Test-AdobeConnection# Install Pester for testing
Install-Module -Name Pester -Force -SkipPublisherCheck
# Run unit tests
Invoke-Pester -Path ".\Tests\*.Tests.ps1" -OutputFormat NUnitXml -OutputFile ".\TestResults.xml"# test_integration.py
import asyncio
import pytest
from adobe_api_client import AdobeAPIClient
@pytest.mark.asyncio
async def test_full_user_lifecycle():
"""Test complete user provisioning lifecycle"""
config = load_config("config.json")
test_email = "test.user@company.com"
async with AdobeAPIClient(**config) as client:
# 1. Create user
user = await client.create_user(
email=test_email,
first_name="Test",
last_name="User"
)
assert user['success'] == True
# 2. Assign product
product_result = await client.assign_products(
email=test_email,
products=["Creative Cloud"]
)
assert product_result['success'] == True
# 3. Verify user exists
user_info = await client.get_user(test_email)
assert user_info['email'] == test_email
assert "Creative Cloud" in user_info['products']
# 4. Remove product
remove_result = await client.remove_products(
email=test_email,
products=["Creative Cloud"]
)
assert remove_result['success'] == True
# 5. Delete user
delete_result = await client.delete_user(test_email)
assert delete_result['success'] == True
# Run tests
pytest test_integration.py -v# Simulate concurrent user provisioning
$testUsers = 1..100 | ForEach-Object {
@{
Email = "loadtest$_@company.com"
FirstName = "Load"
LastName = "Test$_"
}
}
# Measure performance
$results = Measure-Command {
$testUsers | ForEach-Object -Parallel {
& "C:\AdobeAutomation\Scripts\New-AdobeUser.ps1" @_ -TestMode
} -ThrottleLimit 10
}
Write-Host "Processed 100 users in $($results.TotalSeconds) seconds"
Write-Host "Average time per user: $($results.TotalSeconds / 100) seconds"# Enable for pilot group only
Set-SystemConfig -Key "PilotMode" -Value "true"
Set-SystemConfig -Key "PilotGroup" -Value "IT-Department"
# Monitor closely
Start-Job -ScriptBlock {
while ($true) {
Get-AdobeAutomationMetrics | Out-File ".\pilot-metrics.log" -Append
Start-Sleep -Seconds 300
}
}# Progressive department enablement
$departments = @("IT", "Creative", "Marketing", "Sales", "Operations")
$rolloutSchedule = @{}
foreach ($dept in $departments) {
$rolloutSchedule[$dept] = (Get-Date).AddDays($departments.IndexOf($dept) * 2)
}
# Automated rollout
foreach ($dept in $rolloutSchedule.Keys) {
$date = $rolloutSchedule[$dept]
$trigger = New-ScheduledTaskTrigger -Once -At $date
$action = New-ScheduledTaskAction -Execute "PowerShell.exe" `
-Argument "-Command `"Enable-DepartmentAutomation -Department '$dept'`""
Register-ScheduledTask -TaskName "Enable-$dept" -Trigger $trigger -Action $action
}# Final production cutover
Set-SystemConfig -Key "PilotMode" -Value "false"
Set-SystemConfig -Key "ProductionMode" -Value "true"
# Enable all features
Enable-AllAutomationFeatures
# Verify all systems
$checks = @(
"Test-AdobeAPIConnection",
"Test-AzureADConnection",
"Test-DatabaseConnection",
"Test-ScheduledTasks",
"Test-ServiceHealth"
)
$results = $checks | ForEach-Object {
& $_
}
if ($results -notcontains $false) {
Write-Host "✅ All systems operational - GO LIVE SUCCESSFUL" -ForegroundColor Green
}# Configure monitoring dashboard
Install-Module -Name UniversalDashboard -Force
$dashboard = New-UDDashboard -Title "Adobe Automation Monitor" -Content {
New-UDRow {
New-UDColumn -Size 4 {
New-UDCard -Title "Users Processed Today" -Content {
New-UDCounter -Value (Get-ProcessedUsersCount -Today)
}
}
New-UDColumn -Size 4 {
New-UDCard -Title "Active Licenses" -Content {
New-UDCounter -Value (Get-ActiveLicenseCount)
}
}
New-UDColumn -Size 4 {
New-UDCard -Title "System Health" -Content {
New-UDProgress -Value (Get-SystemHealthScore)
}
}
}
New-UDRow {
New-UDColumn -Size 12 {
New-UDChart -Title "API Calls (Last 24 Hours)" -Type Line -Data {
Get-APICallMetrics -Hours 24 | Out-UDChartData -DataProperty Count -LabelProperty Time
}
}
}
}
Start-UDDashboard -Dashboard $dashboard -Port 8080# Automated backup script
$backupScript = {
$date = Get-Date -Format "yyyyMMdd"
$backupPath = "C:\AdobeAutomation\Backup\$date"
# Create backup directory
New-Item -ItemType Directory -Path $backupPath -Force
# Backup configuration
Copy-Item -Path "C:\AdobeAutomation\Config\*" -Destination "$backupPath\Config" -Recurse
# Backup scripts
Copy-Item -Path "C:\AdobeAutomation\Scripts\*" -Destination "$backupPath\Scripts" -Recurse
# Backup database
Backup-SqlDatabase -ServerInstance "localhost" -Database "AdobeAutomation" `
-BackupFile "$backupPath\Database\AdobeAutomation.bak"
# Compress backup
Compress-Archive -Path $backupPath -DestinationPath "$backupPath.zip"
Remove-Item -Path $backupPath -Recurse -Force
# Upload to Azure Storage (optional)
$storageContext = New-AzStorageContext -StorageAccountName "backupstorage" -UseConnectedAccount
Set-AzStorageBlobContent -File "$backupPath.zip" -Container "adobe-backups" -Context $storageContext
}
# Schedule daily backup
$trigger = New-ScheduledTaskTrigger -Daily -At 3:00AM
$action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-Command & {$backupScript}"
Register-ScheduledTask -TaskName "Adobe Automation Backup" -Trigger $trigger -Action $action# Generate documentation
$documentation = @"
# Adobe Automation System Documentation
Generated: $(Get-Date)
## System Configuration
$((Get-SystemConfig | ConvertTo-Json -Depth 3))
## Installed Components
$((Get-InstalledComponents | Format-Table -AutoSize | Out-String))
## Scheduled Tasks
$((Get-ScheduledTask | Where-Object {$_.TaskName -like "*Adobe*"} | Format-Table -AutoSize | Out-String))
## Recent Activity
$((Get-RecentActivity -Days 7 | Format-Table -AutoSize | Out-String))
"@
$documentation | Out-File "C:\AdobeAutomation\Documentation\SystemDoc-$(Get-Date -Format 'yyyyMMdd').md"Track these KPIs post-deployment:
| Metric | Target | Measurement |
|---|---|---|
| User Provisioning Time | <10 minutes | Avg time from request to completion |
| License Utilization | >90% | Active licenses / Total licenses |
| API Success Rate | >99% | Successful calls / Total calls |
| System Uptime | >99.9% | Uptime minutes / Total minutes |
| Error Rate | <1% | Errors / Total operations |
| Cost Savings | $200K/year | Manual cost - Automated cost |
- Technical Lead: automation-team@company.com
- Adobe Support: enterprise-support@adobe.com
- Emergency Hotline: +1-XXX-XXX-XXXX
- Documentation: https://wiki.company.com/adobe-automation
🎉 Deployment Complete! Your Adobe Enterprise Automation system is now operational.