Password Rotation PowerShell Script

# Verify Script Permissions
$executionPolicy = Get-ExecutionPolicy
if ($executionPolicy -eq "Restricted") {
    Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force
}

# Import Required Modules
Import-Module Microsoft.Graph.Authentication -Force
Import-Module Microsoft.Graph.Users -Force
Import-Module Microsoft.Graph.Identity.DirectoryManagement -Force

# Hudu Configuration
$huduApiKey = "your-hudu-api-key"
$huduBaseUrl = "https://your-hudu-domain/api/v1"
$huduHeaders = @{
    "x-api-key"    = $huduApiKey
    "Content-Type" = "application/json"
}

# Function to Get Companies from Hudu
function Get-HuduCompanies {
    try {
        $response = Invoke-RestMethod -Uri "$huduBaseUrl/companies" -Method Get -Headers $huduHeaders
        return $response.companies
    } catch {
        Write-Host "Failed to retrieve companies from Hudu: $_" -ForegroundColor Red
        return $null
    }
}


# Establish the connection to the M365 Tenant
function Connect-M365Tenant {
    param (
        [string]$TenantId,
        [string]$ClientId,
        [string]$ClientSecret
    )
    
    try {
        $tokenBody = @{
            client_id     = $ClientId
            scope         = "https://graph.microsoft.com/.default"
            client_secret = $ClientSecret
            grant_type    = "client_credentials"
        }
        
        $tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" -Method Post -Body $tokenBody
        
        # Convert the access token to a SecureString
        $secureToken = ConvertTo-SecureString -String $tokenResponse.access_token -AsPlainText -Force
        
        # Connect using the SecureString token
        Connect-MgGraph -AccessToken $secureToken
        Write-Host "Connected to Tenant: $TenantId" -ForegroundColor Green
        return $true
    } catch {
        Write-Host "Failed to connect to Tenant $TenantId : $_" -ForegroundColor Red
        return $false
    }
}


# Generate the secure new password
function Generate-SecurePassword {
    $Chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()"
    return -join ((1..16) | ForEach-Object { Get-Random -InputObject $Chars.ToCharArray() })
}


# Get the ID of the Microsoft Tenant
function Get-TenantID {
    param ([string]$Domain)

    try {
        $TenantInfo = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$Domain/v2.0/.well-known/openid-configuration" -Method Get
        $TenantID = $TenantInfo.issuer -replace "https://login.microsoftonline.com/", "" -replace "/v2.0", ""
        return $TenantID
    } catch {
        Write-Host "❌ Failed to retrieve Tenant ID for domain: $Domain" -ForegroundColor Red
        return $null
    }
}

function Update-AdminPassword {
    param (
        [string]$userId,
        [string]$newPassword
    )
    
    try {
        $passwordProfile = @{
            passwordProfile = @{
                forceChangePasswordNextSignIn = $false
                password = $newPassword
            }
        }
        Update-MgUser -UserId $userId -BodyParameter $passwordProfile
        Write-Host "Successfully updated admin password" -ForegroundColor Green
    } catch {
        Write-Host "Failed to update password: $_" -ForegroundColor Red
    }
}


# [Keep your existing functions: Get-HuduCredentials, Update-HuduPassword, Generate-SecurePassword, Get-TenantID, Connect-M365Tenant, Update-AdminPassword, Get-TenantPrimaryDomain]

# Main Execution
# Fetch companies dynamically from Hudu
$huduCompanies = Get-HuduCompanies
if (-not $huduCompanies) {
    Write-Host "No companies retrieved from Hudu. Exiting." -ForegroundColor Red
 
}

# Build tenants array dynamically
$tenants = @()
foreach ($company in $huduCompanies) {
    # Assuming you store ClientId and ClientSecret in Hudu company fields or elsewhere
    # Adjust these based on how you store Microsoft 365 app credentials
    $tenant = @{
        Domain      = "$($company.slug).onmicrosoft.com"  # Adjust based on actual domain storage
        CompanyId   = $company.id
        ClientId    = "your_client_id"  # Replace with logic to fetch from Hudu or another source
        ClientSecret = "your_client_secret"  # Replace with logic to fetch from Hudu or another source
    }
    $tenants += $tenant
}

# Process each tenant
foreach ($tenant in $tenants) {
    Write-Host "Processing tenant: $($tenant.Domain)" -ForegroundColor Cyan
    
    # Get Tenant ID
    $tenantId = Get-TenantID -Domain $tenant.Domain
    if (-not $tenantId) { continue }
    
    # Connect to Tenant
    $connected = Connect-M365Tenant -TenantId $tenantId -ClientId $tenant.ClientId -ClientSecret $tenant.ClientSecret
    if (-not $connected) { continue }
    
    # Get the actual published domain (optional)
    #$publishedDomain = Get-TenantPrimaryDomain -TenantId $tenantId
    #Write-Host "Published domain: $publishedDomain" -ForegroundColor Yellow
    
    # Get current credentials from Hudu
    $credentials = Get-HuduCredentials -companyId $tenant.CompanyId
    if (-not $credentials) { continue }
    
    # Generate new password
    $newPassword = Generate-SecurePassword
    
    # Update password in Microsoft
    Update-AdminPassword -userId $credentials.Username -newPassword $newPassword
    
    # Update password in Hudu
    Update-HuduPassword -passwordId $credentials.Id -newPassword $newPassword -username $credentials.Username
    
    # Disconnect from Graph
    Disconnect-MgGraph
    Write-Host "Completed processing $($tenant.Domain)" -ForegroundColor Green
    Write-Host "------------------------"
}