1+ <#
2+ . SYNOPSIS
3+ Optimizes Adobe license allocation by reclaiming unused licenses
4+ . DESCRIPTION
5+ Identifies inactive users and automatically reclaims their licenses
6+ . EXAMPLE
7+ .\Optimize-Licenses.ps1 -InactiveDays 30 -AutoReclaim
8+ #>
9+
10+ [CmdletBinding ()]
11+ param (
12+ [int ]$InactiveDays = 30 ,
13+ [switch ]$AutoReclaim ,
14+ [switch ]$GenerateReport ,
15+ [switch ]$TestMode ,
16+ [string ]$ConfigPath = " ..\..\config\adobe-config.json"
17+ )
18+
19+ # Initialize logging
20+ $script :LogPath = " ..\..\logs\license-optimization-$ ( Get-Date - Format ' yyyyMMdd' ) .log"
21+
22+ function Write-Log {
23+ param (
24+ [string ]$Message ,
25+ [string ]$Level = " INFO"
26+ )
27+
28+ $timestamp = Get-Date - Format " yyyy-MM-dd HH:mm:ss"
29+ $logEntry = " [$timestamp ] [$Level ] $Message "
30+
31+ Add-Content - Path $script :LogPath - Value $logEntry
32+
33+ switch ($Level ) {
34+ " ERROR" { Write-Host $logEntry - ForegroundColor Red }
35+ " WARNING" { Write-Host $logEntry - ForegroundColor Yellow }
36+ " SUCCESS" { Write-Host $logEntry - ForegroundColor Green }
37+ default { Write-Host $logEntry - ForegroundColor White }
38+ }
39+ }
40+
41+ function Get-InactiveUsers {
42+ param (
43+ [int ]$Days ,
44+ [string ]$Token ,
45+ $Config
46+ )
47+
48+ Write-Log " Fetching user activity data..."
49+
50+ if ($TestMode ) {
51+ # Generate test data
52+ return @ (
53+ [PSCustomObject ]@ {Email = " inactive1@company.com" ; LastLogin = (Get-Date ).AddDays(-45 ); Products = @ (" Photoshop" , " Illustrator" )}
54+ [PSCustomObject ]@ {Email = " inactive2@company.com" ; LastLogin = (Get-Date ).AddDays(-60 ); Products = @ (" Creative Cloud" )}
55+ [PSCustomObject ]@ {Email = " inactive3@company.com" ; LastLogin = (Get-Date ).AddDays(-90 ); Products = @ (" Acrobat DC" )}
56+ )
57+ }
58+
59+ $headers = @ {
60+ " Authorization" = " Bearer $Token "
61+ " X-Api-Key" = $Config.adobe.client_id
62+ }
63+
64+ $url = " https://usermanagement.adobe.io/v2/usermanagement/users/$ ( $Config.adobe.org_id ) "
65+
66+ try {
67+ $response = Invoke-RestMethod - Uri $url - Method Get - Headers $headers
68+ $users = $response.users
69+
70+ $inactiveUsers = $users | Where-Object {
71+ $lastLogin = [DateTime ]::Parse($_.lastLogin )
72+ $daysSinceLogin = (Get-Date ) - $lastLogin
73+ $daysSinceLogin.Days -gt $Days
74+ }
75+
76+ Write-Log " Found $ ( $inactiveUsers.Count ) inactive users (>$Days days)" " WARNING"
77+ return $inactiveUsers
78+ }
79+ catch {
80+ Write-Log " Failed to fetch users: $_ " " ERROR"
81+ throw
82+ }
83+ }
84+
85+ function Remove-UserProducts {
86+ param (
87+ [string ]$Email ,
88+ [string []]$Products ,
89+ [string ]$Token ,
90+ $Config
91+ )
92+
93+ if ($TestMode ) {
94+ Write-Log " TEST MODE: Would remove products from $Email : $ ( $Products -join ' , ' ) " " WARNING"
95+ return @ {success = $true }
96+ }
97+
98+ $headers = @ {
99+ " Authorization" = " Bearer $Token "
100+ " X-Api-Key" = $Config.adobe.client_id
101+ " Content-Type" = " application/json"
102+ }
103+
104+ $body = @ {
105+ user = @ {email = $Email }
106+ do = @ (
107+ @ {
108+ remove = @ {
109+ product = $Products
110+ }
111+ }
112+ )
113+ } | ConvertTo-Json - Depth 10
114+
115+ $url = " https://usermanagement.adobe.io/v2/usermanagement/action/$ ( $Config.adobe.org_id ) "
116+
117+ try {
118+ $response = Invoke-RestMethod - Uri $url - Method Post - Headers $headers - Body $body
119+ Write-Log " Successfully removed products from $Email " " SUCCESS"
120+ return $response
121+ }
122+ catch {
123+ Write-Log " Failed to remove products from $Email : $_ " " ERROR"
124+ throw
125+ }
126+ }
127+
128+ function Calculate-Savings {
129+ param (
130+ [array ]$ReclaimedLicenses
131+ )
132+
133+ $licenseCosts = @ {
134+ " Creative Cloud" = 80
135+ " Photoshop" = 35
136+ " Illustrator" = 35
137+ " Acrobat DC" = 25
138+ " InDesign" = 35
139+ " Premiere Pro" = 35
140+ " After Effects" = 35
141+ }
142+
143+ $totalSavings = 0
144+
145+ foreach ($license in $ReclaimedLicenses ) {
146+ $cost = $licenseCosts [$license ]
147+ if ($cost ) {
148+ $totalSavings += $cost
149+ } else {
150+ $totalSavings += 30 # Default cost
151+ }
152+ }
153+
154+ return $totalSavings
155+ }
156+
157+ function Generate-OptimizationReport {
158+ param (
159+ $InactiveUsers ,
160+ $ReclaimedLicenses ,
161+ $Savings
162+ )
163+
164+ $html = @"
165+ <!DOCTYPE html>
166+ <html>
167+ <head>
168+ <title>Adobe License Optimization Report</title>
169+ <style>
170+ body { font-family: Arial, sans-serif; margin: 40px; }
171+ h1 { color: #FF0000; }
172+ .summary { background: #f0f0f0; padding: 20px; border-radius: 5px; margin: 20px 0; }
173+ .savings { color: green; font-size: 24px; font-weight: bold; }
174+ table { width: 100%; border-collapse: collapse; margin: 20px 0; }
175+ th { background: #333; color: white; padding: 10px; text-align: left; }
176+ td { padding: 10px; border-bottom: 1px solid #ddd; }
177+ .recommendation { background: #fff3cd; padding: 15px; border-left: 4px solid #ffc107; margin: 20px 0; }
178+ </style>
179+ </head>
180+ <body>
181+ <h1>Adobe License Optimization Report</h1>
182+ <p>Generated: $ ( Get-Date - Format " yyyy-MM-dd HH:mm:ss" ) </p>
183+
184+ <div class="summary">
185+ <h2>Executive Summary</h2>
186+ <p>Inactive Users Identified: <strong>$ ( $InactiveUsers.Count ) </strong></p>
187+ <p>Licenses Reclaimed: <strong>$ ( $ReclaimedLicenses.Count ) </strong></p>
188+ <p class="savings">Monthly Savings: `$ $Savings </p>
189+ <p class="savings">Annual Savings: `$ $ ( $Savings * 12 ) </p>
190+ </div>
191+
192+ <h2>Inactive Users</h2>
193+ <table>
194+ <tr>
195+ <th>Email</th>
196+ <th>Last Login</th>
197+ <th>Days Inactive</th>
198+ <th>Products</th>
199+ </tr>
200+ "@
201+
202+ foreach ($user in $InactiveUsers ) {
203+ $daysInactive = ((Get-Date ) - $user.LastLogin ).Days
204+ $html += @"
205+ <tr>
206+ <td>$ ( $user.Email ) </td>
207+ <td>$ ( $user.LastLogin.ToString (" yyyy-MM-dd" )) </td>
208+ <td>$daysInactive </td>
209+ <td>$ ( $user.Products -join " , " ) </td>
210+ </tr>
211+ "@
212+ }
213+
214+ $html += @"
215+ </table>
216+
217+ <div class="recommendation">
218+ <h3>Recommendations</h3>
219+ <ul>
220+ <li>Review inactive users monthly</li>
221+ <li>Implement automated license reclamation after 45 days</li>
222+ <li>Consider usage-based allocation for seasonal workers</li>
223+ <li>Enable single sign-on to track actual usage</li>
224+ </ul>
225+ </div>
226+
227+ <p><small>Report generated by Adobe Enterprise Automation Suite</small></p>
228+ </body>
229+ </html>
230+ "@
231+
232+ $reportPath = " ..\..\reports\license-optimization-$ ( Get-Date - Format ' yyyyMMdd-HHmmss' ) .html"
233+ $html | Out-File - FilePath $reportPath - Encoding UTF8
234+ Write-Log " Report saved to: $reportPath " " SUCCESS"
235+
236+ # Open report in browser
237+ Start-Process $reportPath
238+ }
239+
240+ # Main execution
241+ function Main {
242+ Write-Log " === Adobe License Optimization Started ===" " INFO"
243+
244+ # Load configuration
245+ if (Test-Path $ConfigPath ) {
246+ $config = Get-Content $ConfigPath | ConvertFrom-Json
247+ } else {
248+ Write-Log " Configuration file not found: $ConfigPath " " ERROR"
249+ return
250+ }
251+
252+ # Get access token (simplified for demo)
253+ $token = if ($TestMode ) { " test_token" } else { " actual_token_here" }
254+
255+ # Get inactive users
256+ $inactiveUsers = Get-InactiveUsers - Days $InactiveDays - Token $token - Config $config
257+
258+ if ($inactiveUsers.Count -eq 0 ) {
259+ Write-Log " No inactive users found. Nothing to optimize." " SUCCESS"
260+ return
261+ }
262+
263+ $reclaimedLicenses = @ ()
264+
265+ # Process reclamation if requested
266+ if ($AutoReclaim ) {
267+ Write-Log " Starting automatic license reclamation..." " WARNING"
268+
269+ foreach ($user in $inactiveUsers ) {
270+ try {
271+ Remove-UserProducts - Email $user.Email - Products $user.Products `
272+ - Token $token - Config $config
273+
274+ $reclaimedLicenses += $user.Products
275+ }
276+ catch {
277+ Write-Log " Failed to process $ ( $user.Email ) : $_ " " ERROR"
278+ }
279+ }
280+ }
281+
282+ # Calculate savings
283+ $monthlySavings = Calculate- Savings - ReclaimedLicenses $reclaimedLicenses
284+
285+ Write-Log " Potential monthly savings: `$ $monthlySavings " " SUCCESS"
286+ Write-Log " Potential annual savings: `$ $ ( $monthlySavings * 12 ) " " SUCCESS"
287+
288+ # Generate report if requested
289+ if ($GenerateReport -or $AutoReclaim ) {
290+ Generate- OptimizationReport - InactiveUsers $inactiveUsers `
291+ - ReclaimedLicenses $reclaimedLicenses - Savings $monthlySavings
292+ }
293+
294+ Write-Log " === Adobe License Optimization Completed ===" " SUCCESS"
295+ }
296+
297+ # Run main function
298+ Main
0 commit comments