<# .SYNOPSIS Cria um novo usuário no Active Directory principal (Cliente) e habilita sua caixa de correio em um ambiente Exchange/AD secundário. .DESCRIPTION Este script foi desenvolvido como parte do projeto "Plataforma Unificada de Trabalho Digital". Ele orquestra a criação de contas de usuário em dois ambientes Active Directory distintos, suportando múltiplos métodos de entrada de dados e incluindo validações robustas para garantir a integridade dos dados e a conformidade com as políticas. O script é projetado para automação e não permite interação via console. .NOTES Autor: Gemini (Especialista NGINX & Automação) Data: 14 de outubro de 2025 Versão: 1.3 - Removida interatividade. O script agora falha imediatamente se executado sem parâmetros, exibindo apenas a ajuda. Contexto: Projeto Plataforma Unificada de Trabalho Digital #> [CmdletBinding(DefaultParameterSetName = 'SingleUser')] param( # --- Parâmetros para criação de usuário único --- [Parameter(Mandatory = $true, ParameterSetName = 'SingleUser', HelpMessage = 'Nome de logon (pré-Windows 2000)')] [string]$SamAccountName, [Parameter(Mandatory = $true, ParameterSetName = 'SingleUser', HelpMessage = 'Primeiro nome')] [string]$GivenName, [Parameter(Mandatory = $true, ParameterSetName = 'SingleUser', HelpMessage = 'Sobrenome')] [string]$Surname, [Parameter(Mandatory = $true, ParameterSetName = 'SingleUser', HelpMessage = 'Nome completo para exibição')] [string]$Name, [Parameter(Mandatory = $true, ParameterSetName = 'SingleUser', HelpMessage = 'UPN / Logon de e-mail')] [string]$UserPrincipalName, [Parameter(Mandatory = $true, ParameterSetName = 'SingleUser', HelpMessage = 'OU de destino. Ex: "OU=Usuarios,DC=cliente,DC=local"')] [string]$Path, # --- Parâmetros para importação em massa --- [Parameter(Mandatory = $true, ParameterSetName = 'CsvImport', HelpMessage = 'Caminho do arquivo .CSV para importação')] [string]$CsvPath, [Parameter(Mandatory = $true, ParameterSetName = 'DbImport', HelpMessage = 'Indica que a fonte de dados é um banco de dados')] [switch]$FromDatabase, # --- Parâmetros de Conexão e Autenticação --- [Parameter(Mandatory = $true, Position = 0, HelpMessage = 'IP ou FQDN do DC do cliente')] [string]$ClientADServer, [Parameter(Mandatory = $true, Position = 1, HelpMessage = 'Credencial para o AD do cliente')] [pscredential]$ClientADCredential, [Parameter(Mandatory = $true, Position = 2, HelpMessage = 'IP ou FQDN do DC do Exchange')] [string]$ExchangeADServer, [Parameter(Mandatory = $true, Position = 3, HelpMessage = 'Credencial para o AD do Exchange')] [pscredential]$ExchangeADCredential, # --- Parâmetros de Logging --- [Parameter(Mandatory = $false, HelpMessage = 'String de conexão do banco de dados de log')] [string]$DatabaseConnectionString, [Parameter(Mandatory = $false, HelpMessage = 'Caminho do arquivo de texto para log de fallback')] [string]$LogFilePath = ".\New-UnifiedADUser-Log-$(Get-Date -Format 'yyyy-MM-dd').txt" ) # --- FUNÇÕES AUXILIARES --- function Write-Log { param( [Parameter(Mandatory = $true)] [string]$Message, [Parameter(Mandatory = $true)] [ValidateSet('INFO', 'WARN', 'ERROR')] [string]$Level, [Parameter(Mandatory = $false)] [string]$TargetADServer ) $logEntry = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - [$Level] - $Message" $scriptUser = $env:USERNAME try { if (-not [string]::IsNullOrEmpty($DatabaseConnectionString)) { # [PLACEHOLDER] Lógica de log no banco de dados. Write-Verbose "Log enviado para o banco de dados." } } catch { $dbErrorMessage = "Falha ao gravar no banco de dados: $($_.Exception.Message)" "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - [ERROR] - $dbErrorMessage" | Out-File -FilePath $LogFilePath -Append } $logEntry | Out-File -FilePath $LogFilePath -Append if (-not [string]::IsNullOrEmpty($TargetADServer)) { try { $eventMessage = "Script 'New-UnifiedADUser.ps1' executado por '$scriptUser'.`nDetalhes: $Message" $eventLevel = switch ($Level) { 'INFO' { 'Information' } 'WARN' { 'Warning' } 'ERROR' { 'Error' } } Invoke-Command -ComputerName $TargetADServer -ScriptBlock { param($eventMessage, $eventLevel) $logSource = "Provisionamento de Usuários AD" if (-not ([System.Diagnostics.EventLog]::SourceExists($logSource))) { New-EventLog -LogName 'Application' -Source $logSource } Write-EventLog -LogName 'Application' -Source $logSource -EventId 1001 -EntryType $eventLevel -Message $eventMessage } -ArgumentList $eventMessage, $eventLevel Write-Verbose "Log de evento escrito em '$TargetADServer'." } catch { $eventErrorMessage = "Falha ao escrever no Event Log de '$TargetADServer': $($_.Exception.Message)" "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - [ERROR] - $eventErrorMessage" | Out-File -FilePath $LogFilePath -Append } } } function Show-Usage { Write-Host @" ERRO: O script foi chamado sem os parâmetros necessários ou com um método de entrada de dados inválido. Este script cria usuários no AD do cliente e no AD do Exchange e deve ser chamado com todos os parâmetros requeridos. MÉTODOS DE USO: 1. Criação de Usuário Único (parâmetros diretos): Exemplo: .\New-UnifiedADUser.ps1 -SamAccountName 'joao.silva' -GivenName 'João' -Surname 'Silva' -Name 'João da Silva' -UserPrincipalName 'joao.silva@cliente.com.br' -Path 'OU=Usuarios,DC=local' -ClientADServer '...' -ClientADCredential (Get-Credential) -ExchangeADServer '...' -ExchangeADCredential (Get-Credential) 2. Criação em Massa via CSV (usando o parâmetro -CsvPath): Exemplo: .\New-UnifiedADUser.ps1 -CsvPath 'C:\temp\usuarios.csv' -ClientADServer '...' -ClientADCredential (Get-Credential) -ExchangeADServer '...' -ExchangeADCredential (Get-Credential) 3. Criação via Banco de Dados (usando o parâmetro -FromDatabase): (Funcionalidade a ser implementada) Exemplo: .\New-UnifiedADUser.ps1 -FromDatabase -ClientADServer '...' -ClientADCredential (Get-Credential) -ExchangeADServer '...' -ExchangeADCredential (Get-Credential) "@ } # --- LÓGICA PRINCIPAL --- # --- VALIDAÇÃO: Garante que o script não seja executado de forma interativa --- if ($PSBoundParameters.Count -eq 0) { Show-Usage exit 1 # Encerra o script imediatamente } # --- FIM DA VALIDAÇÃO --- try { Import-Module ActiveDirectory -ErrorAction Stop } catch { Write-Log -Level 'ERROR' -Message "Falha ao importar o módulo ActiveDirectory. Verifique se as Ferramentas de Administração de Servidor Remoto (RSAT) estão instaladas." exit 1 } Write-Host "Coletando informações da floresta de AD para validação..." try { $adForest = Get-ADForest -Server $ClientADServer -Credential $ClientADCredential [array]$validUPNSuffixes = $adForest.UPNSuffixes + $adForest.RootDomain Write-Log -Level 'INFO' -Message "Sufixos de UPN válidos carregados: $($validUPNSuffixes -join ', ')" } catch { Write-Log -Level 'ERROR' -Message "Não foi possível obter informações da floresta do AD. Verifique a conexão e as credenciais. Erro: $($_.Exception.Message)" exit 1 } $usersToProcess = @() switch ($PSCmdlet.ParameterSetName) { 'SingleUser' { $usersToProcess += [PSCustomObject]@{ SamAccountName = $SamAccountName GivenName = $GivenName Surname = $Surname Name = $Name UserPrincipalName = $UserPrincipalName Path = $Path } break } 'CsvImport' { try { $usersToProcess = Import-Csv -Path $CsvPath -ErrorAction Stop Write-Log -Level 'INFO' -Message "Arquivo CSV '$CsvPath' carregado com $($usersToProcess.Count) registros." } catch { Write-Log -Level 'ERROR' -Message "Não foi possível ler o arquivo CSV em '$CsvPath'. Erro: $($_.Exception.Message)" exit 1 } break } 'DbImport' { Write-Log -Level 'WARN' -Message "O método de importação via banco de dados (-FromDatabase) ainda não foi implementado." exit 1 break } default { Show-Usage exit 1 } } foreach ($user in $usersToProcess) { $u_sam = $user.SamAccountName Write-Host "Iniciando processamento para o usuário: $u_sam" Write-Log -Level 'INFO' -Message "Iniciando provisionamento para o usuário '$u_sam'." # --- BLOCO DE VALIDAÇÕES --- $validationFailed = $false if ([string]::IsNullOrWhiteSpace($u_sam) -or [string]::IsNullOrWhiteSpace($user.UserPrincipalName) -or [string]::IsNullOrWhiteSpace($user.Path)) { Write-Log -Level 'ERROR' -Message "USUÁRIO IGNORADO: Dados essenciais (SamAccountName, UserPrincipalName, Path) estão faltando para o usuário '$u_sam'." $validationFailed = $true } if (-not $validationFailed) { if ($u_sam.Length -gt 20) { Write-Log -Level 'ERROR' -Message "USUÁRIO IGNORADO: O SamAccountName '$u_sam' excede o limite de 20 caracteres." $validationFailed = $true } if (Get-ADUser -Filter "SamAccountName -eq '$u_sam'" -Server $ClientADServer -Credential $ClientADCredential) { Write-Log -Level 'ERROR' -Message "USUÁRIO IGNORADO: O SamAccountName '$u_sam' já existe no Active Directory." $validationFailed = $true } } if (-not $validationFailed) { if (-not (Get-ADOrganizationalUnit -Filter "DistinguishedName -eq '$($user.Path)'" -Server $ClientADServer -Credential $ClientADCredential)) { Write-Log -Level 'ERROR' -Message "USUÁRIO IGNORADO: A OU '$($user.Path)' não foi encontrada no Active Directory." $validationFailed = $true } } if (-not $validationFailed) { $upnSuffix = ($user.UserPrincipalName).Split('@')[1] if ($upnSuffix -eq 'exch.local') { Write-Log -Level 'ERROR' -Message "USUÁRIO IGNORADO: O UPN '$($user.UserPrincipalName)' usa o sufixo proibido 'exch.local'." $validationFailed = $true } elseif ($validUPNSuffixes -notcontains $upnSuffix) { Write-Log -Level 'ERROR' -Message "USUÁRIO IGNORADO: O sufixo de UPN '@$upnSuffix' não é válido para esta floresta." $validationFailed = $true } } if ($validationFailed) { Write-Host " [ERRO] Falha na validação. Verifique o log para detalhes." -ForegroundColor Red continue } # --- FIM DO BLOCO DE VALIDAÇÕES --- $clientADSuccess = $false try { $tempPassword = -join ((65..90) + (97..122) + (48..57) | Get-Random -Count 16 | ForEach-Object { [char]$_ }) $securePassword = ConvertTo-SecureString $tempPassword -AsPlainText -Force $userParams = @{ SamAccountName = $u_sam GivenName = $user.GivenName Surname = $user.Surname Name = $user.Name UserPrincipalName = $user.UserPrincipalName Path = $user.Path AccountPassword = $securePassword Enabled = $true ChangePasswordAtLogon = $true Server = $ClientADServer Credential = $ClientADCredential } Write-Log -Level 'INFO' -Message "Tentando criar a conta '$u_sam' no AD do Cliente em '$ClientADServer'." -TargetADServer $ClientADServer New-ADUser @userParams -ErrorAction Stop Write-Log -Level 'INFO' -Message "SUCESSO: Conta '$u_sam' criada no AD do Cliente. Senha temporária gerada." -TargetADServer $ClientADServer Write-Host " [OK] Conta criada no AD do Cliente." -ForegroundColor Green Write-Log -Level 'INFO' -Message "Senha temporária para '$u_sam': $tempPassword" $clientADSuccess = $true } catch { $errorMessage = "FALHA ao criar a conta '$u_sam' no AD do Cliente. Erro: $($_.Exception.Message -replace "`r`n"," ")" Write-Log -Level 'ERROR' -Message $errorMessage -TargetADServer $ClientADServer Write-Host " [ERRO] Falha ao criar no AD do Cliente." -ForegroundColor Red continue } if ($clientADSuccess) { try { Start-Sleep -Seconds 5 Write-Log -Level 'INFO' -Message "Tentando habilitar a mailbox para '$u_sam' no AD do Exchange em '$ExchangeADServer'." -TargetADServer $ExchangeADServer Enable-Mailbox -Identity $u_sam -DomainController $ExchangeADServer -Credential $ExchangeADCredential -ErrorAction Stop Write-Log -Level 'INFO' -Message "SUCESSO: Mailbox para '$u_sam' habilitada no ambiente Exchange." -TargetADServer $ExchangeADServer Write-Host " [OK] Mailbox habilitada no Exchange." -ForegroundColor Green Write-Log -Level 'INFO' -Message "PROVISIONAMENTO COMPLETO para o usuário '$u_sam'." } catch { $errorMessage = "FALHA PARCIAL: A conta '$u_sam' foi criada no AD do Cliente, mas falhou ao habilitar a mailbox no Exchange. Erro: $($_.Exception.Message -replace "`r`n"," ")" Write-Log -Level 'ERROR' -Message $errorMessage -TargetADServer $ExchangeADServer Write-Host " [ERRO] Falha ao habilitar a mailbox no Exchange." -ForegroundColor Red } } } Write-Host "Processamento concluído."