PowerShell es un shell de comandos y lenguaje de scripting desarrollado por Microsoft, construido sobre .NET Framework/.NET Core. Combina la flexibilidad de un lenguaje de scripting con la potencia de una herramienta de administración del sistema.
Versión | Año | Características Principales |
---|---|---|
PowerShell 1.0 | 2006 | Versión inicial, solo para Windows |
PowerShell 2.0 | 2009 | Remoting, módulos, funciones avanzadas |
PowerShell 3.0 | 2012 | Workflows, mejoras en remoting, ISE mejorado |
PowerShell 5.0 | 2016 | Classes, .NET Core support, mejor manejo de módulos |
PowerShell 7.x | 2020+ | Multiplataforma, mejor rendimiento, nuevas características |
# Comparación de comandos básicos
# CMD (Command Prompt)
dir # Listar archivos
ipconfig # Configuración de red
netstat -ano # Conexiones de red
# PowerShell equivalente
Get-ChildItem # Listar archivos
Get-NetIPConfiguration # Configuración de red
Get-NetTCPConnection # Conexiones de red
# Ayuda y descubrimiento
Get-Help Get-Process # Mostrar ayuda para un cmdlet
Get-Command -Verb Get # Listar todos los cmdlets que empiezan con Get
Update-Help # Actualizar la ayuda local
# Sistema de archivos
Set-Location C:\ # Cambiar directorio (cd)
Get-ChildItem # Listar contenido (dir/ls)
New-Item -ItemType File -Name "test.txt" # Crear archivo
Remove-Item test.txt # Eliminar archivo
# Procesos y servicios
Get-Process # Listar procesos
Stop-Process -Name notepad # Detener proceso
Get-Service # Listar servicios
Start-Service -Name "Spooler" # Iniciar servicio
Los cmdlets siguen el formato Verbo-Sustantivo
(por ejemplo, Get-Process
). Los verbos comunes incluyen:
Nota: PowerShell es sensible a mayúsculas/minúsculas en nombres de variables y archivos, pero no en cmdlets.
# Listar archivos con filtrado
Get-ChildItem -Path C:\Windows -Filter *.log -Recurse -File
# Leer y escribir archivos
Get-Content -Path "C:\logs\app.log" -Tail 10 # Últimas 10 líneas
Set-Content -Path "output.txt" -Value "Texto de ejemplo"
Add-Content -Path "log.txt" -Value "$(Get-Date) - Evento ocurrido"
# Copiar y mover archivos
Copy-Item -Path "source.txt" -Destination "C:\backup\source.txt"
Move-Item -Path "old.txt" -Destination "new.txt"
# Comprimir archivos
Compress-Archive -Path "C:\data\*" -DestinationPath "C:\backup\data.zip"
Expand-Archive -Path "data.zip" -DestinationPath "C:\restore\"
# Información del sistema
Get-ComputerInfo # Información detallada del sistema
Get-CimInstance -ClassName Win32_OperatingSystem # Info del OS
Get-Disk # Discos del sistema
Get-Volume # Volúmenes
# Usuarios y grupos
Get-LocalUser # Listar usuarios locales
New-LocalUser -Name "jdoe" -Description "Usuario de prueba"
Get-LocalGroup # Listar grupos locales
Add-LocalGroupMember -Group "Administradores" -Member "jdoe"
# Event Logs
Get-EventLog -LogName System -Newest 10 # Últimos 10 eventos del sistema
Get-WinEvent -FilterHashtable @{LogName='Application'; Level=2} # Eventos de error
El pipeline (|) permite pasar la salida de un cmdlet como entrada al siguiente.
# Ejemplo básico de pipeline
Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 5
# Explicación:
# 1. Get-Process obtiene todos los procesos
# 2. Sort-Object los ordena por uso de CPU (descendente)
# 3. Select-Object toma los primeros 5
# Where-Object para filtrar
Get-Service | Where-Object { $_.Status -eq 'Running' -and $_.StartType -eq 'Automatic' }
# Select-Object para seleccionar propiedades
Get-Process | Select-Object -Property Name, Id, CPU, WorkingSet
# Group-Object para agrupar
Get-ChildItem -File | Group-Object -Property Extension
# Sort-Object para ordenar
Get-Process | Sort-Object -Property WS -Descending | Select-Object -First 10
Operador | Descripción | Ejemplo |
---|---|---|
-eq | Igual | $x -eq 10 |
-ne | No igual | $x -ne 10 |
-gt | Mayor que | $x -gt 10 |
-lt | Menor que | $x -lt 10 |
-like | Comparación con comodines (*) | $name -like "j*" |
-match | Expresión regular | $text -match "^[A-Z]" |
# Definir variables
$nombre = "Juan Pérez"
$edad = 35
$activo = $true
$fecha = Get-Date
# Usar variables
Write-Host "Nombre: $nombre, Edad: $edad"
# Variables especiales
$HOME # Directorio home del usuario
$PWD # Directorio actual
$PSVersionTable # Versión de PowerShell
$_ # Variable automática (objeto actual en el pipeline)
# Tipos explícitos
[int]$numero = 42
[string]$texto = "Hola mundo"
[datetime]$fecha = "2023-01-15"
[bool]$verdadero = $true
# Arrays
$frutas = @("Manzana", "Banana", "Naranja")
$frutas[1] # Acceder al segundo elemento (Banana)
# Hashtables (diccionarios)
$persona = @{
Nombre = "Carlos"
Edad = 28
Profesion = "Ingeniero"
}
$persona.Nombre # Acceder a propiedad
# Crear objeto personalizado
$empleado = [PSCustomObject]@{
ID = 1001
Nombre = "María González"
Departamento = "TI"
Salario = 75000
FechaContratacion = Get-Date "2020-05-15"
}
# Acceder a propiedades
$empleado.Nombre
$empleado.Departamento = "Finanzas" # Modificar valor
# Exportar a CSV
$empleado | Export-Csv -Path "empleados.csv" -NoTypeInformation -Append
$a = 10
$b = 3
$a + $b # Suma (13)
$a - $b # Resta (7)
$a * $b # Multiplicación (30)
$a / $b # División (3.333...)
$a % $b # Módulo (1)
++$a # Incremento (11)
--$b # Decremento (2)
$x = 5 # Asignación básica
$x += 3 # Equivalente a $x = $x + 3 (8)
$x -= 2 # $x = $x - 2 (6)
$x *= 4 # $x = $x * 4 (24)
$x /= 3 # $x = $x / 3 (8)
$true -and $false # AND lógico (False)
$true -or $false # OR lógico (True)
-not $true # NOT lógico (False)
!$true # Alternativa para NOT (False)
# If-elseif-else
$temperatura = 25
if ($temperatura -lt 0) {
Write-Host "Congelando"
} elseif ($temperatura -lt 20) {
Write-Host "Fresco"
} elseif ($temperatura -lt 30) {
Write-Host "Agradable"
} else {
Write-Host "Caliente"
}
# Switch
$dia = (Get-Date).DayOfWeek
switch ($dia) {
"Monday" { Write-Host "Comienza la semana" }
"Friday" { Write-Host "¡Viernes!" }
{$_ -in "Saturday","Sunday"} { Write-Host "Fin de semana" }
default { Write-Host "Día laboral" }
}
# For
for ($i = 1; $i -le 5; $i++) {
Write-Host "Iteración $i"
}
# Foreach (colección)
$servicios = Get-Service
foreach ($servicio in $servicios) {
if ($servicio.Status -eq 'Running') {
Write-Host "$($servicio.Name) está en ejecución"
}
}
# While
$contador = 0
while ($contador -lt 3) {
Write-Host "Contador: $contador"
$contador++
}
# Do-While
$input = ""
do {
$input = Read-Host "Ingrese 'salir' para terminar"
} while ($input -ne "salir")
# Función simple
function Saludar {
param(
[string]$nombre = "Usuario"
)
Write-Host "Hola, $nombre!"
}
Saludar -nombre "Carlos"
# Función con valor de retorno
function Sumar {
param(
[double]$a,
[double]$b
)
return $a + $b
}
$resultado = Sumar -a 5.5 -b 3.2
Write-Host "La suma es $resultado"
# Función avanzada con validación
function Get-FileStats {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[ValidateScript({Test-Path $_ -PathType 'Leaf'})]
[string]$FilePath,
[ValidateSet('KB','MB','GB')]
[string]$Unit = 'KB'
)
begin {
Write-Verbose "Iniciando procesamiento de archivo"
}
process {
$file = Get-Item $FilePath
$size = switch ($Unit) {
'KB' { $file.Length / 1KB }
'MB' { $file.Length / 1MB }
'GB' { $file.Length / 1GB }
}
[PSCustomObject]@{
Name = $file.Name
Path = $file.FullName
Size = $size
Unit = $Unit
LastModified = $file.LastWriteTime
}
}
end {
Write-Verbose "Procesamiento completado"
}
}
# Uso:
Get-FileStats -FilePath "C:\Windows\explorer.exe" -Unit MB -Verbose
<#
.SYNOPSIS
Script para copiar archivos con registro.
.DESCRIPTION
Copia archivos de un origen a un destino y registra las operaciones.
.PARAMETER Source
Directorio de origen.
.PARAMETER Destination
Directorio de destino.
.PARAMETER LogFile
Archivo de registro (opcional).
.EXAMPLE
.\Copy-Files.ps1 -Source C:\temp -Destination D:\backup
#>
param(
[Parameter(Mandatory=$true)]
[string]$Source,
[Parameter(Mandatory=$true)]
[string]$Destination,
[string]$LogFile = "copy_log.txt"
)
# Verificar directorios
if (-not (Test-Path $Source -PathType Container)) {
Write-Error "El directorio de origen no existe"
exit 1
}
if (-not (Test-Path $Destination -PathType Container)) {
try {
New-Item -ItemType Directory -Path $Destination | Out-Null
Add-Content -Path $LogFile -Value "$(Get-Date) - Directorio creado: $Destination"
} catch {
Write-Error "No se pudo crear el directorio de destino"
exit 1
}
}
# Copiar archivos
Get-ChildItem -Path $Source -File | ForEach-Object {
try {
Copy-Item -Path $_.FullName -Destination $Destination -Force
Add-Content -Path $LogFile -Value "$(Get-Date) - Copiado: $($_.Name)"
} catch {
Add-Content -Path $LogFile -Value "$(Get-Date) - ERROR copiando: $($_.Name)"
}
}
Write-Host "Proceso completado. Ver registro en $LogFile"
# Listar módulos disponibles
Get-Module -ListAvailable
# Importar módulo
Import-Module NetTCPIP
# Ver cmdlets en un módulo
Get-Command -Module NetTCPIP
# Crear módulo simple
# Guardar como MyModule.psm1
function Get-Hello {
Write-Host "Hola desde MyModule!"
}
Export-ModuleMember -Function Get-Hello
# Importar módulo personalizado
Import-Module .\MyModule.psm1
Get-Hello
# Configurar la Galería PowerShell (si es necesario)
Register-PSRepository -Default
# Buscar módulos
Find-Module -Name *Azure*
# Instalar módulo
Install-Module -Name Pester -Force -Scope CurrentUser
# Actualizar módulo
Update-Module -Name Pester
# Listar módulos instalados
Get-InstalledModule
try {
# Código que podría generar errores
$result = 10 / $null
Write-Host "Resultado: $result"
}
catch [System.DivideByZeroException] {
Write-Host "Error: División por cero"
$_.Exception.Message # Mensaje detallado del error
}
catch {
# Captura cualquier otro error
Write-Host "Error inesperado: $($_.Exception.GetType().Name)"
Write-Host "Mensaje: $($_.Exception.Message)"
}
finally {
# Siempre se ejecuta
Write-Host "Operación completada (con o sin errores)"
}
# Comportamiento por defecto (Continue)
$ErrorActionPreference = "Continue" # Muestra error y continúa
# Opciones:
# - Stop: Termina la ejecución
# - SilentlyContinue: Omite el error sin mensaje
# - Inquire: Pregunta al usuario qué hacer
# - Ignore: Omite el error completamente
# Ejemplo:
$ErrorActionPreference = "Stop"
Get-Item "archivo_inexistente.txt" # Terminará el script
# Variable $Error contiene los últimos errores
$Error[0] # Último error
$Error.Clear() # Limpiar registro de errores
# Crear registro personalizado
try {
Get-Content "ruta_invalida.txt" -ErrorAction Stop
}
catch {
$errorMsg = "$(Get-Date) - Error al leer archivo: $($_.Exception.Message)"
Add-Content -Path "error_log.txt" -Value $errorMsg
Write-Warning $errorMsg
}
# Listar procesos
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10
# Detener proceso
Stop-Process -Name "notepad" -Force
# Iniciar proceso
Start-Process -FilePath "notepad.exe" -ArgumentList "C:\temp\notes.txt"
# Procesos remotos (necesita permisos)
Invoke-Command -ComputerName Server01 -ScriptBlock { Get-Process }
# Listar servicios
Get-Service | Where-Object { $_.Status -eq 'Running' }
# Iniciar/detener servicio
Start-Service -Name "Spooler"
Stop-Service -Name "Spooler" -Force
# Configurar inicio automático
Set-Service -Name "Spooler" -StartupType Automatic
# Servicios remotos
Get-CimInstance -ClassName Win32_Service -ComputerName Server01 |
Where-Object { $_.State -eq 'Running' }
# Leer logs de eventos
Get-EventLog -LogName System -Newest 20
Get-WinEvent -LogName Application -MaxEvents 10 |
Where-Object { $_.Level -eq 2 } # Eventos de error
# Crear nuevo log
New-EventLog -LogName "MyAppLog" -Source "MyApplication"
# Escribir en el log
Write-EventLog -LogName "MyAppLog" -Source "MyApplication" -EventId 1001 -EntryType Information -Message "Aplicación iniciada"
# Exportar eventos
Get-WinEvent -LogName System -MaxEvents 100 | Export-Csv -Path "system_events.csv"
# Habilitar PSRemoting (en el servidor)
Enable-PSRemoting -Force
# Verificar configuración
Get-PSSessionConfiguration
# Crear sesión remota
$session = New-PSSession -ComputerName "Server01" -Credential (Get-Credential)
# Ejecutar comando remoto
Invoke-Command -Session $session -ScriptBlock { Get-Service }
# Copiar archivos
Copy-Item -Path "C:\localfile.txt" -Destination "C:\remotefile.txt" -ToSession $session
# Cerrar sesión
Remove-PSSession $session
# Crear sesión persistente
$session = New-PSSession -ComputerName "Server01" -Name "Maintenance"
# Entrar en la sesión (como SSH)
Enter-PSSession -Session $session
# Comandos interactivos...
Exit-PSSession
# Ejecutar múltiples comandos
Invoke-Command -Session $session -ScriptBlock {
Get-Service | Where-Object { $_.Status -ne 'Running' } | Start-Service
Get-EventLog -LogName System -Newest 10
}
# Listar sesiones activas
Get-PSSession
# Eliminar sesión
Remove-PSSession -Session $session
# Configurar sesión con opciones
$options = New-PSSessionOption -IdleTimeout 3600000 -OperationTimeout 300000
$cred = Get-Credential
$session = New-PSSession -ComputerName "Server01" -SessionOption $options -Credential $cred
# Configuración de punto final (JEA - Just Enough Administration)
Register-PSSessionConfiguration -Name "Limited" -RunAsCredential $cred -SecurityDescriptorSddl "O:NSG:BAD:P(A;;GA;;;BA)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)"
# Conectar con punto final limitado
Enter-PSSession -ComputerName "Server01" -ConfigurationName "Limited"
# Configuración de red
Get-NetIPConfiguration # Configuración IP completa
Get-NetIPAddress -AddressFamily IPv4 | Select-Object InterfaceAlias, IPAddress
Get-NetRoute | Where-Object { $_.DestinationPrefix -eq '0.0.0.0/0' } # Ruta por defecto
# DNS
Resolve-DnsName -Name "google.com" -Type A
Get-DnsClientServerAddress -AddressFamily IPv4
# Conexiones de red
Get-NetTCPConnection -State Established
Test-NetConnection -ComputerName "google.com" -Port 80
# Descargar archivo
Invoke-WebRequest -Uri "https://example.com/file.zip" -OutFile "C:\temp\file.zip"
# Subir archivo (requiere configuración del servidor)
$headers = @{ Authorization = "Bearer token123" }
Invoke-WebRequest -Uri "https://api.example.com/upload" -Method Post -InFile "data.json" -Headers $headers
# FTP básico
$ftpRequest = [System.Net.FtpWebRequest]::Create("ftp://ftp.example.com/file.txt")
$ftpRequest.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile
$ftpRequest.Credentials = New-Object System.Net.NetworkCredential("user", "pass")
$response = $ftpRequest.GetResponse()
$stream = $response.GetResponseStream()
# ... procesar stream
# GET request
$response = Invoke-RestMethod -Uri "https://api.github.com/users/octocat"
$response.name
$response.public_repos
# POST request con body JSON
$body = @{
name = "nuevo-repo"
description = "Repositorio creado desde PowerShell"
private = $false
} | ConvertTo-Json
$headers = @{
Authorization = "token ghp_yourtokenhere"
Accept = "application/vnd.github.v3+json"
}
Invoke-RestMethod -Uri "https://api.github.com/user/repos" -Method Post -Body $body -Headers $headers -ContentType "application/json"
# Instalar módulo AD (Windows)
Install-WindowsFeature -Name "RSAT-AD-PowerShell" -IncludeAllSubFeature
# Importar módulo
Import-Module ActiveDirectory
# Comandos disponibles
Get-Command -Module ActiveDirectory
# Buscar usuarios
Get-ADUser -Filter { Name -like "j*" } -Properties *
# Crear usuario
New-ADUser -Name "Juan Perez" -GivenName "Juan" -Surname "Perez" `
-SamAccountName "jperez" -UserPrincipalName "jperez@domain.com" `
-Path "OU=Users,DC=domain,DC=com" -AccountPassword (ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force) -Enabled $true
# Modificar usuario
Set-ADUser -Identity "jperez" -Department "IT" -Title "SysAdmin"
# Grupos
Get-ADGroup -Filter * | Select-Object Name
Add-ADGroupMember -Identity "Administrators" -Members "jperez"
# Usuarios inactivos
$inactiveDate = (Get-Date).AddDays(-90)
Get-ADUser -Filter { LastLogonDate -lt $inactiveDate -and Enabled -eq $true } -Properties LastLogonDate
# Buscar computadoras sin actualizar
Get-ADComputer -Filter { OperatingSystem -like "*Windows 7*" } -Properties OperatingSystem, LastLogonDate
# Exportar todos los usuarios a CSV
Get-ADUser -Filter * -Properties * |
Select-Object Name, SamAccountName, EmailAddress, Department, Title, Enabled |
Export-Csv -Path "all_users.csv" -NoTypeInformation
# Definición de clase
class Persona {
[string]$Nombre
[int]$Edad
[string]$Profesion
# Constructor
Persona([string]$nombre, [int]$edad) {
$this.Nombre = $nombre
$this.Edad = $edad
}
# Método
[string]Presentarse() {
return "Hola, soy $($this.Nombre) y tengo $($this.Edad) años."
}
}
# Uso de la clase
$persona1 = [Persona]::new("María", 30)
$persona1.Profesion = "Ingeniera"
Write-Host $persona1.Presentarse()
# Convertir a JSON
$data = @{
nombre = "Carlos"
edad = 35
hobbies = @("programar", "leer", "correr")
activo = $true
}
$json = $data | ConvertTo-Json -Depth 3
Write-Host $json
# Leer JSON
$jsonData = '{
"nombre": "Ana",
"puntuaciones": [85, 92, 78]
}'
$obj = $jsonData | ConvertFrom-Json
Write-Host "$($obj.nombre) tiene una puntuación promedio de $(($obj.puntuaciones | Measure-Object -Average).Average)"
# Coincidencia básica
$texto = "El teléfono es 555-1234 y el otro es 555-5678"
if ($texto -match "\d{3}-\d{4}") {
Write-Host "Teléfono encontrado: $($matches[0])"
}
# Extraer múltiples coincidencias
$matches = [regex]::Matches($texto, "\d{3}-\d{4}")
$matches | ForEach-Object {
Write-Host "Teléfono: $($_.Value)"
}
# Validación de email
function Test-Email {
param([string]$email)
$pattern = '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return $email -match $pattern
}
Test-Email "usuario@dominio.com" # True
Test-Email "invalido@dominio" # False
# Puntos de interrupción
Set-PSBreakpoint -Script .\script.ps1 -Line 10
# Depuración paso a paso
# Ejecutar script con:
# -Step: Paso a paso
# -Debug: Entrar en modo debug en breakpoints
# Variables de depuración
$DebugPreference = "Continue" # Mostrar mensajes de debug
Write-Debug "Este mensaje se mostrará"
# Mensajes detallados
Write-Verbose "Información detallada" -Verbose
# Medir tiempo de ejecución
Measure-Command {
Get-ChildItem -Path C:\Windows -Recurse -File | Where-Object { $_.Length -gt 1MB }
}
# Analizar uso de memoria
$process = Get-Process -Id $PID
Write-Host "Memoria usada: $($process.WorkingSet / 1MB) MB"
# Script de perfilado
$scriptBlock = {
# Código a medir
1..10000 | ForEach-Object { [math]::Sqrt($_) }
}
$time = Measure-Command -Expression $scriptBlock
Write-Host "Tiempo total: $($time.TotalMilliseconds) ms"
# Política de ejecución
Get-ExecutionPolicy # Ver política actual
Set-ExecutionPolicy RemoteSigned # Cambiar política
# Opciones:
# - Restricted: No scripts permitidos (default)
# - AllSigned: Solo scripts firmados
# - RemoteSigned: Scripts locales ok, remotos deben estar firmados
# - Unrestricted: Todos los scripts permitidos (no recomendado)
# Firmar scripts
$cert = Get-ChildItem -Path Cert:\CurrentUser\My -CodeSigningCert
Set-AuthenticodeSignature -FilePath .\script.ps1 -Certificate $cert
# Solicitar credenciales
$cred = Get-Credential
# Crear credenciales programáticamente (no seguro para producción)
$securePass = ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("usuario", $securePass)
# Usar credenciales
Invoke-Command -ComputerName "Server01" -Credential $cred -ScriptBlock { Get-Service }
# Exportar/importar credenciales (solo para pruebas)
$cred.Password | ConvertFrom-SecureString | Set-Content "password.txt"
$securePass = Get-Content "password.txt" | ConvertTo-SecureString
$cred = New-Object System.Management.Automation.PSCredential ("usuario", $securePass)
# Habilitar registro de módulos (PowerShell 5.1+)
# En política de grupo o registro:
# HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging
# Habilitar y especificar módulos
# Registro de ejecución de scripts
# Habilitar en:
# HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging
# Transcribir sesiones
Start-Transcript -Path "C:\logs\powershell_$(Get-Date -Format 'yyyyMMdd').txt"
# Comandos interactivos...
Stop-Transcript
# Monitor básico de recursos
function Get-SystemMonitor {
[CmdletBinding()]
param(
[int]$Interval = 5,
[int]$Duration = 60
)
$endTime = (Get-Date).AddSeconds($Duration)
$counter = 0
while ((Get-Date) -lt $endTime) {
$counter++
$cpuUsage = (Get-Counter '\Processor(_Total)\% Processor Time').CounterSamples.CookedValue
$memUsage = (Get-Counter '\Memory\% Committed Bytes In Use').CounterSamples.CookedValue
$processCount = (Get-Process).Count
Write-Host "$(Get-Date -Format 'HH:mm:ss') - CPU: $($cpuUsage.ToString('0.0'))% | Mem: $($memUsage.ToString('0.0'))% | Procesos: $processCount"
if ($counter -lt ($Duration / $Interval)) {
Start-Sleep -Seconds $Interval
}
}
}
# Uso:
Get-SystemMonitor -Interval 2 -Duration 30
<#
.SYNOPSIS
Script para backup de directorios.
.DESCRIPTION
Crea backups comprimidos de directorios especificados.
.PARAMETER SourcePath
Directorio(s) a respaldar.
.PARAMETER DestinationPath
Directorio de destino para los backups.
.PARAMETER RetentionDays
Número de días para retener backups (opcional).
#>
param(
[Parameter(Mandatory=$true)]
[string[]]$SourcePath,
[Parameter(Mandatory=$true)]
[string]$DestinationPath,
[int]$RetentionDays = 0
)
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$backupName = "Backup_$timestamp.zip"
$backupPath = Join-Path -Path $DestinationPath -ChildPath $backupName
# Verificar directorios de origen
foreach ($path in $SourcePath) {
if (-not (Test-Path $path -PathType Container)) {
Write-Error "Directorio no encontrado: $path"
exit 1
}
}
# Crear directorio de destino si no existe
if (-not (Test-Path $DestinationPath -PathType Container)) {
try {
New-Item -ItemType Directory -Path $DestinationPath | Out-Null
} catch {
Write-Error "No se pudo crear el directorio de destino: $_"
exit 1
}
}
# Crear backup
try {
Compress-Archive -Path $SourcePath -DestinationPath $backupPath -CompressionLevel Optimal
Write-Host "Backup creado exitosamente: $backupPath"
} catch {
Write-Error "Error al crear backup: $_"
exit 1
}
# Limpieza de backups antiguos
if ($RetentionDays -gt 0) {
$cutoffDate = (Get-Date).AddDays(-$RetentionDays)
Get-ChildItem -Path $DestinationPath -Filter "Backup_*.zip" |
Where-Object { $_.LastWriteTime -lt $cutoffDate } |
ForEach-Object {
try {
Remove-Item $_.FullName -Force
Write-Host "Eliminado backup antiguo: $($_.Name)"
} catch {
Write-Warning "No se pudo eliminar $($_.Name): $_"
}
}
}
<#
.SYNOPSIS
Genera reporte de usuarios de Active Directory.
.DESCRIPTION
Crea un reporte HTML con información de usuarios de AD.
#>
param(
[string]$OutputPath = "AD_User_Report.html",
[string]$OU = "OU=Users,DC=domain,DC=com"
)
# Verificar módulo AD
if (-not (Get-Module -Name ActiveDirectory -ListAvailable)) {
Write-Error "Módulo Active Directory no disponible"
exit 1
}
Import-Module ActiveDirectory
# Obtener usuarios
try {
$users = Get-ADUser -Filter * -SearchBase $OU -Properties *
} catch {
Write-Error "Error al obtener usuarios: $_"
exit 1
}
# Generar HTML
$htmlHeader = @"
<!DOCTYPE html>
<html>
<head>
<title>Reporte de Usuarios AD</title>
<style>
body { font-family: Arial, sans-serif; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #0066cc; color: white; }
tr:nth-child(even) { background-color: #f2f2f2; }
.disabled { color: #999; }
</style>
</head>
<body>
<h1>Reporte de Usuarios de Active Directory</h1>
<p>Generado: $(Get-Date)</p>
<p>Total usuarios: $($users.Count)</p>
<table>
<tr>
<th>Nombre</th>
<th>Usuario</th>
<th>Email</th>
<th>Departamento</th>
<th>Último inicio</th>
<th>Estado</th>
</tr>
"@
$htmlRows = $users | ForEach-Object {
$lastLogon = if ($_.LastLogonDate) { $_.LastLogonDate.ToString("yyyy-MM-dd") } else { "Nunca" }
$rowClass = if (-not $_.Enabled) { "class='disabled'" } else { "" }
@"
<tr $rowClass>
<td>$($_.Name)</td>
<td>$($_.SamAccountName)</td>
<td>$($_.EmailAddress)</td>
<td>$($_.Department)</td>
<td>$lastLogon</td>
<td>$(if ($_.Enabled) { "Activo" } else { "Desactivado" })</td>
</tr>
"@
}
$htmlFooter = @"
</table>
</body>
</html>
"@
# Guardar reporte
try {
$htmlHeader + $htmlRows + $htmlFooter | Out-File -FilePath $OutputPath -Force
Write-Host "Reporte generado exitosamente: $OutputPath"
} catch {
Write-Error "Error al guardar reporte: $_"
exit 1
}