Powershell: Script para comparar directorios y ficheros
Hoy os muestro un script que os va a permitir comparar y monitorizar ficheros dentro de varias carpetas.
Os muestro el contexto, para poder interpretar el uso del script.
- ORIGEN: Dispongo de varias máquinas de varios proveedores diferentes, que generan ficheros periódicamente en un share en un formato determinado en una carpeta para cada proveedor. El nombre de cada carpeta tiene que ver con su número de serie, con lo que no puedo relacionarlas correctamente con un alias.
- DESTINO: Esos ficheros a su vez, se copian y tratan en otra carpeta por otro proveedor único, donde este proveedor, cambia el formato de los mismos para poder entregar los resultados en su aplicación a los usuarios.
- Los nombres de los ficheros resultantes en origen y destino, incluyen el ID del proceso que han ejecutado, pero los nombres son diferentes, según el proveedor de origen
El problema es, que no puedo monitorizar que no existan problemas en el tratamiento de los datos, así que he creado este script para poder monitorizar eventuales problemas, que se pueden generar tanto en origen como en destino, simplemente comprobando que los ficheros existen en ambas carpetas o no, lo que me indica que se han procesado correctamente.
Adicionalmente, necesito:
- Crear una alias para cada máquina, de tal forma que relacione el nombre de carpeta con cada máquina, con un nombre que yo genere
- Validar si no existe en origen o destino, para saber qué proveedor tiene el problema. Para esto usaremos lo que nos devuelva de VALUE (==, =>…)
- Generar un informe HTML donde se pueda visualizar fácilmente qué proveedor tiene el problema
- Entregar este informe por correo periódicamente
- Registro de log de la ejecución
Voy a hacer el ejemplo con 3 proveedores, dos de ORIGEN (fabricantes de dos tipos de máquinas) y uno de DESTINO (quien procesa el dato).
Os dejo el resultado:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
############################################# # EL BLOG DE NEGU - SCRIPT DIFERENCIAS SHARE ############################################# # OBTENER FECHA y AÑO $dia=Get-Date -Format "dd/MM/yyyy" $year=Get-Date -Format "yyyy" $currentDate = Get-Date -Format "yyyyMMdd_HHmmss" ## LOG $Logfile = "C:\Users\USUARIO\Documents\MAQUINAS\resultados_$currentDate.log" Start-Transcript -Path $Logfile -Append # ESTILO CSS REPORTE HTML #Definimos los códigos de estilos CSS $header = @" <style> h1 { font-family: Arial, Helvetica, sans-serif; color: #44A1FE; font-size: 28px; } h2 { font-family: Arial, Helvetica, sans-serif; color: #000099; font-size: 16px; } table { font-family:"Trebuchet MS", Arial, Helvetica, sans-serif; border-collapse:collapse; overflow:scroll; } td { font-size:1em; border:1px solid #2087db; padding:5px 5px 5px 5px; text-align: center; } th { font-size:1.1em; text-align:center; padding-top:5px; padding-bottom:5px; padding-right:7px; padding-left:7px; background-color:#2087db; color:#ffffff; text-align: center; } tbody tr:nth-child(even) { background: #f0f0f2; } #CreationDate { font-family: Arial, Helvetica, sans-serif; color: #ff3300; font-size: 12px; } .OrigenStatus { color: #ff0000; } .DestinoStatus { color: #0000ff; } .OKStatus { color: #008000; } </style> "@ # DATOS RAIZ SHARE $SERVER= "servidorficheros" $SHARE= "MAQUINAS" # HASH LISTADO CORRELACIONES MAQUINAS-DIRECTORIOS PROVEEDOR-A $LISTADO= @{"MAQUINA01"="00016189";"MAQUINA02"="00013899";"MAQUINA03"="00019706";"MAQUINA04"="00025241";"MAQUINA05"="00021689";"MAQUINA06"="00030312"; } foreach ($MACHINE in $LISTADO.GetEnumerator() | Sort-Object -Property Name -Descending) { # MAQUINAS QUE ESTAMOS TRATANDO $MACHINES = $MACHINE.Value $NOMBRE = $MACHINE.Name # RUTA COMPLETA DEL SHARE $PROVEEDORA="\\$SERVER\$SHARE\PROVEEDOR-A\$MACHINES\$year\" $PROVEEDORX="\\$SERVER\$SHARE\Procesados\PROVEEDOR-A\$MACHINES\$year\" # EXTRAER DATOS ORIGEN (PROVEEDOR-A) $fso = Get-ChildItem -Recurse -Path $PROVEEDORA -Include *.txs | Select-Object Name,LastWriteTime | Sort-Object -property lastwritetime -Descending | Where-Object -FilterScript {$_.LastWriteTime -gt (Get-Date).AddDays(-1)} # SI NO HAY FICHEROS if ($fso){ # LIMPIAR LOS DATOS DE ORIGEN (PROVEEDOR-A) $origen = $fso.Name.Replace(".txs", "") $origen = $origen.Substring(2,4) } else{ $origen = "0000" } # EXTRAEMOS DATOS DE DESTINO (PROVEEDOR-X) $fsd = Get-ChildItem -Recurse -Path $PROVEEDORX -Include *.txs | Select-Object Name,LastWriteTime | Sort-Object -property lastwritetime -Descending | Where-Object -FilterScript {$_.LastWriteTime -gt (Get-Date).AddDays(-1)} if ($fsd){ # LIMPIAR LOS DATOS DE ORIGEN (PROVEEDOR-X) $destino = $fsd.Name.Replace(".txs", "") $destino = $destino.Substring(0,4) } else{ $destino = "0001" } # COMPARAMOS Y EXTRAEMOS EL RESULTADO PROCESO A PROCESO PARA EL LOG Compare-Object -ReferenceObject $origen -DifferenceObject $destino -IncludeEqual | Tee-Object -Variable compareObject $num = $compareObject.Name.Count $y = 0 Do { foreach ($i in $compareObject.InputObject){ write-host "Proceso :" $i if ($compareObject.SideIndicator[$y] -eq '==') { write-host "Estado :" $compareObject.SideIndicator[$y] write-host "Encontrado el dia $dia proceso $i en ambas carpetas para la maquina $NOMBRE" } elseif ($compareObject.SideIndicator[$y] -eq '=>') { write-host "Estado :" $compareObject.SideIndicator[$y] write-host "Encontrada diferencia el dia $dia en proceso $i en destino (PROVEEDOR-X) para la maquina $NOMBRE" } else{ write-host "Estado :" $compareObject.SideIndicator[$y] write-host "Encontrada diferencia el dia $dia en proceso $i en origen (PROVEEDOR-A) para la maquina $NOMBRE" } $y++ } } while ($y -lt $num) #INFORME HTML: OBTENEMOS EL NOMBRE DE LA MAQUINA $MachineName = "<h1>Nombre maquina PROVEEDOR-A: $NOMBRE</h1>" ## COMPARAMOS Y EXTRAEMOS EL RESULTADO CON FORMATO $ProcesosInfo = Compare-Object -ReferenceObject $origen -DifferenceObject $destino -IncludeEqual | Tee-Object -Variable compareObject | ConvertTo-Html -Property InputObject,SideIndicator -Fragment -PreContent "<h2>Informacion Procesos carpeta $MACHINES</h2>" $ProcesosInfo = $ProcesosInfo -replace 'InputObject','PROCESO' $ProcesosInfo = $ProcesosInfo -replace 'SideIndicator','ESTADO' $ProcesosInfo = $ProcesosInfo -replace '<td>==</td>','<td class="OKStatus">OK</td>' $ProcesosInfo = $ProcesosInfo -replace '<td>=></td>','<td class="DestinoStatus">PROBLEMA PROVEEDOR-X</td>' $ProcesosInfo = $ProcesosInfo -replace '<td><=</td>','<td class="OrigenStatus">PROBLEMA PROVEEDOR-A</td>' $ProcesosInfo = $ProcesosInfo -replace '<td>0000</td>','<td class="ProblemStatus">MAQUINA NO GENERA FICHEROS</td>' $ProcesosInfo = $ProcesosInfo -replace '<td>0001</td>','<td class="ProblemStatus">MAQUINA NO GENERA FICHEROS</td>' #El siguiente comando combinará toda la información recopilada en un solo informe HTML $Report = ConvertTo-HTML -Body "$MachineName $ProcesosInfo" -Head $header -Title "Machines Information Report" -PostContent "<p id='CreationDate'>Creado el dia: $dia</p>" #El siguiente comando generará el informe en un archivo HTML #$Report | Out-File C:\Users\USUARIO\Documents\MAQUINAS\Basic-Machine-Information-Report-$NOMBRE.html $Report >> C:\Users\USUARIO\Documents\MAQUINAS\Basic-Machine-Information-Report_$currentDate.html } # HASH LISTADO CORRELACIONES MAQUINAS-DIRECTORIOS PROVEEDOR-B $LISTADOST= @{"MAQUINA07"="1047180538";"MAQUINA08"="4320052391";"MAQUINA09"="4320073912"; } foreach ($MACHINEST in $LISTADOST.GetEnumerator() | Sort-Object -Property Name -Descending) { # MAQUINAS QUE ESTAMOS TRATANDO $MACHINESST = $MACHINEST.Value $NOMBREST = $MACHINEST.Name # RUTA COMPLETA DEL SHARE $PROVEEDORB="\\$SERVER\$SHARE\PROVEEDOR-B\$MACHINESST\" $PROVEEDORXST="\\$SERVER\$SHARE\Procesados\PROVEEDOR-B\$MACHINESST\$year\" # Una de las maquinas del proveedor-B genera otro nombre de fichero para el ID del proceso, añadiendo un cero if ($MACHINESST -eq "1047180538") { # EXTRAER DATOS ORIGEN (PROVEEDOR-B) $fsoST = Get-ChildItem -Recurse -Path $PROVEEDORB -Include *.txt | Select-Object Name,LastWriteTime | Sort-Object -property lastwritetime -Descending | Where-Object -FilterScript {$_.LastWriteTime -gt (Get-Date).AddDays(-1)} if ($fsoST){ # LIMPIAR LOS DATOS DE ORIGEN (PROVEEDORB) $origenST = $fsoST.Name.Replace("CONFIDENTIALITY_NOTICE_0", "") # SI LA NUMERACION SUBE DE 10000 DARA ERROR Y HAY QUE CAMBIAR LA LINEA ANTERIOR POR #$origenST = $fsoST.Name.Replace("CONFIDENTIALITY_NOTICE_", "") $origenST = $origenST -Replace (".txt", "") #$origenST = $origenST.Substring(23,26) } else{ $origenST = "0000" } } Else { # EXTRAER DATOS ORIGEN (PROVEEDOR-B) $fsoST = Get-ChildItem -Recurse -Path $PROVEEDOR-B -Include *.txt | Select-Object Name,LastWriteTime | Sort-Object -property lastwritetime -Descending | Where-Object -FilterScript {$_.LastWriteTime -gt (Get-Date).AddDays(-1)} if ($fsoST){ # LIMPIAR LOS DATOS DE ORIGEN (PROVEEDOR-B) $origenST = $fsoST.Name.Replace("CONFIDENTIALITY_NOTICE_", "") # SI LA NUMERACION SUBE DE 10000 DARA ERROR Y HAY QUE CAMBIAR LA LINEA ANTERIOR POR #$origenST = $fsoST.Name.Replace("CONFIDENTIALITY_NOTICE_", "") $origenST = $origenST -Replace (".txt", "") #$origenST = $origenST.Substring(23,26) } else{ $origenST = "0000" } } # EXTRAEMOS DATOS DE DESTINO (PROVEEDOR-X) $fsdST = Get-ChildItem -Recurse -Path $PROVEEDORXST -Include *.pdf | Select-Object Name,LastWriteTime | Sort-Object -property lastwritetime -Descending | Where-Object -FilterScript {$_.LastWriteTime -gt (Get-Date).AddDays(-1)} if ($fsdST){ # LIMPIAR LOS DATOS DE ORIGEN (PROVEEDOR-X) $destinoST = $fsdST.Name.Replace(".pdf", "") #$destinoST = $destinoST.Substring(0,4) } else{ $destinoST = "0001" } # COMPARAMOS Y EXTRAEMOS EL RESULTADO PROCESO A PROCESO PARA EL LOG Compare-Object -ReferenceObject $origenST -DifferenceObject $destinoST -IncludeEqual | Tee-Object -Variable compareObjectST $numST = $compareObjectST.Name.Count $z = 0 Do { foreach ($st in $compareObjectST.InputObject){ write-host "Proceso :" $st if ($compareObjectST.SideIndicator[$z] -eq '==') { write-host "Estado :" $compareObjectST.SideIndicator[$z] write-host "Encontrado el dia $dia proceso $st en ambas carpetas para la maquina $NOMBREST" } elseif ($compareObjectST.SideIndicator[$z] -eq '=>') { write-host "Estado :" $compareObjectST.SideIndicator[$z] write-host "Encontrada diferencia el dia $dia en proceso $st en destino (PROVEEDOR-X) para la maquina $NOMBREST" } else{ write-host "Estado :" $compareObjectST.SideIndicator[$z] write-host "Encontrada diferencia el dia $dia en proceso $st en origen (PROVEEDOR-B) para la maquina $NOMBREST" } $z++ } } while ($z -lt $numST) #INFORME HTML: OBTENEMOS EL NOMBRE DE LA MAQUINA $MachineNameST = "<h1>Nombre maquina PROVEEDOR-B: $NOMBREST</h1>" ## COMPARAMOS Y EXTRAEMOS EL RESULTADO CON FORMATO $ProcesosInfoST = Compare-Object -ReferenceObject $origenST -DifferenceObject $destinoST -IncludeEqual | Tee-Object -Variable compareObjectST | ConvertTo-Html -Property InputObject,SideIndicator -Fragment -PreContent "<h2>Informacion Procesos carpeta $MACHINESST</h2>" $ProcesosInfoST = $ProcesosInfoST -replace 'InputObject','PROCESO' $ProcesosInfoST = $ProcesosInfoST -replace 'SideIndicator','ESTADO' $ProcesosInfoST = $ProcesosInfoST -replace '<td>==</td>','<td class="OKStatus">OK</td>' $ProcesosInfoST = $ProcesosInfoST -replace '<td>=></td>','<td class="DestinoStatus">PROBLEMA PROVEEDOR-X</td>' $ProcesosInfoST = $ProcesosInfoST -replace '<td><=</td>','<td class="OrigenStatus">PROBLEMA PROVEEDOR-B</td>' $ProcesosInfoST = $ProcesosInfoST -replace '<td>0000</td>','<td class="ProblemStatus">MAQUINA NO GENERA FICHEROS</td>' $ProcesosInfoST = $ProcesosInfoST -replace '<td>0001</td>','<td class="ProblemStatus">MAQUINA NO GENERA FICHEROS</td>' #El siguiente comando combinará toda la información recopilada en un solo informe HTML $Report = ConvertTo-HTML -Body "$MachineNameST $ProcesosInfoST" -Head $header -Title "Machines Information Report" -PostContent "<p id='CreationDate'>Creado el dia: $dia</p>" #El siguiente comando generará el informe en un archivo HTML $Report >> C:\Users\USUARIO\Documents\MAQUINAS\Basic-Machine-Information-Report_$currentDate.html } $Report2 = Get-Content -Path "C:\Users\USUARIO\Documents\MAQUINAS\Basic-Machine-Information-Report_$currentDate.html" # ENVIAR DATOS POR CORREO # IRAN ADJUNTOS E INSERTADOS EN EL CUERPO DEL MENSAJE $From = "monitorizacion@elblogdenegu.local" $To = "raul@elblogdenegu.local" ## VARIOS USUARIOS "usuario1@elblogdenegu.local", "usuario2@elblogdenegu.local" $Servidor = "correo.elblogdenegu.local" $Asunto = "Informe Maquinas - $dia" $Cuerpo = @" <table style="width: 68%" style="border-collapse: collapse; border: 1px solid #2087db;"> <tr> <td colspan="2" bgcolor="#2087db" style="color: #FFFFFF; font-size: large; height: 35px;"> INFORME DIARIO MAQUINAS - $dia </td> </tr> <tr style="border-bottom-style: solid; border-bottom-width: 1px; padding-bottom: 1px"> <td style="width: 201px; height: 35px"> Numero de maquinas PROVEEDOR-A</td> <td style="text-align: center; height: 35px; width: 233px;"> <b>6</b></td> </tr> <tr style="height: 39px; border: 1px solid #2087db"> <td style="width: 201px; height: 39px"> Numero de maquinas PROVEEDOR-B</td> <td style="text-align: center; height: 39px; width: 233px;"> <b>3</b></td> </tr> </table> $Report2 "@ Send-MailMessage -SmtpServer $Servidor -BodyAsHtml -From $From -To $To -Subject $Asunto -Body $Cuerpo -Priority High -dno onSuccess, onFailure -Encoding ([System.Text.Encoding]::UTF8) -Attachments "C:\Users\USUARIO\Documents\MAQUINAS\Basic-Machine-Information-Report_$currentDate.html" # PARAR LOG Stop-Transcript |
Ahora simplemente llevaríamos el script a una tarea programada Windows y listo. Nos llegaría un email con el HTML adjunto, y los problemas detectados en cada caso, por proceso:
Seguro que hay mil formas de optimizar esto…pero a mí me funciona relativamente bien y el desarrollo no me ha parecido complejo.
Te ha gustado la entrada SGUENOS EN TWITTER O INVITANOS A UN CAFE?