314 lines
14 KiB
PowerShell
314 lines
14 KiB
PowerShell
<#
|
|
.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." |