param( [string]$ProjectRoot = "D:\laragon\www\MailPolicy", [string]$PhpPath = "php", [switch]$UseQueueTransport = $true, [string]$QueueConnection = "database", [string]$QueueName = "exchange-sync", [switch]$InstallWorker, [string]$ServiceName = "MailPolicySyncWorker", [string]$ServiceUser = "", [string]$ServicePassword = "", [switch]$StartWorker, [switch]$SkipMigrate, [switch]$SkipOptimizeClear ) $ErrorActionPreference = "Stop" function Write-Step { param([string]$Message) Write-Host "" Write-Host "==> $Message" } function Invoke-PhpArtisan { param( [string]$PhpExe, [string]$Root, [string[]]$Arguments ) & $PhpExe (Join-Path $Root "artisan") @Arguments if ($LASTEXITCODE -ne 0) { throw "Artisan command failed: $($Arguments -join ' ')" } } function Set-EnvValue { param( [string]$EnvPath, [string]$Key, [string]$Value ) if (!(Test-Path $EnvPath)) { throw ".env file not found: $EnvPath" } $escapedValue = $Value.Replace('\', '\\') $lines = Get-Content $EnvPath $matched = $false for ($i = 0; $i -lt $lines.Count; $i++) { if ($lines[$i] -match "^\s*#?\s*$([regex]::Escape($Key))=") { $lines[$i] = "$Key=$escapedValue" $matched = $true } } if (-not $matched) { $lines += "$Key=$escapedValue" } Set-Content -Path $EnvPath -Value $lines } if (!(Test-Path $ProjectRoot)) { throw "Project root not found: $ProjectRoot" } $artisan = Join-Path $ProjectRoot "artisan" if (!(Test-Path $artisan)) { throw "artisan not found at: $artisan" } $envPath = Join-Path $ProjectRoot ".env" $storageRoot = Join-Path $ProjectRoot "storage\app\mailpolicy" $storageFolders = @( (Join-Path $storageRoot "lists"), (Join-Path $storageRoot "scripts"), (Join-Path $storageRoot "reports"), (Join-Path $storageRoot "logs") ) Write-Step "Ensuring MailPolicy storage directories exist" foreach ($folder in $storageFolders) { if (!(Test-Path $folder)) { New-Item -ItemType Directory -Path $folder -Force | Out-Null } Write-Host $folder } Write-Step "Writing required queue and storage values to .env" Set-EnvValue -EnvPath $envPath -Key "QUEUE_CONNECTION" -Value $QueueConnection Set-EnvValue -EnvPath $envPath -Key "EXCHANGE_SYNC_QUEUE" -Value $QueueName Set-EnvValue -EnvPath $envPath -Key "WHITELIST_STORAGE_DIRECTORY" -Value "app/mailpolicy" Set-EnvValue -EnvPath $envPath -Key "WHITELIST_LIST_DIRECTORY" -Value "lists" Set-EnvValue -EnvPath $envPath -Key "WHITELIST_SCRIPT_DIRECTORY" -Value "scripts" Set-EnvValue -EnvPath $envPath -Key "WHITELIST_REPORT_DIRECTORY" -Value "reports" Set-EnvValue -EnvPath $envPath -Key "WHITELIST_LOG_DIRECTORY" -Value "logs" Set-EnvValue -EnvPath $envPath -Key "WHITELIST_DOMAIN_FILE" -Value "AllowedDomains.txt" Set-EnvValue -EnvPath $envPath -Key "WHITELIST_SENDER_FILE" -Value "AllowedSenders.txt" Set-EnvValue -EnvPath $envPath -Key "WHITELIST_DOMAIN_SCRIPT_FILE" -Value "AllowedDomainSync.ps1" Set-EnvValue -EnvPath $envPath -Key "WHITELIST_SENDER_SCRIPT_FILE" -Value "AllowedSendersSync.ps1" if ($UseQueueTransport) { Set-EnvValue -EnvPath $envPath -Key "EXCHANGE_SYNC_TRANSPORT" -Value "queue" } else { Set-EnvValue -EnvPath $envPath -Key "EXCHANGE_SYNC_TRANSPORT" -Value "direct" } if (-not $SkipMigrate) { Write-Step "Running migrations" Invoke-PhpArtisan -PhpExe $PhpPath -Root $ProjectRoot -Arguments @("migrate", "--force") } if (-not $SkipOptimizeClear) { Write-Step "Clearing Laravel cached config" Invoke-PhpArtisan -PhpExe $PhpPath -Root $ProjectRoot -Arguments @("optimize:clear") } if ($InstallWorker) { Write-Step "Installing or updating NSSM sync worker" $installer = Join-Path $ProjectRoot "scripts\windows\install-mailpolicy-sync-worker.ps1" if (!(Test-Path $installer)) { throw "Worker installer not found: $installer" } $workerArgs = @( "-ExecutionPolicy", "Bypass", "-File", $installer, "-ProjectRoot", $ProjectRoot, "-PhpPath", $PhpPath, "-QueueConnection", $QueueConnection, "-QueueName", $QueueName, "-ServiceName", $ServiceName ) if ($ServiceUser -ne "") { $workerArgs += @("-ServiceUser", $ServiceUser, "-ServicePassword", $ServicePassword) } if ($StartWorker) { $workerArgs += "-StartService" } & powershell.exe @workerArgs if ($LASTEXITCODE -ne 0) { throw "Worker install script failed." } } Write-Step "Bootstrap complete" Write-Host "Provide these files if not already present:" Write-Host (Join-Path $storageRoot "lists\Initial_AllowedDomains.txt") Write-Host (Join-Path $storageRoot "lists\Initial_AllowedSenders.txt") Write-Host (Join-Path $storageRoot "lists\Initial_BlockedMailDomains.txt") Write-Host (Join-Path $storageRoot "scripts\AllowedDomainSync.ps1") Write-Host (Join-Path $storageRoot "scripts\AllowedSendersSync.ps1")