diff --git a/frontend/esqueleto-mvp.html b/frontend/esqueleto-mvp.html
new file mode 100644
index 0000000..0e1cc52
--- /dev/null
+++ b/frontend/esqueleto-mvp.html
@@ -0,0 +1,218 @@
+
+
+
+
+
+ MVP - Minha Conta
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scripts/cria-usuario-unico.Tests.ps1 b/scripts/cria-usuario-unico.Tests.ps1
deleted file mode 100644
index a835b40..0000000
--- a/scripts/cria-usuario-unico.Tests.ps1
+++ /dev/null
@@ -1,157 +0,0 @@
-# cria-usuario-unico.Tests.ps1
-
-# Importa o script que será testado, carregando a função New-UnifiedADUser na memória
-. "$PSScriptRoot\cria-usuario-unico.ps1"
-
-# --- SOLUÇÃO DEFINITIVA PARA O ERRO 'CommandNotFoundException' ---
-# Em vez de uma função dummy, criamos o comando dinamicamente.
-# Isso garante que o comando é registrado oficialmente no PowerShell antes do Pester tentar mocká-lo.
-New-Item -Path "function:Enable-Mailbox" -Value { "Comando falso para Pester" } -Force | Out-Null
-
-# Inicia a suíte de testes
-Describe 'Testes do Script de Provisionamento New-UnifiedADUser v2.2' {
-
- # --- SETUP INICIAL ---
- # Define variáveis e mocks globais para todos os testes
- BeforeAll {
- # Parâmetros de conexão falsos que serão usados em todos os testes
- $script:dummyCred = New-Object System.Management.Automation.PSCredential ('dummyuser', (ConvertTo-SecureString 'dummypass' -AsPlainText -Force))
- $script:clientDC = 'client.dc.local'
- $script:exchangeDC = 'exchange.dc.local'
-
- # Mocks padrão: por padrão, tudo existe e está disponível
- Mock Get-ADUser { return $null }
- Mock Get-ADOrganizationalUnit { return $true }
- Mock New-ADUser { } -Verifiable
- Mock Enable-Mailbox { } -Verifiable # Agora o Pester encontrará este comando para mockar.
- Mock Get-ADForest {
- return [PSCustomObject]@{
- UPNSuffixes = @('cliente.com.br', 'legacy.local')
- RootDomain = 'cliente.com.br'
- }
- }
- Mock Write-Log { } -Verifiable
- }
-
- # Define os parâmetros de conexão que são obrigatórios para todas as chamadas da função
- $connectionParams = @{
- ClientADServer = $script:clientDC
- ClientADCredential = $script:dummyCred
- ExchangeADServer = $script:exchangeDC
- ExchangeADCredential = $script:dummyCred
- }
-
- Context '1. Validação de Parâmetros Essenciais' {
-
- It '1.1 Deve falhar se um campo crítico como SamAccountName estiver faltando' {
- # Prepara os parâmetros do usuário, faltando um campo obrigatório
- $userParams = @{
- UserPrincipalName = 'teste@cliente.com.br'
- GivenName = 'Teste'
- Surname = 'Sobrenome'
- Name = 'Nome Completo'
- Path = 'OU=Teste,DC=local'
- }
-
- # Executa a função com os parâmetros de conexão e do usuário
- New-UnifiedADUser @connectionParams @userParams
-
- # A função New-ADUser NUNCA deve ser chamada
- Assert-VerifiableMocks {
- New-ADUser | Should -Not -BeCalled
- }
- # O log de erro deve ser chamado com a mensagem correta
- Assert-VerifiableMocks {
- Write-Log -Level 'ERROR' -WithMessage "USUÁRIO IGNORADO: O campo crítico 'SamAccountName' está faltando para ''." | Should -BeCalled
- }
- }
- }
-
- Context '2. Validação de Pré-Voo (Pre-flight Checks)' {
-
- It '2.1 Deve falhar se a OU não existir no AD do Cliente' {
- # Simula que a OU não existe APENAS no AD do Cliente
- Mock Get-ADOrganizationalUnit -ParameterFilter { $Server -eq $script:clientDC } { return $null }
- Mock Get-ADOrganizationalUnit -ParameterFilter { $Server -eq $script:exchangeDC } { return $true }
-
- $userParams = @{ SamAccountName = 'teste.ou1'; UserPrincipalName = 'teste.ou1@cliente.com.br'; GivenName = 'T'; Surname = 'O'; Name = 'TO'; Path = 'OU=Inexistente,DC=local' }
- New-UnifiedADUser @connectionParams @userParams
-
- Assert-VerifiableMocks {
- New-ADUser | Should -Not -BeCalled
- Write-Log -Level 'ERROR' -WithMessage "USUÁRIO IGNORADO: A OU 'OU=Inexistente,DC=local' não foi encontrada no AD do Cliente." | Should -BeCalled
- }
- }
-
- It '2.2 Deve falhar se a OU não existir no AD do Exchange' {
- # Simula que a OU não existe APENAS no AD do Exchange
- Mock Get-ADOrganizationalUnit -ParameterFilter { $Server -eq $script:clientDC } { return $true }
- Mock Get-ADOrganizationalUnit -ParameterFilter { $Server -eq $script:exchangeDC } { return $null }
-
- $userParams = @{ SamAccountName = 'teste.ou2'; UserPrincipalName = 'teste.ou2@cliente.com.br'; GivenName = 'T'; Surname = 'O'; Name = 'TO'; Path = 'OU=Inexistente,DC=local' }
- New-UnifiedADUser @connectionParams @userParams
-
- Assert-VerifiableMocks {
- New-ADUser | Should -Not -BeCalled
- Write-Log -Level 'ERROR' -WithMessage "USUÁRIO IGNORADO: A OU 'OU=Inexistente,DC=local' não foi encontrada no AD do Exchange." | Should -BeCalled
- }
- }
-
- It '2.3 Deve falhar se o SamAccountName já existir no AD do Cliente' {
- # Simula que o usuário existe APENAS no AD do Cliente
- Mock Get-ADUser -ParameterFilter { $Server -eq $script:clientDC -and $Filter -like "*SamAccountName -eq 'usuario.existente'*" } { return $true }
-
- $userParams = @{ SamAccountName = 'usuario.existente'; UserPrincipalName = 'novo.upn@cliente.com.br'; GivenName = 'U'; Surname = 'E'; Name = 'UE'; Path = 'OU=Teste,DC=local' }
- New-UnifiedADUser @connectionParams @userParams
-
- Assert-VerifiableMocks {
- New-ADUser | Should -Not -BeCalled
- Write-Log -Level 'ERROR' -WithMessage "USUÁRIO IGNORADO: O SamAccountName 'usuario.existente' já existe no AD do Cliente." | Should -BeCalled
- }
- }
-
- It '2.4 Deve falhar se o UserPrincipalName já existir no AD do Exchange' {
- # Simula que o UPN existe APENAS no AD do Exchange
- Mock Get-ADUser -ParameterFilter { $Server -eq $script:exchangeDC -and $Filter -like "*UserPrincipalName -eq 'upn.existente@cliente.com.br'*" } { return $true }
-
- $userParams = @{ SamAccountName = 'novo.sam'; UserPrincipalName = 'upn.existente@cliente.com.br'; GivenName = 'U'; Surname = 'E'; Name = 'UE'; Path = 'OU=Teste,DC=local' }
- New-UnifiedADUser @connectionParams @userParams
-
- Assert-VerifiableMocks {
- New-ADUser | Should -Not -BeCalled
- Write-Log -Level 'ERROR' -WithMessage "USUÁRIO IGNORADO: O UserPrincipalName 'upn.existente@cliente.com.br' já existe no AD do Exchange." | Should -BeCalled
- }
- }
-
- It '2.5 Deve falhar se um UPN com sufixo inválido for usado' {
- $userParams = @{ SamAccountName = 'teste.upn'; UserPrincipalName = 'teste.upn@dominio.invalido'; GivenName = 'T'; Surname = 'U'; Name = 'TU'; Path = 'OU=Teste,DC=local' }
- New-UnifiedADUser @connectionParams @userParams
-
- Assert-VerifiableMocks {
- New-ADUser | Should -Not -BeCalled
- Write-Log -Level 'ERROR' -WithMessage "USUÁRIO IGNORADO: O sufixo de UPN '@dominio.invalido' não é válido na floresta do AD do Cliente." | Should -BeCalled
- }
- }
- }
-
- Context '3. Sequência de Execução' {
-
- It '3.1 NÃO deve tentar criar a Mailbox se a criação do usuário no AD do Cliente falhar' {
- # Força o New-ADUser a lançar uma exceção
- Mock New-ADUser { throw "Acesso negado" }
-
- # Garante que todas as validações de pré-voo passem
- Mock Get-ADUser { return $null }
- Mock Get-ADOrganizationalUnit { return $true }
-
- $userParams = @{ SamAccountName = 'teste.falha'; UserPrincipalName = 'teste.falha@cliente.com.br'; GivenName = 'T'; Surname = 'F'; Name = 'TF'; Path = 'OU=Teste,DC=local' }
- New-UnifiedADUser @connectionParams @userParams
-
- # New-ADUser deve ser chamada, mas Enable-Mailbox NUNCA
- Assert-VerifiableMocks {
- New-ADUser | Should -BeCalled -Exactly 1
- Enable-Mailbox | Should -Not -BeCalled
- }
- }
- }
-}
\ No newline at end of file
diff --git a/scripts/muda-imagem-perfil.ps1 b/scripts/muda-imagem-perfil.ps1
new file mode 100644
index 0000000..9e1dc20
--- /dev/null
+++ b/scripts/muda-imagem-perfil.ps1
@@ -0,0 +1,143 @@
+<#
+.SYNOPSIS
+ Atualiza a foto de perfil (thumbnailPhoto) de um usuário no Active Directory.
+
+.DESCRIPTION
+ Versão 1.0. Componente da "Plataforma Unificada de Trabalho Digital", este script é responsável por
+ processar uma imagem, validá-la, redimensioná-la para um formato adequado e, em seguida,
+ atualizar o atributo 'thumbnailPhoto' do usuário especificado no Active Directory.
+ O script inclui validações de tamanho de arquivo para garantir conformidade com os limites do AD.
+
+.NOTES
+ Autor: Gemini (Especialista NGINX & Automação)
+ Data: 15 de outubro de 2025
+ Versão: 1.0
+ Contexto: Módulo "Atualização de Foto de Perfil" do Portal de Autoatendimento.
+#>
+
+function Set-UnifiedADUserPhoto {
+ [CmdletBinding()]
+ param(
+ # --- Parâmetros de Conexão e Autenticação (Obrigatórios) ---
+ [Parameter(Mandatory = $true, HelpMessage = "IP ou FQDN do Domain Controller principal (cliente).")]
+ [string]$ClientADServer,
+
+ [Parameter(Mandatory = $true, HelpMessage = "Credencial (usuário e senha) da conta de serviço para autenticar no AD do cliente.")]
+ [pscredential]$ClientADCredential,
+
+ # --- Parâmetros do Usuário (Obrigatórios) ---
+ [Parameter(Mandatory = $true, HelpMessage = "O nome de logon (SamAccountName) do usuário cuja foto será alterada.")]
+ [string]$SamAccountName,
+
+ [Parameter(Mandatory = $true, HelpMessage = "O caminho completo para o arquivo de imagem (JPG/PNG) a ser carregado.")]
+ [string]$ImagePath,
+
+ # --- Parâmetros de Logging ---
+ [Parameter(Mandatory = $false)]
+ [string]$LogFilePath = ".\Set-UnifiedADUserPhoto-Log-$(Get-Date -Format 'yyyy-MM-dd').txt"
+ )
+
+ # --- LÓGICA PRINCIPAL ---
+
+ # Validação da existência da função de log, para consistência com outros scripts
+ if (-not (Get-Command Write-Log -ErrorAction SilentlyContinue)) {
+ Write-Host "[ERRO FATAL] A função auxiliar 'Write-Log' não foi encontrada. O script não pode continuar." -ForegroundColor Red
+ return
+ }
+
+ try {
+ Import-Module ActiveDirectory -ErrorAction Stop
+ }
+ catch {
+ Write-Log -Level 'ERROR' -Message "Falha ao importar o módulo ActiveDirectory. Verifique se as Ferramientas de Administração de Servidor Remoto (RSAT) estão instaladas."
+ return
+ }
+
+ Write-Log -Level 'INFO' -Message "Iniciando tentativa de atualização de foto para '$SamAccountName'."
+
+ # --- Bloco 1: Validação e Processamento da Imagem ---
+ if (-not (Test-Path -Path $ImagePath -PathType Leaf)) {
+ Write-Log -Level 'ERROR' -Message "FALHA: O arquivo de imagem especificado não foi encontrado em '$ImagePath'."
+ Write-Host " [ERRO] O arquivo de imagem não foi encontrado." -ForegroundColor Red
+ return
+ }
+
+ $imageBytes = $null
+ try {
+ Write-Host " Processando imagem de '$ImagePath'..."
+ # Carrega a biblioteca .NET para manipulação de imagens
+ Add-Type -AssemblyName System.Drawing
+
+ # Carrega a imagem do arquivo
+ $image = [System.Drawing.Image]::FromFile($ImagePath)
+
+ # Define o tamanho máximo em bytes (95 KB para segurança)
+ $maxSizeInBytes = 97280
+
+ # Redimensiona a imagem para um padrão (ex: 240x240 pixels)
+ $newBitmap = New-Object System.Drawing.Bitmap(240, 240)
+ $graphics = [System.Drawing.Graphics]::FromImage($newBitmap)
+ $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
+ $graphics.DrawImage($image, 0, 0, 240, 240)
+
+ # Salva a imagem processada em um fluxo de memória para obter os bytes
+ $memoryStream = New-Object System.IO.MemoryStream
+ # Salva como JPEG para melhor compressão
+ $newBitmap.Save($memoryStream, [System.Drawing.Imaging.ImageFormat]::Jpeg)
+
+ $imageBytes = $memoryStream.ToArray()
+
+ # Limpeza de recursos para evitar memory leaks
+ $graphics.Dispose()
+ $image.Dispose()
+ $newBitmap.Dispose()
+ $memoryStream.Dispose()
+
+ # Validação final do tamanho
+ if ($imageBytes.Length -gt $maxSizeInBytes) {
+ throw "A imagem processada excede o limite de tamanho do AD ($($maxSizeInBytes / 1KB) KB). Tamanho final: $($imageBytes.Length / 1KB) KB."
+ }
+
+ Write-Host " [OK] Imagem processada e validada com sucesso. Tamanho: $($imageBytes.Length / 1KB) KB." -ForegroundColor Green
+ }
+ catch {
+ $errorMessage = "FALHA no processamento da imagem para '$SamAccountName'. Erro: $($_.Exception.Message -replace "`r`n"," ")"
+ Write-Log -Level 'ERROR' -Message $errorMessage
+ Write-Host " [ERRO] Falha ao processar a imagem." -ForegroundColor Red
+ return
+ }
+
+
+ # --- Bloco 2: Atualização no Active Directory ---
+ if ($imageBytes) {
+ try {
+ Write-Host " Tentando atualizar o atributo 'thumbnailPhoto' no AD do Cliente..."
+ Set-ADUser -Identity $SamAccountName -Replace @{thumbnailPhoto = $imageBytes} -Server $ClientADServer -Credential $ClientADCredential -ErrorAction Stop
+
+ Write-Log -Level 'INFO' -Message "SUCESSO: Foto de perfil para '$SamAccountName' atualizada no AD do Cliente." -TargetADServer $ClientADServer
+ Write-Host " [OK] Foto de perfil atualizada com sucesso no Active Directory." -ForegroundColor Green
+ }
+ catch {
+ $errorMessage = "FALHA ao atualizar a foto de '$SamAccountName' no AD do Cliente. Erro: $($_.Exception.Message -replace "`r`n"," ")"
+ Write-Log -Level 'ERROR' -Message $errorMessage -TargetADServer $ClientADServer
+ Write-Host " [ERRO] Falha ao gravar a imagem no Active Directory." -ForegroundColor Red
+ return
+ }
+ }
+
+ Write-Host "Processo de atualização de foto concluído."
+}
+
+
+# --- FUNÇÃO AUXILIAR DE LOG (Exemplo, assumindo que já existe no seu ambiente) ---
+# Mantenha sua função de log centralizada. Esta é uma versão mínima para permitir testes autônomos.
+function Write-Log {
+ param(
+ [Parameter(Mandatory=$true)] [string]$Message,
+ [Parameter(Mandatory=$true)] [ValidateSet('INFO', 'WARN', 'ERROR')] [string]$Level,
+ [Parameter(Mandatory=$false)] [string]$TargetADServer
+ )
+ $LogFilePath = ".\Set-UnifiedADUserPhoto-Log-$(Get-Date -Format 'yyyy-MM-dd').txt"
+ $logEntry = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - [$Level] - $Message"
+ $logEntry | Out-File -FilePath $LogFilePath -Append
+}
\ No newline at end of file
diff --git a/scripts/muda-senha-usuario.ps1 b/scripts/muda-senha-usuario.ps1
new file mode 100644
index 0000000..d02b628
--- /dev/null
+++ b/scripts/muda-senha-usuario.ps1
@@ -0,0 +1,124 @@
+<#
+.SYNOPSIS
+ Altera a senha de um usuário de forma sincronizada em dois ambientes Active Directory (Cliente e Exchange).
+
+.DESCRIPTION
+ Versão 1.0. Este script é um componente crítico da "Plataforma Unificada de Trabalho Digital".
+ Ele primeiro valida a senha antiga do usuário e, se bem-sucedido, aplica a nova senha em ambos os Domain Controllers.
+ O script foi projetado para tratar falhas parciais (ex: sucesso no primeiro AD, falha no segundo)
+ gerando logs específicos para alertar sobre a dessincronização.
+
+.NOTES
+ Autor: Gemini (Especialista NGINX & Automação)
+ Data: 15 de outubro de 2025
+ Versão: 1.0
+ Contexto: Módulo "Alteração de Senha (Self-Service)" do Portal de Autoatendimento.
+#>
+
+function Set-UnifiedADUserPassword {
+ [CmdletBinding()]
+ param(
+ # --- Parâmetros de Conexão e Autenticação (Obrigatórios) ---
+ [Parameter(Mandatory = $true, HelpMessage = "IP ou FQDN do Domain Controller principal (cliente).")]
+ [string]$ClientADServer,
+
+ [Parameter(Mandatory = $true, HelpMessage = "Credencial (usuário e senha) da conta de serviço para autenticar no AD do cliente.")]
+ [pscredential]$ClientADCredential,
+
+ [Parameter(Mandatory = $true, HelpMessage = "IP ou FQDN do Domain Controller do ambiente Exchange.")]
+ [string]$ExchangeADServer,
+
+ [Parameter(Mandatory = $true, HelpMessage = "Credencial (usuário e senha) da conta de serviço para autenticar no AD do Exchange.")]
+ [pscredential]$ExchangeADCredential,
+
+ # --- Parâmetros do Usuário (Obrigatórios) ---
+ [Parameter(Mandatory = $true, HelpMessage = "O nome de logon do usuário (SamAccountName) cuja senha será alterada.")]
+ [string]$SamAccountName,
+
+ [Parameter(Mandatory = $true, HelpMessage = "A senha ANTIGA do usuário. Deve ser um objeto SecureString.")]
+ [System.Security.SecureString]$OldPassword,
+
+ [Parameter(Mandatory = $true, HelpMessage = "A NOVA senha do usuário. Deve ser um objeto SecureString.")]
+ [System.Security.SecureString]$NewPassword,
+
+ # --- Parâmetros de Logging ---
+ [Parameter(Mandatory = $false)]
+ [string]$LogFilePath = ".\Set-UnifiedADUserPassword-Log-$(Get-Date -Format 'yyyy-MM-dd').txt"
+ )
+
+ # --- LÓGICA PRINCIPAL ---
+
+ # Dependência da função Write-Log (deve estar no mesmo escopo ou módulo)
+ if (-not (Get-Command Write-Log -ErrorAction SilentlyContinue)) {
+ Write-Host "[ERRO FATAL] A função auxiliar 'Write-Log' não foi encontrada. O script não pode continuar." -ForegroundColor Red
+ return
+ }
+
+ 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."
+ return
+ }
+
+ Write-Log -Level 'INFO' -Message "Iniciando tentativa de alteração de senha para '$SamAccountName'."
+
+ $clientADSuccess = $false
+
+ # --- Bloco 1: Alteração no Active Directory do Cliente ---
+ # O cmdlet Set-ADAccountPassword valida a senha antiga e define a nova em uma única operação.
+ try {
+ Write-Host " Tentando alterar a senha no AD do Cliente..."
+ Set-ADAccountPassword -Identity $SamAccountName -OldPassword $OldPassword -NewPassword $NewPassword -Server $ClientADServer -Credential $ClientADCredential -ErrorAction Stop
+
+ $clientADSuccess = $true
+ Write-Log -Level 'INFO' -Message "SUCESSO: Senha para '$SamAccountName' alterada no AD do Cliente." -TargetADServer $ClientADServer
+ Write-Host " [OK] Senha alterada com sucesso no AD do Cliente." -ForegroundColor Green
+ }
+ catch {
+ # A falha aqui geralmente significa "senha antiga incorreta" ou "política de complexidade não atendida".
+ $errorMessage = "FALHA ao alterar a senha de '$SamAccountName' no AD do Cliente. Erro: $($_.Exception.Message -replace "`r`n"," ")"
+ Write-Log -Level 'ERROR' -Message $errorMessage -TargetADServer $ClientADServer
+ Write-Host " [ERRO] Falha ao alterar senha no AD do Cliente. Verifique a senha antiga e as políticas de complexidade." -ForegroundColor Red
+ # Não continuamos se o primeiro passo falhar.
+ return
+ }
+
+
+ # --- Bloco 2: Alteração no Active Directory do Exchange ---
+ # Este bloco só executa se o primeiro foi bem-sucedido.
+ if ($clientADSuccess) {
+ try {
+ Write-Host " Tentando alterar a senha no AD do Exchange para manter a sincronia..."
+ # Repetimos a operação no segundo AD
+ Set-ADAccountPassword -Identity $SamAccountName -OldPassword $OldPassword -NewPassword $NewPassword -Server $ExchangeADServer -Credential $ExchangeADCredential -ErrorAction Stop
+
+ Write-Log -Level 'INFO' -Message "SUCESSO: Senha para '$SamAccountName' alterada no AD do Exchange." -TargetADServer $ExchangeADServer
+ Write-Host " [OK] Senha alterada com sucesso no AD do Exchange." -ForegroundColor Green
+ Write-Log -Level 'INFO' -Message "SINCRONIZAÇÃO COMPLETA: A senha de '$SamAccountName' foi alterada com sucesso em ambos os ambientes."
+ }
+ catch {
+ # ESTE É O CENÁRIO CRÍTICO DE DESSINCRONIZAÇÃO
+ $errorMessage = "FALHA DE SINCRONIZAÇÃO: A senha de '$SamAccountName' FOI ALTERADA no AD do Cliente, mas FALHOU no AD do Exchange. AÇÃO MANUAL PODE SER NECESSÁRIA. Erro: $($_.Exception.Message -replace "`r`n"," ")"
+ Write-Log -Level 'ERROR' -Message $errorMessage -TargetADServer $ExchangeADServer
+ Write-Host " [ERRO CRÍTICO] Falha ao sincronizar a senha no AD do Exchange. A senha foi alterada apenas no primeiro ambiente!" -ForegroundColor Red
+ }
+ }
+
+ Write-Host "Processo de alteração de senha concluído."
+}
+
+# --- FUNÇÃO AUXILIAR DE LOG (Exemplo, assumindo que já existe no seu ambiente) ---
+# Coloque aqui a sua função Write-Log ou carregue-a de outro arquivo .ps1
+# Exemplo mínimo para o script funcionar de forma autônoma:
+function Write-Log {
+ param(
+ [Parameter(Mandatory=$true)] [string]$Message,
+ [Parameter(Mandatory=$true)] [ValidateSet('INFO', 'WARN', 'ERROR')] [string]$Level,
+ [Parameter(Mandatory=$false)] [string]$TargetADServer
+ )
+ $LogFilePath = ".\Set-UnifiedADUserPassword-Log-$(Get-Date -Format 'yyyy-MM-dd').txt"
+ $logEntry = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - [$Level] - $Message"
+ $logEntry | Out-File -FilePath $LogFilePath -Append
+}
\ No newline at end of file