|
101
|
Informática / Hardware / Re: Imágenes y vídeos en mi USB están cifrados
|
en: 5 Marzo 2024, 12:49 pm
|
Ya me dices algo (...) o al no tener el directorio de la cuenta antigua sería en vano.
Para poder llevar a cabo la posible solución que te indiqué, es necesario el archivo "NTUSER.DAT" que estaría ubicado en: "C:\Users\NOMBRE DE TU ANTIGUA CUENTA\NTUSER.DAT", sin eso, no sirve; si el directorio se eliminó al restablecer el sistema a la configuración de fábrica, entonces ya no nos sirve. Qué lástima. Aunque, de todas formas, quizás el intento no hubiese valido mucho la pena. Para determinarlo con algo de confianza y exactitud habría que conocer exactamente que información maneja de forma interna el servicio de cifrado EFS para validar una cuenta de usuario y permitir el descifrado desde esa cuenta, y eso es algo que desconozco. No creo que sea información pública.
Bueno, si todavía sigues queriendo probar, se me ocurre una sugerencia que podrías intentar... Esta sugerencia tiene el fin de intentar recuperar el archivo "NTUSER.DAT" que se borró en el procedimiento de ajustes de fábrica, y también el archivo "SECURITY" ubicado en "C:\Windows\System32\config" (aunque si puedes recuperar todo lo demás que hubiese en esta carpeta (las demás colmenas), mejor que mejor). Para ello puedes utilizar un programa de recuperación de datos, como por ejemplo Recuva: https://www.ccleaner.com/es-es/recuvaSi nunca has usado este tipo de programas creo que es preferible que visualices algún tutorial en Youtube antes que leer un par de explicaciones cortas escritas por mi parte. Nota: Para minimizar el riesgo de que algunas partes del archivo hayan sido sobreescritos por nuevos datos (y por ende, que no se puedan recuperar en su totalidad), sería conveniente que no hagas mucho uso del disco más allá del necesario, es decir, intentar no realizar demasiadas operaciones de escritura (intentar no descargar nada en ese disco, no crear archivos de tamaño muy pesado, etc). Solo hasta que hayas terminado de usar el programa de recuperación de datos. También es conveniente, en caso de que logres encontrar los archivos solicitados y también para minimizar el riesgo de sobreescritura, que, desde el programa de recuperación de datos, los archivos los recuperes enviándolos / guardándolos / reconstruyéndolos a otra unidad de disco, no al mismo disco en el que fueron eliminados. Suerte.
|
|
|
102
|
Informática / Hardware / Re: Imágenes y vídeos en mi USB están cifrados
|
en: 5 Marzo 2024, 05:19 am
|
Tengo un archivo llamado NTUSER.DAT en esa ubicación que indicas, que tendría que hacer con ella? ¿Pero el archivo reside en el directorio de la antigua cuenta de usuario, ¿no?, de lo contrario no sirve. De acuerdo, en ese caso entiendo que en tu PC quedan rastros, al menos del directorio del perfil de usuario de la cuenta "Alex". Ese archivo "NTUSER.DAT" contiene toda la rama del registro HKEY_CURRENT_USER de esa cuenta de usuario, incluyendo el SID, así que podría ser de utilidad para posibles soluciones como la sugerencia de @ Daniel sobre "clonar" esa cuenta de usuario, usando el mismo nombre exacto y el mismo SID, y a ver si con mucha suerte eso es suficiente para que puedas descifrar los archivos...
A continuación te detallo los pasos a seguir. Pero te advierto que todo esto es un planteamiento teoríco que he desarrollado, jamás lo he probado, así que puede acabar siendo de inutilidad. 1. Monta el archivo de colmena del registro "NTUSER.DAT" de la antigua cuenta de usuario de "Alex" usando el programa Regedit integrado en Windows, aunque puede que te sea más fácil usando el programa de terceros Registry Explorer ( https://ericzimmerman.github.io/#!index.md), y yo en este ejemplo es el programa que usaré. Simplemente haz click en la opción del menú: "File -> Load Hive" y cargas el archivo "NTUSER.DAT". Una vez que has montado la colmena, y para recuperar el SID de esa cuenta de usuario, ubica el valor "RecycleBin" de la clave HKEY_CURRENT_USER/Environment como en la siguiente imagen: Simplemente apunta esa cadena de texto que empieza por la letra "S". En mi caso sería: "S-1-5-21-4028340171-1815735104-1074574231-500" (A menos que hayas configurado de forma atípica las papeleras de reciclaje, lo de arriba te debería funcionar para obtener el SID.) 2.A continuación, carga el archivo de colmena "SECURITY" ubicado en: C:\Windows\System32\config, encuentra la clave que hace referecia al SID que apuntaste anteriormente, y en la subclave "sid" copia el contenido del valor que te muestro en la siguiente imagen: Para ello simplemente haz click derecho sobre el valor, selecciona la opción del menú: "Copy -> Value data" y el contenido del valor se enviará al porpapales de Windows (ya sabes, utiliza CONTROL+V para pegar lo copiado). En mi caso obtengo una cadena de texto como esta: 01-05-00-00-00-00-00-05-15-00-00-00-CB-97-1B-F0-40-EB-39-6C-97-B3-0C-40-F4-01-00-00 Pues bien, ahora reemplaza los guiones por comas, y quedará algo como esto: 01,05,00,00,00,00,00,05,15,00,00,00,CB,97,1B,F0,40,EB,39,6C,97,B3,0C,40,F4,01,00,00 Apúntate en algún sitio esa cadena de texto separada por comas. Notas: Obtener ese valor SID en Hexadecimal es esencial, por que no es simplemente una conversión a Hexadecimal, sino que además sigue un orden basado en la estructura que forman las partes de un valor SID. En teoría, teniendo unicamente el SID del paso anterior, me refiero, el que empieza por la letra "S", se puede desglosar su estructura para obtener este formato de SID en Hexadecimal, pero yo no tengo muy claro como y cual es el orden de ese formato para desglosar las partes del SID correctamente. Y el problema es que no estoy muy seguro de si tras los "ajustes de fábrica" realizados en tu PC quedarán rastros de estas claves necesarias para obtener el SID en formato Hexadecimal. Esperemos que si. 3. Para proseguir con el intento de clonación de cuenta de usuario, más adelante necesitaremos obtener permisos de escritura para una clave muy sensible del registro de Windows... Descárgate el programa de terceros por línea de comandos "SetACL" (no confundir con SetACL Studio): https://helgeklein.com/download/Y una vez descargado el programa y, DESDE UNA CUENTA DE USUARIO CON PRIVILEGIOS DE ADMINISTRADOR, abres un prompt de la CMD en el directorio donde se encuentre el archivo "SetACL.exe" y escribes el siguiente comando en la consola: SetACL.exe -on "HKEY_LOCAL_MACHINE\SECURITY\SAM\Domains\Account\Users" -ot "reg" -ace "n:%UserName%;p:full" -rec "Yes" -actn "ace" ( Si el comando te diese error entonces repite el procedimiento pero esta vez desde la cuenta integrada de Administrador de Windows. Para activar la cuenta integrada de Administrador escribe el siguiente comando en la CMD: net user administrator /active:yes , posteriormente inicias sesión en esa cuenta de Administrador y repites el comando de SetACL para modificar los permisos de esa clave de registro.) 4.Lo último que queda por hacer, a ver como lo simplifico para que no te suponga mucha dificultad.... Observa este código (es un script del Registro de Windows): Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\{SID}] "ProfileImagePath"=hex(2):{DIRECTORIO DE LA CUENTA DE USUARIO} "Flags"=dword:00000000 "State"=dword:00000004 "Sid"=hex:{SID HEXADECIMAL} "FullProfile"=dword:00000001 [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\ProfileList\{SID}] "ProfileImagePath"=hex(2):{DIRECTORIO DE LA CUENTA DE USUARIO} "Flags"=dword:00000000 "State"=dword:00000004 "Sid"=hex:{SID HEXADECIMAL} "FullProfile"=dword:00000001 [HKEY_LOCAL_MACHINE\SECURITY\SAM\Domains\Account\Users\Names\{NOMBRE DE USUARIO}] @=hex(9eb): [HKEY_LOCAL_MACHINE\SECURITY\SAM\Domains\Account\Users\000009EB] "F"=hex:03,00,01,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,cd,fb,4c,b5,a8,6e,da,01,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ eb,03,00,00,01,02,00,00,14,02,00,00,00,00,00,00,00,00,00,00,01,00,00,00,00,\ 00,00,00,00,00,00,00 "V"=hex:00,00,00,00,f4,00,00,00,03,00,01,00,f4,00,00,00,08,00,00,00,00,00,00,\ 00,fc,00,00,00,08,00,00,00,00,00,00,00,04,01,00,00,00,00,00,00,00,00,00,00,\ 04,01,00,00,00,00,00,00,00,00,00,00,04,01,00,00,00,00,00,00,00,00,00,00,04,\ 01,00,00,00,00,00,00,00,00,00,00,04,01,00,00,00,00,00,00,00,00,00,00,04,01,\ 00,00,00,00,00,00,00,00,00,00,04,01,00,00,00,00,00,00,00,00,00,00,04,01,00,\ 00,00,00,00,00,00,00,00,00,04,01,00,00,15,00,00,00,a8,00,00,00,1c,01,00,00,\ 08,00,00,00,01,00,00,00,24,01,00,00,18,00,00,00,00,00,00,00,3c,01,00,00,18,\ 00,00,00,00,00,00,00,54,01,00,00,18,00,00,00,00,00,00,00,6c,01,00,00,18,00,\ 00,00,00,00,00,00,01,00,14,80,d4,00,00,00,e4,00,00,00,14,00,00,00,44,00,00,\ 00,02,00,30,00,02,00,00,00,02,c0,14,00,44,00,05,01,01,01,00,00,00,00,00,01,\ 00,00,00,00,02,c0,14,00,ff,07,0f,00,01,01,00,00,00,00,00,05,07,00,00,00,02,\ 00,90,00,04,00,00,00,00,00,24,00,44,00,02,00,01,05,00,00,00,00,00,05,15,00,\ 00,00,cb,97,1b,f0,40,eb,39,6c,97,b3,0c,40,eb,03,00,00,00,00,38,00,1b,03,02,\ 00,01,0a,00,00,00,00,00,0f,03,00,00,00,00,04,00,00,de,a2,28,67,21,3e,d2,af,\ 19,ad,5d,79,b0,c1,07,29,27,56,fc,20,d8,ad,66,f6,10,f2,68,fa,df,2a,f8,0f,00,\ 00,18,00,ff,07,0f,00,01,02,00,00,00,00,00,05,20,00,00,00,20,02,00,00,00,00,\ 14,00,5b,03,02,00,01,01,00,00,00,00,00,01,00,00,00,00,01,02,00,00,00,00,00,\ 05,20,00,00,00,20,02,00,00,01,02,00,00,00,00,00,05,20,00,00,00,20,02,00,00,\ 41,00,6c,00,65,00,78,00,41,00,6c,00,65,00,78,00,ff,ff,ff,ff,ff,ff,ff,ff,ff,\ ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ff,ca,a7,80,01,02,00,00,07,00,00,00,02,00,\ 02,00,00,00,00,00,f3,f1,77,17,ad,ca,a7,80,b1,5a,7d,a0,d4,a9,55,6e,02,00,02,\ 00,00,00,00,00,2d,f6,ce,86,e6,76,c7,c4,6a,61,19,a9,ad,4a,1b,1a,02,00,02,00,\ 00,00,00,00,52,8d,4d,94,18,cf,0d,6a,53,db,8f,8c,3c,81,23,95,02,00,02,00,00,\ 00,00,00,17,79,7f,58,6e,de,ec,d8,70,2d,1b,b5,2f,f4,36,54 "UserTile"=-
Donde pone "{NOMBRE DE USUARIO}" debes colocar el nombre de la cuenta antigua cuenta de usuario de "Alex" (sin lo del paréntesis). Donde pone "{SID}" debes colocar el SID (el que empieza por la letra "S") de esa cuenta de usuario. Donde pone {DIRECTORIO DE LA CUENTA DE USUARIO} debe ir la ruta al directorio del perfil del usuario de "Alex" (por ejemplo: "C:\Users\Alex\") Y donde pone {SID HEXADECIMAL} debe ir el SID en hexadecimal separado por comas que apuntaste en el paso anterior. El valor de "{NOMBRE DE USUARIO}" y "{SID}" los puedes colocar directamente modificando ese código, pero los otros dos valores requieren una edición con un formato diferente. Por mostrarte un ejemplo real, parte del código se vería así: Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-5-21-4028340171-1815735104-1074574231-1003] "ProfileImagePath"=hex(2):43,00,3a,00,5c,00,55,00,73,00,65,00,72,00,73,00,5c,\ 00,41,00,6c,00,65,00,78,00,00,00 "Flags"=dword:00000000 "State"=dword:00000004 "Sid"=hex:01,05,00,00,00,00,00,05,15,00,00,00,cb,97,1b,f0,40,eb,39,6c,97,b3,0c,\ 40,eb,03,00,00 "FullProfile"=dword:00000001 [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-5-21-4028340171-1815735104-1074574231-1003] "ProfileImagePath"=hex(2):43,00,3a,00,5c,00,55,00,73,00,65,00,72,00,73,00,5c,\ 00,41,00,6c,00,65,00,78,00,00,00 "Flags"=dword:00000000 "State"=dword:00000004 "Sid"=hex:01,05,00,00,00,00,00,05,15,00,00,00,cb,97,1b,f0,40,eb,39,6c,97,b3,0c,\ 40,eb,03,00,00 "FullProfile"=dword:00000001
Creo que lo mejor es que cuando llegues a este punto, simplemente dime cual es el SID (el que empieza por la letra "S") y el SID separado por comas, y yo te modifico los valores del registro de forma adecuada para que finalmente ejecutes el script y a ver lo que acaba sucediendo... Pero me gustaría que comprobases si en las claves de registro HKEY_LOCAL_MACHINE\SECURITY\SAM\Domains\Account\Users y también en HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList quedasen rastros de la antigua cuenta de usuario de "Alex", más que nada para poder hacer las cosas intentando incrementar la probabilidad de éxito. Si quedasen rastros, exporta esas claves del registro y comparte el contenido del script del registro como yo he hecho.
Todos los pasos que mencioné anteriormente deberías probarlos en un "entorno seguro" como una máquina virtual (usando el programa de terceros VMWare Workstation Player, por ejemplo), aunque sinceramente creo que no es realmente necesario y lo único que podría pasar es que la solución no funcione. Pero bueno, no me hago responsable de un posible malfuncionamiento del sistema tras haber probado esta metodología teórica. En caso de que esto lo vayas a probar en una máquina virtual, puedes crea una nueva cuenta de usuario con nombre "Alex", o como se llamase tu antigua cuenta de usuario desde donde se cifraron los archivos, y le otorgas permisos de Administrador. Para administrar (crear, editar, borrar) cuentas de usuario de forma sencillita te sugiero utilizar el programa de terceros Quick User Manager ( https://www.carifred.com/quick_user_manager/). Si la creaste con cuenta de correo de Microsoft, hazlo con la misma cuenta de correo y mismo nombre, todo igual. Aténtamente, Elektro.
|
|
|
103
|
Sistemas Operativos / Windows / Re: ¿Cómo borrar el historial de archivos abiertos que se muestran en ventana Ejecutar?
|
en: 4 Marzo 2024, 17:52 pm
|
La lista MRU ( Most Recently Used) del diálogo "Ejecutar" se almacena en la clave de registro HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\RunMRU, por lo que una forma de eliminarlas como alternativa a recurrir a software de terceros es mediante el uso del siguiente comando que puedes utilizar en la CMD o en un batch-script: REG DELETE "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\RunMRU" /VA /F O también puedes guardar el contenido de este script del Registro de Windows en un archivo por nombre "RunMRU_Clean.reg" y ejecutarlo: RunMRU_Clean.regWindows Registry Editor Version 5.00 [-HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\RunMRU]
Las entradas adicionales que te aparecen al pulsar la tecla "F" pertenecen al historial de navegación de archivos de Internet Explorer. Este historial incluye entradas que se generan automáticamente al navegar por directorios y archivos en el Explorer de Windows. Puedes eliminar todas esas entradas desde el applet del Panel de Control por nombre "Opciones de Internet" (InetCpl.cpl): O también puedes hacerlo utilizando el siguiente comando: rundll32.exe InetCpl.cpl,ClearMyTracksByProcess 1
Aquí tienes más valores que puedes usar, aparte del "1", para la función ClearMyTracksByProcess del applet InetCpl.cpl: - superuser.com | ClearMyTracksByProcess - all options?Aténtamente, Elektro.
CCleaner tiene la opción de eliminar todos esos historiales. Y eso es verdad. ¿Quien quiere andarse con todas estas eliminaciones manuales pudiendo configurarlo mediante las opciones de limpieza del CCleaner?. Lo digo totalmente en serio, vamos, CCleaner + CCEnhancer + reglas de eliminación personalizadas resuelve la tediosa tarea de limpiar un sistema en profundidad. Estoy aquí para ayudar a resolver dudas, incluyendo enseñar este tipo de "trucos", pero lo recomendable sería usar CCleaner para estas cosas como indica @ Songoku.
|
|
|
104
|
Informática / Hardware / Re: Imágenes y vídeos en mi USB están cifrados
|
en: 4 Marzo 2024, 16:04 pm
|
Parece evidente que estamos hablando de archivos cifrados mediante EFS (Encrypting File System) de Windows. Yo en tu lugar y para evitar que esto se vuelva a repetir, deshabilitaría los servicios relacionados con EFS y adicionalmente los de BitLocker (cifrado de dispositivos enteros), y los caparía / eliminaría del sistema operativo, para siempre. Es lo que yo decidí hacer hace ya siglos.
La solución de "clonar" la cuenta de usuario en una VM es ingeniosa, pero no creo que sea suficiente con usar el mismo nombre de usuario, tampoco estoy seguro de ello, pero quiero pensar que para poder descifrar los archivos también debería ser necesario que la cuenta de usuario tenga el mismo identificador único (SID), y puede que otras cosas más. Se podría realizar una mejor "clonación" de la cuenta de usuario si tuvieras una copia de seguridad del archivo de colmena (HIVE) del registro de Windows del usuario en cuestión ("C:\Users\Alex\NTUSER.DAT").
En caso contrario, no creo que puedas recuperar esos archivos a menos que logres acceso a la cuenta de usuario desde la cual se cifraron.
He leído que si mueves o copias los archivos cifrados a un disco con formato FAT32 o exFAT, se pierde el cifrado. (¿Tu USB tiene formarto NTFS?). Pero imagino que esta operación habrá que realizarla desde la cuenta de usuario original desde donde se cifraron. Tampoco estoy totalmente seguro de ello.
Quizás otros usuarios te puedan brindar alguna posible solución poco convencional. No hagas nada por el momento y espera un poco a ver. Suerte.
Aténtamente, Elektro.
|
|
|
105
|
Programación / Scripting / [APORTE] [PowerShell] SetACL.exe | Get Full Registry Ownership
|
en: 4 Marzo 2024, 15:31 pm
|
El siguiente script desarrollado en PowerShell y dependiente del programa de terceros SetACL ( https://helgeklein.com/download/#), sirve para adquirir propiedad absoluta sobre todas las claves de registro del sistema, lo que puede servir en algunos escenarios de prueba (generalmente en máquinas virtuales), o de infecciones por malware. UTILIZAR ESTE SCRIPT BAJO SU PROPIA RESPONSABILIDAD, Y BAJO UNA CUENTA DE ADMINISTRADOR.
MODIFICAR LOS PERMISOS DE ALGUNAS CLAVES DEL REGISTRO DE WINDOWS PUEDE CONLLEVAR CONSECUENCIAS IMPREVISTAS QUE PROVOQUEN UN MALFUNCIONAMIENTO DEL SISTEMA OPERATIVO E IMPIDAN INICIAR SESIÓN DE USUARIO.
NO ME HAGO RESPONSABLE DE NADA.
<# =========================================================================================== | | | Functions | | | =========================================================================================== #> function Show-WelcomeScreen { Clear-Host Write-Output "" Write-Output " $($host.ui.RawUI.WindowTitle)" Write-Output " +====================================================================+" Write-Output " | |" Write-Output " | This script will take the ownership and ACE (Access Control Entry) |" Write-Output " | of all the registry keys and subkeys in the current computer, |" Write-Output " | giving full access and permissions for the current user. |" Write-Output " | |" Write-Output " +====================================================================+" Write-Output "" Write-Host " CHANGING THE OWNER AND PERMISSIONS COULD BREAK THINGS," -ForegroundColor Red Write-Host " SO PROCEED WITH CAUTION AND DO IT AT YOUR OWN RISK !!" -ForegroundColor Red Write-Output "" Write-Output " CURRENT SCRIPT CONFIG:" Write-Output " ----------------------" Write-Output " -SetAclFilePath: $SetAclFilePath" Write-Output " -UserName......: $UserName" Write-Output " -RegKeys.......:" Write-Output ($RegKeys | ForEach-Object {" $_"}) Write-Output "" } function Confirm-Continue { Write-Host " Press 'Y' key to continue or 'N' to exit." Write-Host "" Write-Host " -Continue? (Y/N)" do { $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") $char = $key.Character.ToString().ToUpper() if ($char -ne "Y" -and $char -ne "N") { [console]::beep(1500, 500) } } while ($char -ne "Y" -and $char -ne "N") if ($char -eq "N") {Exit(1)} else {Clear-Host} } function Get-RegistryOwnership { param( [string]$setAclFilePath = "$env:ProgramFiles\SetACL\setacl.exe", [string[]]$regKeys, [string]$userName = "$env:UserName" ) try { if (-not (Test-Path $setAclFilePath)) { $ex = New-Object System.IO.FileNotFoundException("SetACL.exe file not found at path '$setAclFilePath'.", $setAclFilePath) throw $ex } $logFile = New-TemporaryFile foreach ($key in $regKeys) { Start-Process -Wait -FilePath "$setAclFilePath" -ArgumentList "-on", "`"$key`"", "-ot", "reg", "-actn", "setowner", "-ownr", "`"n:$userName`"", "-rec", "Yes", "-actn", "ace", "-ace", "`"n:$userName;p:full`"", "-rec", "Yes", "-log", "`"$($logFile.FullName)`"" -NoNewWindow -PassThru #$logContent = Get-Content -Path $logFile.FullName Write-Output "" #Write-Output $logContent } } catch { Write-Host "Something went wrong when calling '$($MyInvocation.MyCommand.Name)' method:" Write-Host "" Write-Warning ($_.Exception) Write-Host "" Write-Error -Message ($_.Exception | Format-List * -Force | Out-String) Write-Host "" Write-Host "Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown") Exit(1) } } function Show-GoodbyeScreen { Write-Host "Operation Completed!" -BackgroundColor Black -ForegroundColor Green Write-Host "" Write-Host "Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown") Exit(0) } <# =========================================================================================== | | | Main | | | =========================================================================================== #> [System.Console]::Title = "Get Full Registry Ownership Tool - by Elektro" [CultureInfo]::CurrentUICulture = "en-US" $SetAclFilePath = "$env:ProgramFiles\SetACL\SetACL.exe" $RegKeys = "HKEY_CLASSES_ROOT", "HKEY_CURRENT_USER", "HKEY_LOCAL_MACHINE", "HKEY_USERS", "HKEY_CURRENT_CONFIG" $UserName = $env:UserName try { Set-ExecutionPolicy -ExecutionPolicy "Unrestricted" -Scope "Process" } catch { } Show-WelcomeScreen Confirm-Continue Get-RegistryOwnership -SetAclFilePath $SetAclFilePath -RegKeys $RegKeys -UserName $UserName Show-GoodbyeScreen
|
|
|
106
|
Programación / Scripting / [APORTE] [PowerShell] Automated AppX Package Installer
|
en: 4 Marzo 2024, 15:19 pm
|
El siguiente script desarrollado en Powershell, buscará archivos de paquetes AppX (*.appx, *.appxbundle, *.msixbundle) dentro del directorio actual (sin recursividad), imprimirá información sobre el paquete, imprimirá un mensaje en caso de que el paquete ya esté instalado, e instalará el paquete en caso de que no esté instalado, manejando posibles errores durante instalación. Es una herramienta muy útil en particular para quien (como yo) tenga completamente capada la Microsoft Store y sus funcionalidades en el sistema operativo, y necesite una forma de poder instalar paquetes de aplicaciones (*.appx, *.appxbundle, *.msixbundle) descargadas de forma local desde la Microsoft Store.
# --------------------------------------------- # # Automated AppX Package Installer - by Elektro # # --------------------------------------------- # # This script will find any AppX package files within the current directory (without recursion), # print info about the package, print a message in case of the package is already installed, # and install the package in case of it is not installed, handling errors during installation. # --------------------------------------------------------------------- # Takes a string argument that points to an AppX package name or file, # then it uses a regular expression to match the package string pattern # and returns a custom object with the Name, Version, Architecture, # PublisherId and other properties. # # Parameters: # -PackageString: A string that points to the file name # or full path of an AppX package file. # # Returns: # A PSCustomObject object with these properties defined: # [String] Name # [String] Version # [String] Architecture # [String] PublisherId # [String] FullName function Get-AppXPackageInfo { param ( [Parameter(Mandatory=$true)] [string]$PackageString ) #$dirname = [System.IO.Path]::GetDirectoryName($PackageString) #if ([string]::IsNullOrEmpty($dirname)) { # $dirname = $PWD #} $filename = [System.IO.Path]::GetFileName($PackageString) -replace "(?i)\.appxbundle$", "" -replace "(?i)\.msixbundle$", "" -replace "(?i)\.appx$", "" $regex = '^(?<Name>.+?)_(?<Version>.+?)_(?<Architecture>.+?)_(?<chars>~)?_(?<PublisherId>.+)$' $match = $filename -match $regex if (!$match) { throw "Unable to parse the string package: '$PackageString'" } [string]$packageName = $matches['Name'] [string]$packageVersion = $matches['Version'] [string]$packageArchitecture = $matches['Architecture'] [string]$packagePublisherId = $matches['PublisherId'] [string]$chars = $matches['chars'] [string]$packageFullName = "${packageName}_${packageVersion}_${packageArchitecture}_${chars}_${packagePublisherId}" #[string]$packageFullPath = [System.IO.Path]::Combine($dirname, "$filename.Appx") [PSCustomObject]@{ Name = $packageName Version = $packageVersion Architecture = $packageArchitecture PublisherId = $packagePublisherId FullName = $packageFullName #FullPath = $packageFullPath } } # Determines whether an Appx package matching the specified # name, version and architecture is installed in the system. # # Parameters: # -Name........: The package name. # -Version.....: The package version. # -Architecture: The package architecture ("x86", "x64"). # # Returns: # $true if the AppX package is installed in the system, # $false otherwise. function IsAppxPackageInstalled() { param ( [Parameter(Mandatory=$true)] [string]$name, [Parameter(Mandatory=$true)] [string]$version, [Parameter(Mandatory=$true)] [string]$architecture ) if ($architecture -eq "neutral") { $architecture = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture } $packages = Get-AppxPackage "$($name)*" -ErrorAction Stop | Where-Object { $_.Name.ToLower() -eq $name.ToLower() -and $_.Version.ToLower() -eq $version.ToLower() -and "$($_.Architecture)".ToLower() -eq $architecture.ToLower() } return ($packages.Count -gt 0) } <# =========================================================================================== | | | Main | | | =========================================================================================== #> [System.Console]::Title = "Automated AppX Package Installer - by Elektro" [CultureInfo]::CurrentUICulture = "en-US" try { Set-ExecutionPolicy -ExecutionPolicy "Unrestricted" -Scope "Process" } catch { } # Hides the progress-bar for 'Add-AppxPackage' cmdlet in this script. # Thanks to @Santiago Squarzon for the tip: https://stackoverflow.com/questions/75716867 # https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-7.3#progresspreference $ProgressPreference = "Ignore" Do { Clear-Host Write-Output "" Write-Output " $($host.ui.RawUI.WindowTitle)" Write-Output " +=====================================================+" Write-Output " | |" Write-Output " | This script will find any AppX package files |" Write-Output " | within the current directory (without recursion), |" Write-Output " | print info about the package, print a message |" Write-Output " | in case of the package is already installed, |" Write-Output " | and install the package in case of it is |" Write-Output " | not installed, handling errors during installation. |" Write-Output " | |" Write-Output " +=====================================================+" Write-Output "" Write-Host " -Continue? (Y/N)" $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") $char = $key.Character.ToString().ToUpper() if ($char -ne "Y" -and $char -ne "N") { [console]::beep(1500, 500) } } while ($char -ne "Y" -and $char -ne "N") if ($char -eq "N") {Exit(1)} else {Clear-Host} $appxFiles = Get-ChildItem -Path "$PWD" -Filter "*.appx*" if ($appxFiles.Count -eq 0) { Write-Warning "No Appx files were found in the current directory." Write-Host "" $LastExitCode = 2 } else { $appxFiles | ForEach-Object { # The AppX package string. It can be a file name (with or without extension), or a full path. $packageString = $_.FullName $packageInfo = Get-AppXPackageInfo -PackageString $packageString $nameVerArch = "$($packageInfo.Name) v$($packageInfo.Version) ($($packageInfo.Architecture))" Write-Host "Package Info.:" -ForegroundColor Gray Write-Host ($packageInfo | Format-List | Out-String).Trim() -ForegroundColor DarkGray Write-Host "" $isInstalled = IsAppxPackageInstalled -Name $packageInfo.Name -Version $packageInfo.Version -Architecture $packageInfo.Architecture if ($isInstalled) { Write-Warning "Package $nameVerArch is already installed." Write-Warning "Installation is not needed." } else { Write-Host "Package $nameVerArch is ready to install." Write-Host "Installing package..." try { Add-AppxPackage -Path "$($_.FullName)" -ErrorAction Stop Write-Host "Package $nameVerArch has been successfully installed." -BackgroundColor Black -ForegroundColor Green } catch { Write-Host "Error installing package $nameVerArch" -BackgroundColor Black -ForegroundColor Red Write-Host "" Write-Error -Message ($_.Exception | Format-List * -Force | Out-String) $LastExitCode = 1 Break } } Write-Host "" $LastExitCode = 0 } } Write-Host "Program will terminate now with exit code $LastExitCode. Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") Exit($LastExitCode)
|
|
|
107
|
Programación / Scripting / [APORTE] [PowerShell] Remove Windows Installer product registration for missing MSI packages
|
en: 4 Marzo 2024, 15:10 pm
|
El siguiente script desarrollado en Powershell sirve para realizar un tipo de limpieza que CCleaner y limpiadores especializados del registro (como por ejemplo Wise Registry Cleaner) no pueden llevar a cabo: Limpiar todo rastro, en el registro de Windows, de entradas a instaladores MSI que no se encuentren presentes en el sistema o que simplemente den conflictos pos fallas de instalación o desinstalación. Es magia pura para solucionar cierto tipo de problemas relacionados con entradas de registro de paquetes MSI huérfanos. Autor del código original: https://gist.github.com/heaths/77fbe0b44496960fab25c2eb0b9e8475#Requires -Version 3 # https://gist.github.com/heaths/77fbe0b44496960fab25c2eb0b9e8475 [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter(Position = 0, ValueFromPipeline = $true)] [ValidateNotNullOrEmpty()] [string[]] $ProductCode ) [System.Console]::Title = "Remove Windows Installer product registration for missing MSI packages" [CultureInfo]::CurrentUICulture = "en-US" try { Set-ExecutionPolicy -ExecutionPolicy "Unrestricted" -Scope "Process" } catch { } $ErrorActionPreference = 'Stop' [int[]] $translation = 7,6,5,4,3,2,1,0,11,10,9,8,15,14,13,12,17,16,19,18,21,20,23,22,25,24,27,26,29,28,31,30 $loc = data { ConvertFrom-StringData @' Error_Elevation_Required = You must run this script in an elevated command prompt Error_64Bit_Required = You must run this in a 64-bit command prompt Error_PackageManagement_Required = Please install PackageManagement from http://go.microsoft.com/fwlink/?LinkID=746217 Process_Remove_Args1 = Remove registration for {0} Verbose_Install_MSI = Installing the "MSI" module Verbose_Scan_Missing = Scanning for products missing cached packages Verbose_Remove_Key_Args1 = Removing key : {0} Verbose_Remove_Value_Args2 = Removing value: {0}\\{1} Verbose_Remove_Source_Reg = Removing source registration Verbose_Remove_Product_Reg = Removing product registration Verbose_Remove_Upgrade_Reg = Removing upgrade registration Verbose_Remove_Component_Reg = Removing component registration Verbose_Found_Source_Args2 = Cache missing for {0} but found source at {1} '@ } $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object System.Security.Principal.WindowsPrincipal $identity if (!$principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) { throw $loc.Error_Elevation_Required } if ([System.Environment]::Is64BitOperatingSystem) { if (![System.Environment]::Is64BitProcess) { throw $loc.Error_64Bit_Required } } $pack = { param ( [string] $Guid ) if (!$Guid) { return } $Guid = (New-Object System.Guid $Guid).ToString("N").ToUpperInvariant() $sb = New-Object System.Text.StringBuilder $translation.Count foreach ($i in $translation) { $null = $sb.Append($Guid[$i]) } $sb.ToString() } $test = { param ( $Product ) if ($Product.PSPath -and ($Product | Test-Path)) { return $true } if ($Product.PackageName) { $Product | Get-MSISource | ForEach-Object { $path = Join-Path $_.Path $Product.PackageName if ($path | Test-Path) { Write-Host ($loc.Verbose_Found_Source_Args2 -f $Product.ProductCode, $path) return $true } } } $false } $remove = { param ( [string] $Key ) if (Test-Path $Key) { Write-Host ($loc.Verbose_Remove_Key_Args1 -f $Key) Remove-Item -Recurse -Force $Key } } $removeChild = { param ( [string] $Key, [string] $Name ) if (Test-Path $Key) { Get-ChildItem $Key | ForEach-Object { $obj = $_ | Get-ItemProperty if ($obj.$Name -ne $null) { Write-Host ($loc.Verbose_Remove_Value_Args2 -f $_.Name, $Name) Remove-ItemProperty -Force -Name $Name -LiteralPath $_.PSPath $obj = Get-ItemProperty -LiteralPath $_.PSPath if (!$obj) { Write-Host ($loc.Verbose_Remove_Key_Args1 -f $_.Name) Remove-Item -Recurse -Force -LiteralPath $_.PSPath } } } } } if (!$ProductCode) { # Install the MSI module if missing. if (!(Get-Module -ListAvailable MSI)) { Write-Host $loc.Verbose_Install_MSI # Make sure PackageManagement is installed (comes with WMF 5.0 / Windows 10). if (!(Get-Module -ListAvailable PackageManagement)) { throw $loc.Error_PackageManagement_Required } Install-Module MSI -Scope CurrentUser -SkipPublisherCheck -Force } Write-Host $loc.Verbose_Scan_Missing foreach ($msi in (Get-MSIProductInfo -UserContext Machine)) { if (!(&$test $msi)) { $ProductCode += $msi.ProductCode } } } foreach ($code in $ProductCode) { if ($PSCmdlet.ShouldProcess($msi, $loc.Process_Remove_Args1 -f $code)) { $packedProductCode = &$pack $code Write-Host $loc.Verbose_Remove_Source_Reg &$remove "Registry::HKCL\SOFTWARE\Classes\Installer\Products\$packedProductCode" &$remove "Registry::HKCL\SOFTWARE\Classes\Installer\Features\$packedProductCode" &$remove "Registry::HKLM\SOFTWARE\Classes\Installer\Products\$packedProductCode" &$remove "Registry::HKLM\SOFTWARE\Classes\Installer\Features\$packedProductCode" Write-Host $loc.Verbose_Remove_Product_Reg &$remove "Registry::HKCL\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\$packedProductCode" &$remove "Registry::HKCL\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$code" &$remove "Registry::HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\$packedProductCode" &$remove "Registry::HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$code" &$remove "Registry::HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\$code" Write-Host $loc.Verbose_Remove_Upgrade_Reg &$removeChild "Registry::HKCL\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes" $packedProductCode &$removeChild "Registry::HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes" $packedProductCode Write-Host $loc.Verbose_Remove_Component_Reg &$removeChild "Registry::HKCL\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components" $packedProductCode &$removeChild "Registry::HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components" $packedProductCode } } Write-Host "Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") Exit(0) <# .SYNOPSIS Removes Windows Installer product registrtation for missing or specified MSIs .DESCRIPTION If Windows Installer product registration is corrupt (exit code 1610) or package sources are missing (exit code 1603, error message 1714; or exit code 1612), you can use this script in an elevated PowerShell command shell to clean up the registration is a transactional manner to avoid making machine state worse. Please note that this should be a last resort and only for those issues above. The old msizap.exe program was frought with issues and can make matters worse if not used properly. .PARAMETER ProductCode Optional list of ProductCode to clean up; otherwise, ProductCodes are scanned from products with missing sources. .EXAMPLE PS> Unregister-MissingMSIs.ps1 Removes per-machine product registration for products with missing cached MSIs. .EXAMPLE PS> Unregister-MissingMSIs.ps1 '{7B88D6BB-A664-4E5A-AB81-C435C8639A4D}' Remove per-machine product registration for the specified ProductCode only. #>
|
|
|
108
|
Programación / Scripting / [APORTE] [BATCH] FFMPEG | Convert Video to MP4 - Sony Vegas Compatible
|
en: 4 Marzo 2024, 14:59 pm
|
El siguiente Batch-script, dependiente del programa de terceros FFMPEG, tiene la función de convertir un archivo de video (por lo general, MKV) a un formato MP4 que será compatible para la edición del video en los productos de Sony VEGAS.
@Echo OFF & CHCP 1252 >NUL & Title FFMPEG Convert Video to MP4 - Sony Vegas Compatible - Tool by Elektro ECHO: This script will convert the source video file ECHO: to a MP4 video compatible with Sony Vegas. ECHO: YOU MUST DROP A MKV FILE TO THIS BATCH-FILE. ) ECHO: Output file: " %~dpn1_VEGAS.mp4" CHOICE /C YN /M "Continue?" CLS ) ) ::::::::::::::::::::::::::::::::::::::::::::::::::::::: REM How to encode Vegas-compatible H.264 file using FFmpeg: REM http://www.konstantindmitriev.ru/blog/2014/03/02/how-to-encode-vegas-compatible-h-264-file-using-ffmpeg/ ECHO+Choose a encoding preset: ECHO+ [6] medium – default preset CHOICE /C "0123456789" /M "" IF %ERRORLEVEL% EQU 2 (SET "preset=ultrafast" ) IF %ERRORLEVEL% EQU 3 (SET "preset=superfast" ) IF %ERRORLEVEL% EQU 4 (SET "preset=veryfast" ) IF %ERRORLEVEL% EQU 5 (SET "preset=faster" ) IF %ERRORLEVEL% EQU 6 (SET "preset=fast" ) IF %ERRORLEVEL% EQU 7 (SET "preset=medium" ) IF %ERRORLEVEL% EQU 8 (SET "preset=slow" ) IF %ERRORLEVEL% EQU 9 (SET "preset=slower" ) IF %ERRORLEVEL% EQU 10 (SET "preset=veryslow" ) :: SET "forcedFPS=-r 23.976" CLS "%~dp0ffmpeg.exe" %forcedFPS% -y -loglevel info -i "%~1" -c:v libx264 -preset %preset% -crf 23 -c:a aac -strict experimental -tune fastdecode -pix_fmt yuv420p -b:a 192k -ar 48000 %forcedFPS% "%~n1_VEGAS.mp4" CLS Color A Echo: Video conversion completed successfully. | MORE | MORE Echo: Input.: " %~1" | MORE Echo: Output: " %~dpn1_VEGAS.mp4" | MORE Color C Echo: Video conversion completed with errors. | MORE | MORE Echo: Input.: " %~1" | MORE Echo: Output: " %~dpn1_VEGAS.mp4" | MORE )
|
|
|
109
|
Programación / Scripting / [APORTE] [PowerShell] IrfanView | Crop image files
|
en: 4 Marzo 2024, 14:48 pm
|
El siguiente script desarrollado en PowerShell y dependiente del programa de terceros IrfanView, sirve para hacer un recorte ( crop) específico en los archivos de imagen del directorio actual. En la sección "Variables" dentro del script pueden personalizar los puntos de recorte (x, y, width, height), así como la calidad de codificación para archivos JPG entre otras cosas configurables.
<# =========================================================================================== | | | Variables | | | =========================================================================================== #> $inputDirectoryPath = "$PSScriptRoot" $fileNameSearchPattern = "*.*" $imageExts = @("avif", "bmp", "jp2", "jpg", "png", "tga", "tif", "webp") $recurse = $false $irfanviewFullPath = "C:\Program Files\IrfanView\i_view64.exe" # Cropping values $x = 12 $y = 20 $width = 620 $height = 560 # For cropping images that are jpg/jpeg $jpgQuality = 95 <# =========================================================================================== | | | Functions | | | =========================================================================================== #> function Show-WelcomeScreen { Clear-Host Write-Host "" Write-Host " $($host.ui.RawUI.WindowTitle)" Write-Host " +=========================================+" Write-Host " | |" Write-Host " | This script will search for image files |" Write-Host " | in the current working directory, and |" Write-Host " | use IrfanView to crop them using the |" Write-Host " | specified cropping settings. |" Write-Host " | |" Write-Host " +=========================================+" Write-Host "" Write-Host " Script Settings " -ForegroundColor DarkGray Write-Host " ========================" -ForegroundColor DarkGray Write-Host " Input Directory Path....: $inputDirectoryPath" -ForegroundColor DarkGray Write-Host " Recursive File Search...: $recurse" -ForegroundColor DarkGray Write-Host " Search File Name Pattern: $fileNameSearchPattern" -ForegroundColor DarkGray Write-Host " Search File Extensions..: $($imageExts -join ', ')" -ForegroundColor DarkGray Write-Host " IrfanView Full Path.....: $irfanviewFullPath" -ForegroundColor DarkGray Write-Host " JPG Quality.............: $jpgQuality%" -ForegroundColor DarkGray Write-Host " Cropping.values.........: X=$x, Y=$y, Width=$width, Height=$height" -ForegroundColor DarkGray Write-Host "" } function Confirm-Continue { Write-Host " Press 'Y' key to continue or 'N' to exit." Write-Host "" Write-Host " -Continue? (Y/N)" do { $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") $char = $key.Character.ToString().ToUpper() if ($char -ne "Y" -and $char -ne "N") { [console]::beep(1500, 500) } } while ($char -ne "Y" -and $char -ne "N") if ($char -eq "N") {Exit(1)} } function Validate-Parameters { if (-not (Test-Path -LiteralPath $inputDirectoryPath -PathType Container)) { Write-Host " Input directory path does not exists!" -BackgroundColor Black -ForegroundColor Red Write-Host "" Write-Host " Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown") Exit(1) } if (-not (Test-Path -LiteralPath $irfanviewFullPath -PathType Leaf)) { Write-Host " Irfanview file path does not exists!" -BackgroundColor Black -ForegroundColor Red Write-Host "" Write-Host " Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown") Exit(1) } if ($imageExts.Count -eq 0) { Write-Host " No image file extensions were specified!" -BackgroundColor Black -ForegroundColor Red Write-Host "" Write-Host " Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown") Exit(1) } } function Crop-Files { Clear-Host $imageFiles = $null if ($recurse) { $imageFiles = Get-ChildItem -LiteralPath $inputDirectoryPath -Filter $fileNameSearchPattern -Recurse | Where-Object { $imageExts -contains $_.Extension.ToLower().TrimStart('.') } } else { $imageFiles = Get-ChildItem -LiteralPath $inputDirectoryPath -Filter $fileNameSearchPattern | Where-Object { $imageExts -contains $_.Extension.ToLower().TrimStart('.') } } foreach ($imageFile in $imageFiles) { Write-Host " Cropping file: $($imageFile.FullName.Replace($inputDirectoryPath, "."))" $exitCode = $null try { $process = New-Object System.Diagnostics.Process $process.StartInfo.FileName = $irfanviewFullPath $process.StartInfo.Arguments = "`"$($imageFile.FullName)`" /crop=($x,$y,$width,$height) /jpgq=$jpgQuality /convert=""$($imageFile.FullName)""" $process.StartInfo.UseShellExecute = $false $started = $process.Start() | Out-Null $exited = $process.WaitForExit() $exitCode = $process.ExitCode } catch { Write-Host "" Write-Host " Error running IrfanView process." -BackgroundColor Black -ForegroundColor Red Write-Host "" Write-Error -Message ($_.Exception.Message) Write-Host "" Write-Host " Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown") Exit(1) } if ($exitCode -eq 0) { Write-Host " File cropped successfully." -ForegroundColor DarkGreen Write-Host "" } else { Write-Host " Error cropping file. IrfanView Exit Code: $exitCode" -BackgroundColor Black -ForegroundColor Red Write-Host "" Write-Host " Press any key to ignore and continue..." $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown") } } } function Show-GoodbyeScreen { Write-Host " Operation Completed!" -BackgroundColor Black -ForegroundColor Green Write-Host "" Write-Host " Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown") Exit(0) } <# =========================================================================================== | | | Main | | | =========================================================================================== #> [System.Console]::Title = "Crop image files - by Elektro" #[System.Console]::SetWindowSize(146, 27) [CultureInfo]::CurrentUICulture = "en-US" try { Set-ExecutionPolicy -ExecutionPolicy "Unrestricted" -Scope "Process" } catch { } Show-WelcomeScreen Validate-Parameters Confirm-Continue Crop-Files Show-GoodbyeScreen
|
|
|
110
|
Programación / Scripting / [APORTE] [PowerShell] IrfanView | Convert image files to JPG
|
en: 4 Marzo 2024, 14:45 pm
|
El siguiente script desarrollado en PowerShell y dependiente del programa de terceros IrfanView, sirve para convertir todos los archivos de imagen del directorio actual, a formato JPG. En la sección "Variables" dentro del script pueden personalizar la calidad de codificación JPG y los tipos de archivos de imagen a procesar entre otras cosas configurables.
<# =========================================================================================== | | | Variables | | | =========================================================================================== #> $inputDirectoryPath = "$PSScriptRoot" $fileNameSearchPattern = "*.*" $imageExts = @("avif", "bmp", "jp2", "jpg", "png", "tga", "tif", "webp") $recurse = $false $irfanviewFullPath = "C:\Program Files\IrfanView\i_view64.exe" $jpgQuality = 95 $overwriteConfirm = $true $sendToRecycleBinConvertedFiles = $true <# =========================================================================================== | | | Functions | | | =========================================================================================== #> function Show-WelcomeScreen { Clear-Host Write-Host "" Write-Host " $($host.ui.RawUI.WindowTitle)" Write-Host " +===========================================+" Write-Host " | |" Write-Host " | This script will search for image files |" Write-Host " | in the current working directory, and use |" Write-Host " | IrfanView to convert them to JPG format. |" Write-Host " | |" Write-Host " +===========================================+" Write-Host "" Write-Host " Script Settings " -ForegroundColor DarkGray Write-Host " ========================" -ForegroundColor DarkGray Write-Host " Input Directory Path....: $inputDirectoryPath" -ForegroundColor DarkGray Write-Host " Recursive File Search...: $recurse" -ForegroundColor DarkGray Write-Host " Search File Name Pattern: $fileNameSearchPattern" -ForegroundColor DarkGray Write-Host " Search File Extensions..: $($imageExts -join ', ')" -ForegroundColor DarkGray Write-Host " IrfanView Full Path.....: $irfanviewFullPath" -ForegroundColor DarkGray Write-Host " JPG Quality.............: $jpgQuality%" -ForegroundColor DarkGray Write-Host " Confirm Overwrite JPG...: $overwriteConfirm" -ForegroundColor DarkGray Write-Host " Recycle Converted Files.: $sendToRecycleBinConvertedFiles" -ForegroundColor DarkGray Write-Host "" } function Confirm-Continue { Write-Host " Press 'Y' key to continue or 'N' to exit." Write-Host "" Write-Host " -Continue? (Y/N)" do { $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") $char = $key.Character.ToString().ToUpper() if ($char -ne "Y" -and $char -ne "N") { [console]::beep(1500, 500) } } while ($char -ne "Y" -and $char -ne "N") if ($char -eq "N") {Exit(1)} } function Validate-Parameters { if (-not (Test-Path -LiteralPath $inputDirectoryPath -PathType Container)) { Write-Host " Input directory path does not exists!" -BackgroundColor Black -ForegroundColor Red Write-Host "" Write-Host " Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown") Exit(1) } if (-not (Test-Path -LiteralPath $irfanviewFullPath -PathType Leaf)) { Write-Host " Irfanview file path does not exists!" -BackgroundColor Black -ForegroundColor Red Write-Host "" Write-Host " Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown") Exit(1) } if ($imageExts.Count -eq 0) { Write-Host " No image file extensions were specified!" -BackgroundColor Black -ForegroundColor Red Write-Host "" Write-Host " Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown") Exit(1) } } function Convert-Files { Clear-Host Add-Type -AssemblyName Microsoft.VisualBasic $imageFiles = $null if ($recurse) { $imageFiles = Get-ChildItem -LiteralPath $inputDirectoryPath -Filter $fileNameSearchPattern -Recurse | Where-Object { $imageExts -contains $_.Extension.ToLower().TrimStart('.') } } else { $imageFiles = Get-ChildItem -LiteralPath $inputDirectoryPath -Filter $fileNameSearchPattern | Where-Object { $imageExts -contains $_.Extension.ToLower().TrimStart('.') } } foreach ($imageFile in $imageFiles) { Write-Host " Converting to JPG: $($imageFile.FullName.Replace($inputDirectoryPath, "."))" $fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($imageFile.Name) $outputFilePath = Join-Path -Path ($imageFile.Directory.FullName) -ChildPath "$fileNameWithoutExtension.jpg" if ((Test-Path -LiteralPath $outputFilePath -PathType Leaf) -and ($overwriteConfirm)) { # El archivo no existe o no se debe sobrescribir Write-Warning " Output JPG file already exists but `$overwriteConfirm variable is disabled." Write-Warning " The output JPG file will be overwitten if you continue." Write-Host "" Confirm-Continue Write-Host "" } $exitCode = $null try { $procStartInfo = New-Object System.Diagnostics.ProcessStartInfo $procStartInfo.FileName = $irfanviewFullPath $procStartInfo.Arguments = "`"$($imageFile.FullName)`" /jpgq=$jpgQuality /convert=`"$outputFilePath`"" $procStartInfo.UseShellExecute = $false $process = New-Object System.Diagnostics.Process $process.StartInfo = $procStartInfo $process.Start() | Out-Null $process.WaitForExit() $exitCode = $process.ExitCode } catch { Write-Host "" Write-Host " Error running IrfanView process." -BackgroundColor Black -ForegroundColor Red Write-Host "" Write-Error -Message ($_.Exception.Message) Write-Host "" Write-Host " Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown") Exit(1) } if ($exitCode -eq 0) { Write-Host " File converted successfully." -ForegroundColor DarkGreen if ($sendToRecycleBinConvertedFiles) { [Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile($imageFile.FullName, 'OnlyErrorDialogs', 'SendToRecycleBin') Write-Host " File sent to recycle bin." -ForegroundColor DarkGray } Write-Host "" } else { Write-Host " Error converting file to JPG. IrfanView Exit Code: $exitCode" -BackgroundColor Black -ForegroundColor Red Write-Host "" } } } function Show-GoodbyeScreen { Write-Host " Operation Completed!" -BackgroundColor Black -ForegroundColor Green Write-Host "" Write-Host " Press any key to exit..." $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown") Exit(0) } <# =========================================================================================== | | | Main | | | =========================================================================================== #> [System.Console]::Title = "Convert image files to JPG - by Elektro" #[System.Console]::SetWindowSize(146, 27) [CultureInfo]::CurrentUICulture = "en-US" try { Set-ExecutionPolicy -ExecutionPolicy "Unrestricted" -Scope "Process" } catch { } Show-WelcomeScreen Validate-Parameters Confirm-Continue Convert-Files Show-GoodbyeScreen
|
|
|
|
|
|
|