elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.


Tema destacado: Security Series.XSS. [Cross Site Scripting]


  Mostrar Temas
Páginas: [1] 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ... 107
1  Foros Generales / Sugerencias y dudas sobre el Foro / Hilo borrado (¿por error?): sugar daddy en: 30 Junio 2025, 00:23 am
¡Hola! Abro esta cuestión por que no puedo usar el botón 'reportar' en un tema de la papelera.

Me he fijado que se ha "reciclado" un hilo titulado "8.500 universitarias buscan su 'sugar daddy': "No es prostitución, es dar un braguetazo"...

Me pregunto si esto es un error, por que si es algo deliberado honestamente no lo entendería, ya que considero que solamente se debería haber eliminado el último comentario, es decir el del bot, pero no el hilo entero, y menos todavía siendo del año 2021 (incapaz de generar polémica ni impacto negativo en el foro a estas alturas) y de un grandísimo colaborador y persona como es Machacador, quien no se merece un hilo borrado sin motivo razonable.

Por mi parte cierro este hilo para evitar que se malinterpreten mis intenciones, sin embargo, esta vez sí, lo dejo deliberadamente sin "reciclar" (no veo la necesidad de hacerlo, a menos que alguien esté interesado en tapar algo impidiendo que los usuarios como yo podamos hacer preguntas en público que puedan cuestionar ciertas acciones que nos parezcan incorrectas, aunque lo hagamos por no conocer los detalles exactos de esa decisión).

No sé si compartirán mi opinión. Bueno, por eso estoy escribiendo esto, por que a mi me parece un error, ya sea un error humano o un error de criterio. Solo lo comento por si acaso realmente es un error humano; No voy a intentar combatir la decisión de un moderador/staff, aunque me parecería muy mal, ya que el hilo en vez de eliminarlo se podría haber bloqueado, eso sería la opción menos perjudicial y sería igual de efectivo: no habría más bots "rastreando" y respondiendo a ese hilo en el futuro.

Atentamente,
Elektro.
2  Foros Generales / Dudas Generales / Consulta sobre bloqueo de usuarios en Telegram en: 27 Junio 2025, 01:50 am
Tengo una duda general sobre Telegram.

Si estoy chateando con alguien y después de unos 30 minutos reviso el chat y me aparece el mensaje "Visto por última vez hace mucho tiempo" como se muestra en esta imagen:



Y además ya no me aparece su foto de perfil / avatar…

¿Eso significa que esa persona me ha bloqueado?.

Pero a esa persona yo todavía puedo enviarle mensajes, y Telegram no me muestra ninguna notificación que me indique que me han bloqueado. Por eso me resulta confuso, y quería saber si realmente eso es señal de un bloqueo.

Quizás la pregunta que en realidad debería hacer sea: ¿cuando una persona te bloquea en Telegram puedes seguir enviándole mensajes? (aunque obviamente, en caso de ser así, esos mensajes no los recibirá)

Atentamente,
Elektro.
3  Programación / Scripting / [APORTE] [Bash] Instalador completo de compatibilidad Windows en Linux (con Wine) en: 8 Junio 2025, 13:12 pm
Instalador automatizado de compatibilidad Windows en Linux (con Wine)

Este script Bash automatiza completamente la habilitación e integración de compatibilidad con aplicaciones de Windows en sistemas Linux, incluyendo:

  • Instalación de Wine y sus dependencias.
  • Interfaz gráfica para Wine.
  • Asociación automática de archivos .exe en el gestor de archivos.
  • Generación automática de iconos (miniaturas) para ejecutables de Windows.
  • Fuentes TrueType de Windows.
  • Runtimes de Visual Basic,Visual C++, .NET Framework y .NET 6.0+
  • DirectX y codecs de video.
  • Librerías DLL específicas y componentes auxiliares.
  • Acceso a la consola CMD de Windows

Con todos estos componentes instalados he podido ejecutar bajo Linux casi cualquier aplicación para Windows, la mayoría modernas, así como también video juegos antiguos que no son de Steam.

No van a funcionar absolutamente todas las aplicaciones de Windows, ya que por lo poco que sé Wine no soporta .NET Framework 4.x en su totalidad, y alguna aplicación puede solicitar librerías específicas que habría que copiar directamente desde una instalación de Windows a Linux, y luego registrar los archivos con regsvr32.exe en caso de ser necesario (y suerte intentando hacer que eso funcione), pero la mayoría de software que he probado ha funcionado correctamente sin hacer nada especial, incluyendo software compilado bajo .NET 8 y .NET 9 que apuntan a Windows.

El script ha sido probado en Xubuntu (XFCE) y Kubuntu (KDE).


(hacer click en la imagen para agrandar)

Cabe mencionar que, y según creo tener entendido, 'sudo' se puede configurar para que siempre pida contraseña cada vez que se invoca durante la misma sesión de la terminal, o que después de 1 minuto / un tiempo configurable se vuelva a pedir contraseña la próxima vez que se invoque, así que en esos casos pues el script no realizará un procedimiento totalmente automatizado...



Tras la instalación de todos estos componentes el script generará varios accesos directos y lanzadores en el escritorio de nuestro gestor de archivos (no sé si funcionará para todos) para abrir los componentes de Wine, la carpeta del disco "C:\" de Windows y la CMD, además, en caso de tener instalado el gestor de archivos Thunar también se generarán unas acciones personalizadas en el menú contextual del gestor para ejecutar un programa con Wine y también para abrir la CMD en el directorio actual o abrir el directorio en "Windows Explorer".

Todo esto con la finalidad de mejorar un poquito más la experiencia de integración con Wine.


(hacer click en la imagen para agrandar)

Nota: La instalación podría demorar entre 30~60 minutos aprox. dependiendo del hardware y la velocidad de conexión a Internet. En mi caso, usando una máquina virtual con el sistema operativo Xubuntu, con 6 GB de RAM y 4 núcleos, tarda unos 40 minutos. Y se requiere de aprox. 10 GB de espacio libre en disco para los archivos a instalar, además de archivos temporales adicionales que se descargan durante el procedimiento de instalación; El script elimina estos archivos temporales después de completar la instalación y el espacio total utilizado se reduce aprox. 2,50 GB, dejando unos 7,50 GB utilizados.

Tengan en cuenta que escribir este script me ha supuesto muchas horas de esfuerzo e investigación ya que no tengo experiencia con Bash (este es de mis primeros scripts) ni con Wine ni con Linux en general, así que he recurrido a ChatGPT en muchas ocasiones para armar hasta la línea de código más básica, a base de mucho ensayo y error (20% errores míos, 80% errores de esta IA inútil), y también horas de tediosa experimentación, ya que instalar un componente o una librería "equivocada" con winetricks supone que Wine se vaya al carajo y no funcione ningún ejecutable de Windows, lo cual me ha ocurrido varias veces... y vuelta a empezar de cero.

¿Mi motivación para escribir este script?, el simple capricho de poder usar WinRAR y otras aplicaciones para Windows que considero esenciales y sin un equivalente digno para Linux, sumado a mi cabezonería y el tiempo libre para experimentar.



El script de instalación:

Wine_Install.sh

Código:
#!/bin/bash
set -e

###############################################################################
#                              CONFIGURATION                                  #
###############################################################################

DESKTOP_DIR="$(xdg-user-dir DESKTOP)"

###############################################################################
#                                  FUNCTIONS                                  #
###############################################################################

create_desktop_launcher() {
    local EXEC_PATH="$1"               # Path to executable or URL (required)
    local APP_NAME="$2"                # Display name of the app (required)
    local COMMENT="${3:-}"             # Comment/description (optional)
    local ICON_PATH="${4:-}"           # Path to icon file or URL (optional)
    local TERMINAL="${5:-false}"       # true or false to run in terminal (optional, default false)
    local TYPE="${6:-Application}"     # Desktop entry type (Application, Link, etc.) (optional)
    local CATEGORIES="${7:-Utility;}"  # Categories for the launcher (optional)
    local ARGS="${8:-}"                # Arguments for the executable (optional)
    local DESKTOP_FILE="${9:-$DESKTOP_DIR/$APP_NAME.desktop}" # Path to .desktop file (optional)

    # Validate required params
    if [ -z "$EXEC_PATH" ] || [ -z "$APP_NAME" ]; then
        echo "❌ Usage: create_desktop_launcher <exec_path> <app_name> [comment] [icon_path] [terminal:true|false] [type] [categories] [args] [desktop_file]"
        return 1
    fi

    # Handle icon: if URL, download it to ~/.local/share/icons/<app_name>.png
    if [[ "$ICON_PATH" == http* ]]; then
        local ICON_DIR="$HOME/.local/share/icons"
        mkdir -p "$ICON_DIR"
        local SAFE_APP_NAME=$(echo "$APP_NAME" | tr '[:upper:]' '[:lower:]' | tr ' ' '_')
        local LOCAL_ICON_PATH="$ICON_DIR/$SAFE_APP_NAME.png"

        if [ ! -f "$LOCAL_ICON_PATH" ]; then
            # echo "⬇️ Downloading icon from URL: $ICON_PATH"
            if command -v wget > /dev/null 2>&1; then
                wget -qO "$LOCAL_ICON_PATH" "$ICON_PATH"
            elif command -v curl > /dev/null 2>&1; then
                curl -sL "$ICON_PATH" -o "$LOCAL_ICON_PATH"
            else
                echo "❌ Neither wget nor curl found. Cannot download icon for desktop launcher."
                # return 1
            fi

            if [ ! -f "$LOCAL_ICON_PATH" ]; then
                echo "❌ Icon download failed for desktop launcher. Check your internet connection or URL."
                # return 1
            fi
        fi
        ICON_PATH="$LOCAL_ICON_PATH"
    fi

    # Write .desktop file
    {
        echo "[Desktop Entry]"
        echo "Name=$APP_NAME"
        [ -n "$COMMENT" ] && echo "Comment=$COMMENT"
        echo "Exec=$EXEC_PATH $ARGS"
        [ -n "$ICON_PATH" ] && echo "Icon=$ICON_PATH"
        echo "Terminal=$TERMINAL"
        echo "Type=$TYPE"
        echo "Categories=$CATEGORIES"
    } > "$DESKTOP_FILE"
}

create_thunar_custom_action() {
  local UCA_FILE="$HOME/.config/Thunar/uca.xml"
  local UNIQUE_ID="$1"
  local ICON="$2"
  local NAME="$3"
  local SUBMENU="$4"
  local COMMAND="$5"
  local DESCRIPTION="$6"
  local RANGE="$7"
  local PATTERNS="$8"
  local EXTRA_TAGS="${9}"

  if [ ! -f "$UCA_FILE" ]; then
    sudo mkdir -p "$(dirname "$UCA_FILE")"
    echo '<?xml version="1.0" encoding="UTF-8"?>
<actions>
</actions>' > "$UCA_FILE"
    # echo "✨ Created new uca.xml configuration file."
  fi

  if grep -q "<unique-id>$UNIQUE_ID</unique-id>" "$UCA_FILE"; then
    # echo "⚠️ Custom Action '$NAME' already exists in Thunar."
    return
  fi

  local ACTION_BLOCK="  <action>
    <icon>$ICON</icon>
    <name>$NAME</name>
    <submenu>$SUBMENU</submenu>
    <unique-id>$UNIQUE_ID</unique-id>
    <command>$COMMAND</command>
    <description>$DESCRIPTION</description>
    <range>$RANGE</range>
    <patterns>$PATTERNS</patterns>"
 
  if [ -n "$EXTRA_TAGS" ]; then
    ACTION_BLOCK="${ACTION_BLOCK}
    $EXTRA_TAGS"
  fi

  ACTION_BLOCK="${ACTION_BLOCK}
  </action>"

  awk -v block="$ACTION_BLOCK" '
    /<\/actions>/ {
      print block
    }
    { print }
  ' "$UCA_FILE" > "$UCA_FILE.tmp" && mv "$UCA_FILE.tmp" "$UCA_FILE"
  # echo "✅ Custom Action '$NAME' added successfully to Thunar."
}

###############################################################################
#                            MAIN SCRIPT EXECUTION                            #
###############################################################################

echo "ℹ️ INFO: This script will install Wine and required components and tools"
echo "          to integrate and run Windows applications on your Linux system."
echo ""
echo "⚠️ About 10 GB of free space is required to download and install all componentes."
echo "    The installation may take approximately 40~60 minutes."
echo
echo -n "Do you want to continue? [Y/N]: "
while true; do
    read -n1 confirm
    echo
    if [[ -z "$confirm" || "$confirm" =~ ^[Yy]$ ]]; then
        break
    elif [[ "$confirm" =~ ^[Nn]$ ]]; then
        echo "❌ Operation cancelled."
        exit 1
    else
        echo "⚠️ Invalid option. Please press Y or N."
    fi
done
clear

echo "🛠️ Adding support for 32-bit architecture and packages (required to install wine32)..."
sudo dpkg --add-architecture i386

echo -e "\n🔄 Updating package list to fetch latest info..."
sudo apt-get update

echo -e "\n🍷 Installing Wine (wine32, wine64), required to run Windows apps on Linux..."
# https://www.winehq.org/
sudo apt-get install --install-recommends -y wine wine32 wine64 libwine fonts-wine

echo -e "\n🍷 Installing Qt GUI for Wine..."
# https://github.com/brezerk/q4wine
sudo apt-get install --install-recommends -y q4wine

echo -e "\n🍷 Installing Winbind, required for Windows user authentication integration with Wine..."
# https://www.samba.org/samba/docs/current/man-html/winbindd.8.html
sudo apt-get install -y winbind

echo -e "\n🍷 Installing WineTricks for automatic installation of Windows runtimes and libraries with Wine..."
# https://github.com/Winetricks/winetricks
sudo apt-get install --install-recommends -y winetricks
# Installs latest winetricks script, allowing later dotnetdesktop8 and dotnetdesktop9 runtime installation.
# https://github.com/Winetricks/winetricks/issues/2178#issuecomment-2299877869
yes | sudo winetricks --self-update # Use sudo, it requires @root permissions to self update.

echo -e "\n🍷 Installing wine-binfmt, which causes Wine to be invoked automatically whenever a Windows .exe file is to be launched..."
# https://packages.debian.org/sid/wine-binfmt
# https://binfmt-support.nongnu.org/
sudo apt-get install -y wine-binfmt binfmt-support

if command -v thunar >/dev/null 2>&1; then
    echo -e "\n📦 Installing Tumbler and its plugins to enable thumbnail generation for various file types in Thunar file manager."
    # https://docs.xfce.org/xfce/thunar/4.14/tumbler
    # https://packages.debian.org/sid/xfce/tumbler-plugins-extra
    sudo apt-get install -y tumbler tumbler-plugins-extra
fi

echo -e "\n📦 Installing icoextract-thumbnailer (exe-thumbnailer), which generates thumbnail previews for Windows .exe files in your file manager..."
# https://github.com/jlu5/icoextract?tab=readme-ov-file#installing-from-source
sudo apt-get install --install-recommends -y icoextract-thumbnailer

echo -e "\n🆕 Creating file: '/usr/local/share/thumbnailers/exe-thumbnailer.thumbnailer' with thumbnail previews configuration for Windows PE files..."
# https://github.com/jlu5/icoextract/blob/master/exe-thumbnailer.thumbnailer
sudo mkdir -p "/usr/local/share/thumbnailers/" && {
  if [ ! -f "/usr/local/share/thumbnailers/exe-thumbnailer.thumbnailer" ]; then
    sudo tee "/usr/local/share/thumbnailers/exe-thumbnailer.thumbnailer" > /dev/null << EOF
[Thumbnailer Entry]
Exec=exe-thumbnailer -v -s %s %i %o
MimeType=application/x-ms-dos-executable;application/x-dosexec;application/x-msdownload;application/vnd.microsoft.portable-executable
EOF
  fi
}

echo -e "\n🧹 Removing existing Wine configuration in '~/.wine' (if any)..."
rm -rf ~/.wine

echo -e "\n🆕 Creating new Wine configuration with Windows 10 settings..."
sudo WINEPREFIX="/root/.wine" wine-stable winecfg -v win10
WINEPREFIX=~/.wine wine-stable winecfg -v win10

echo -e "\n🅰️ Installing Microsoft Windows fonts for better app compatibility..."
winetricks --unattended corefonts calibri cambria consolas uff

echo -e "\n⚙️ Installing Microsoft Windows runtimes..."
winetricks --unattended vb6run
winetricks --unattended vcrun6sp6 vcrun2005 vcrun2008 vcrun2010 vcrun2012 vcrun2013
winetricks --unattended --force vcrun2022 # Force installation due installer file checksum missmatch.
{
  winetricks --unattended dotnet48
  # These registry keys forces all .NET Framework assemblies to run on the latest installed CLR (i.e., dotnet48)
  # It also solves issue: https://bugs.winehq.org/show_bug.cgi?id=41727#c5
  wine reg add "HKLM\\Software\\Microsoft\\.NETFramework" /v "OnlyUseLatestCLR" /t "REG_DWORD" /d "0001" /f
  wine reg add "HKLM\\Software\\WOW6432Node\\Microsoft\\.NetFramework" /v "OnlyUseLatestCLR" /t "REG_DWORD" /d "0001" /f
}
winetricks --unattended dotnetdesktop6 dotnetdesktop7
 # .NET 8 and .NET 9 are available only from latest winetricks release which we got with 'winetricks --self-update' command.
winetricks --unattended dotnetdesktop8 dotnetdesktop9

echo -e "\n🎥 Installing codecs for media playback (also useful for Windows video games)..."
winetricks --unattended cinepak directshow ffdshow l3codecx openal

echo -e "\n📚 Installing essential Microsoft Windows libraries..."
winetricks --unattended cabinet crypt32 dbghelp gdiplus hid iertutil msacm32 msxml6 \
                        ole32 oleaut32 setupapi uiribbon urlmon webio wininet

echo -e "\n🖥️ Installing DirectX runtimes and APIs for graphics and gaming..."
winetricks --unattended d3dx9 d3dx10 dxdiag d3drm d3dxof dx8vb dxtrans \
                        devenum dinput8 directmusic directplay mdx sdl

echo -e "\n🖥️ Installing Vulkan APIs for advanced graphics support..."
winetricks --unattended dxvk vkd3d

echo -e "\n💾 Installing Microsoft Windows CMD..."
winetricks --unattended cmd

echo -e "\n🔄 Restoring Wine configuration to Windows 10 settings..."
wine winecfg -v win10

echo -e "\n🧹 Cleaning winetricks cache folder in '~/.cache/winetricks'..."
rm -rf ~/.cache/winetricks/*

echo -e "\n🚀 Creating desktop link: 'Wine (C:\)'..."
if command -v dolphin >/dev/null 2>&1; then
    WINE_DIR_ICON="folder-windows-symbolic"
else
    WINE_DIR_ICON="wine"
fi
printf '%s\n' \
"[Desktop Entry]" \
"Type=Link" \
'Name=Wine (C:\\)' \
"Icon=$WINE_DIR_ICON" \
"URL=file://$HOME/.wine/drive_c" \
> "$DESKTOP_DIR/wine-open-drive_c.desktop"

echo -e "\n🚀 Creating desktop launcher: 'Wine Configuration'..."
create_desktop_launcher \
    "wine-stable winecfg" \
    "Wine Configuration" \
    "Launch Wine Configuration" \
    "wine-stable" \
    "false" \
    "Application" \
    "Utility;" \
    "" \
    "$DESKTOP_DIR/wine-configuration.desktop"

echo -e "\n🚀 Creating desktop launcher: 'Qt GUI for Wine'..."
create_desktop_launcher \
    "q4wine" \
    "Qt GUI for Wine" \
    "Launch Qt GUI for Wine" \
    "q4wine" \
    "false" \
    "Application" \
    "Utility;" \
    "" \
    "$DESKTOP_DIR/qt-gui-for-wine.desktop"

echo -e "\n🚀 Creating desktop launcher: 'Winetricks'..."
create_desktop_launcher \
    "winetricks --gui" \
    "Winetricks" \
    "Launch Winetricks with GUI" \
    "winetricks" \
    "false" \
    "Application" \
    "Utility;" \
    "" \
    "$DESKTOP_DIR/winetricks.desktop"

if command -v thunar >/dev/null 2>&1; then
    CMD_EXEC="xfce4-terminal --title=\"CMD\" --color-bg=#000000 --color-text=#FFFFFF -e 'sudo wine-stable cmd.exe'"
    CMD_RUN_IN_TERMINAL=true
elif command -v dolphin >/dev/null 2>&1; then
    CMD_EXEC="konsole --hold -e sudo wine-stable cmd.exe"
    CMD_RUN_IN_TERMINAL=false
fi
if [[ -n "$CMD_EXEC" ]]; then
    echo -e "\n🚀 Creating desktop launcher: 'CMD'..."
    create_desktop_launcher \
        "$CMD_EXEC" \
        "CMD" \
        "Launch Microsoft Windows CMD as root" \
        "https://upload.wikimedia.org/wikipedia/commons/7/7b/CMD-Icon_%28small%29.png" \
        $CMD_RUN_IN_TERMINAL \
        "Application" \
        "Utility;" \
        "" \
        "$DESKTOP_DIR/cmd.desktop"
fi

if command -v thunar >/dev/null 2>&1; then

    echo -e "\n🚀 Creating Thunar custom action: 'Run with Wine'..."
    create_thunar_custom_action \
        "wine-run-with-wine" \
        "wine" \
        "Run with Wine" \
        "" \
        "wine-stable %f" \
        "Run a Microsoft Windows executable with Wine" \
        "*" \
        "*.exe" \
        "<other-files/>"

    echo -e "\n🚀 Creating Thunar custom action: 'Run with Wine (Terminal)'..."
    create_thunar_custom_action \
        "wine-run-with-wine-terminal" \
        "wine" \
        "Run with Wine (Terminal)" \
        "" \
        "xfce4-terminal --hold -e &quot;wine-stable %f&quot;" \
        "Run a Microsoft Windows executable with Wine (Terminal)" \
        "*" \
        "*.exe" \
        "<other-files/>"

    echo -e "\n🚀 Creating Thunar custom action: 'Open CMD here'..."
    create_thunar_custom_action \
        "wine-open-cmd-here" \
        "cmd" \
        "Open CMD here" \
        "" \
        "sudo xfce4-terminal --title=&quot;CMD&quot; --color-bg=#000000 --color-text=#FFFFFF -e &quot;wine start /wait /b /d %f cmd&quot;" \
        "Open a Windows CMD in the current directory" \
        "*" \
        "*" \
        "<directories/>"

    echo -e "\n🚀 Creating Thunar custom action: 'Open in Explorer (Wine)'..."
    create_thunar_custom_action \
        "wine-open-in-explorer" \
        "folder" \
        "Open in Explorer (Wine)" \
        "" \
        "wine-stable explorer %f" \
        "Open the current directory in Explorer (Wine)" \
        "*" \
        "*" \
        "<directories/>"

fi

echo -n -e "\n🏁 Operation completed."
echo
read -n1 -r -s -p "Press any key to finish..."
echo
exit



Adicionalmente, recomiendo utilizar estos comandos para instalar los runtimes de .NET 8 y 9 en Linux:

Código:
sudo apt install -y dotnet-runtime-8.0
sudo apt install -y dotnet-runtime-9.0

He preferido no incluir la instalación de estos runtimes en el script por que son parte del soporte nativo en Linux para aplicaciones .NET 8 y .NET 9 que apuntan a Linux; No tienen relación ni influencia sobre Wine. El script ya instala los respectivos runtimes de .NET 8 y 9 dentro de su entorno para poder ejecutar con Wine los binarios de .NET 8 y 9 que apuntan a Windows.



Por último, comparto este script para revertir la instalación de Wine y sus componentes:

Wine_Uninstall.sh
Código:
#!/bin/bash

###############################################################################
#                            MAIN SCRIPT EXECUTION                            #
###############################################################################

echo "⚠️ WARNING: This script will uninstall Wine and related components, directories, caches and configurations COMPLETELY."
echo
echo -n "Do you want to continue? [Y/N]: "
while true; do
    read -n1 confirm
    echo
    if [[ -z "$confirm" || "$confirm" =~ ^[Yy]$ ]]; then
        break
    elif [[ "$confirm" =~ ^[Nn]$ ]]; then
        echo "❌ Operation cancelled."
        exit 1
    else
        echo "⚠️ Invalid option. Please press Y or N."
    fi
done
clear

# Remove wine directory, including "drive_c" and its contents.
WINEPREFIX="/root/.wine" winetricks --unattended annihilate
WINEPREFIX="$HOME/.wine" winetricks --unattended annihilate

sudo rm -rf "/root/.wine"
rm -rf "$HOME/.wine"
rm -rf "$HOME/.cache/winetricks"

# Remove packages that are part of Wine or strictly related to.
sudo apt-get remove --purge -y wine wine32 wine64 libwine fonts-wine \
                               q4wine winetricks wine-binfmt

# Remove auxiliary packages that are not strictly tied to Wine but are "safe" to remove.
sudo apt-get remove --purge -y binfmt-support winbind \
                               samba-common samba-common-bin samba-dsdb-modules

# Additional package cleanup.
sudo apt-get autoremove -y
sudo apt-get clean

echo -e "\n🏁 Operation completed."
read -n1 -r -s -p "Press any key to finish..."
echo
exit 0

⚠️ Este script de desinstalación eliminará por completo el directorio de Windows (~/.wine) y todo lo que haya en él, sin embargo, no revierte por completo todos los paquetes instalados previamente por el script del instalador de Wine, en parte por que me parece peligroso forzar la desinstalación de ciertos paquetes relacionados con gtk que se instalaron por parte del paquete q4wine con el parámetro --install-recommends, entre otros paquetes recomendados que se instalan relacionados con Python, ya que todo eso podría depender de otros paquetes que el usuario tuviera instalado anteriormente, así que solo desinstala los paquetes estrictamente relacionados con Wine y los que considero que prácticamente nadie estará utilizando para otras cosas: binfmt-support, winbind, samba*

Revisen los paquetes que este script desinstala antes de usarlo. No me hago responsable.
4  Programación / Scripting / [APORTE] [Bash] (Linux) VMWare: Montar / Desmontar 'Shared Folders' en: 4 Junio 2025, 21:09 pm
Los siguientes dos scripts, desarrollados en el lenguaje Bash, y que se deben usar bajo un sistema operativo Linux en una máquina virtual de VMWare (aunque se pueden modificar para Virtual Box), sirven como atajo para montar y desmontar las "carpetas compartidas" (shared folders) de forma sencilla.

Utilizar estos scripts nos ahorra un valioso tiempo al no tener que usar comandos específicos en la distro de Linux para llevar a cabo el montaje de las carpetas compartidas de VMWare y de forma repetitiva (ya que el montaje no es persistente).

La idea tras esta simple herramienta es eso, ahorrar tiempo, y de esta manera, mediante el script de desmontaje, poder aislar la máquina virtual del sistema operativo anfitrión impidiendo el acceso a las carpetas compartidas, y volver a habilitar el acceso, tan solo haciendo dos clicks para ejecutar estos scripts.

 

Estos scripts son un equivalente de estos otros para Windows:

  — Tema: [APORTE] [VBS] VMWare: Mount / Unmount Shared Folders Network Drive

Sin embargo, en esta ocasión estos scripts que comparto están programados en el idioma español, e incluyen emojis. Para ser honestos yo no tengo experiencia con Bash, así que básicamente lo ha hecho casi todo ChatGPT, yo solo le di unas pinceladas.

Mount_VMWare_Shared_Folders.sh
Código:
#!/bin/bash

# Carpeta a montar: VMWare Shared Folders (".host:/" = todas las carpetas)
# Destino: "/mnt/shared_folders"
MOUNT_SOURCE=".host:/"
MOUNT_DESTINATION="/mnt/shared_folders"

# =========================================
# Montar las carpetas compartidas de VMWare
# =========================================

# Crear /mnt/shared_folders si no existe
if [ ! -d "$MOUNT_DESTINATION" ]; then
    echo "📂 Creando carpeta $MOUNT_DESTINATION... 🔥"
    sudo mkdir -p "$MOUNT_DESTINATION"
fi

# Verificar si ya está montado en /mnt/shared_folders
if mountpoint -q "$MOUNT_DESTINATION"; then
    echo "⚠️ $MOUNT_DESTINATION ya está montado."
else
    echo "🔗 Montando carpeta compartida VMWare en $MOUNT_DESTINATION..."
    sudo vmhgfs-fuse "$MOUNT_SOURCE" "$MOUNT_DESTINATION" -o allow_other
    if [ $? -ne 0 ]; then
        echo "❌ Error montando la carpeta compartida. Abortando... 💔"
        exit 1
    fi
    echo "✅ Montaje exitoso de carpeta compartida VMWare en $MOUNT_DESTINATION."
fi

# ====================================================================
# Crear enlace simbólico de las carpetas compartidas, en el escritorio
# ====================================================================

# Detectar ruta del escritorio usando user-dirs.dirs (XDG estándar)
DESKTOP_DIR=""

# Leer archivo de configuración XDG si existe
if [ -f "$HOME/.config/user-dirs.dirs" ]; then
    DESKTOP_DIR=$(grep XDG_DESKTOP_DIR "$HOME/.config/user-dirs.dirs" | cut -d= -f2 | tr -d \")
fi

# Si no lo encontró o está vacío, probar las carpetas comunes
if [ -z "$DESKTOP_DIR" ]; then
    if [ -d "$HOME/Desktop" ]; then
        DESKTOP_DIR="$HOME/Desktop"
    elif [ -d "$HOME/Escritorio" ]; then
        DESKTOP_DIR="$HOME/Escritorio"
    else
        echo "⚠️ No se pudo detectar la ubicación de la carpeta Desktop / Escritorio. Abortando... 😢"
        exit 1
    fi
else
    # Eliminar $HOME si está en la ruta para expandirla bien
    DESKTOP_DIR="${DESKTOP_DIR/#\$HOME/$HOME}"
fi

# Definir origen y destino
LINK_DESTINATION="$DESKTOP_DIR/VMWare Shared Folders"

# Crear enlace simbólico solo si no existe ya.
if [ -L "$LINK_DESTINATION" ] || [ -e "$LINK_DESTINATION" ]; then
    echo "⚠️ El enlace o archivo '$LINK_DESTINATION' ya existe. No se creará un nuevo enlace."
else
    ln -s "$MOUNT_DESTINATION" "$LINK_DESTINATION"
    echo "✅ Enlace simbólico creado en: $LINK_DESTINATION 🎉"
fi

echo -e "\n🏁 Operación finalizada."

Dismount_VMWare_Shared_Folders.sh
Código:
#!/bin/bash

# Ruta de montaje de las carpetas compartidas de VMware
MOUNT_DESTINATION="/mnt/shared_folders"

echo "🔍 Verificando si está montado $MOUNT_DESTINATION..."

if mountpoint -q "$MOUNT_DESTINATION"; then
    echo "📤 Desmontando carpeta compartida de VMware de: $MOUNT_DESTINATION..."
    sudo umount "$MOUNT_DESTINATION"
    if [ $? -eq 0 ]; then
        echo "✅ Carpeta compartida desmontada correctamente. 🎉"
    else
        echo "❌ Error al desmontar $MOUNT_DESTINATION. ¿Está en uso? 💔"
        exit 1
    fi
else
    echo "⚠️ $MOUNT_DESTINATION no está montado actualmente."
    if [ -d "$MOUNT_DESTINATION" ]; then
        echo "ℹ️ La carpeta existe, pero no contiene un punto de montaje activo."
    else
        echo "🚫 La carpeta $MOUNT_DESTINATION no existe."
    fi
fi

echo -e "\n🏁 Operación finalizada."

PD: parece que SMF no se lleva bien con los emojis, pierden el formato al usar la etiqueta "Bash" en el bloque de código.
5  Informática / Hardware / Método "infalible" — bajo Linux — para poner a prueba la integridad de un disco. en: 3 Junio 2025, 09:06 am
¡Hola! Estaba navegando por eBay buscando un disco duro, y mientras leía las reseñas de un disco en específico, me topé con un comentario bastante interesante. Era de alguien que compartía lo que, según él, es una capa adicional de verificación muy confiable para comprobar la integridad de un disco, especialmente útil para saber si uno recién comprado es perfectamente funcional o por lo contrario será propenso a fallar.

Se trata de una prueba intensiva que DEBE REALIZARSE BAJO LINUX (en Windows podríamos usar WSL con Ubuntu), y, aunque como con cualquier otra prueba no es posible garantizar al 100% que el disco no falle en el futuro por algún motivo, pero en teoría sí proporciona mucha fiabilidad adicional, especialmente como dije para discos recien comprados. Realizando esta prueba podriamos detectar con cierta fiabilidad si es un disco sin fallos de fábrica, o si por lo contrario deberíamos devolverlo lo antes posible durante el plazo de devolución. Si el disco que hemos comprado supera la prueba entonces podríamos asumir que está en excelente estado y que, al menos inicialmente, se puede depositar nuestra confianza en él con menor preocupación.

Lo que acabo de decir solo son las conclusiones que he sacado de dicho comentario.

Yo jamás había escuchado sobre esta prueba intensiva bajo Linux de 4 pasadas usando badblocks. Conozco herramientas para Windows como Victoria y otras tantas que realizan operaciones de escritura similar en el disco, pero le he preguntado a ChatGPT si existe un equivalente a badblocks para Windows y me dijo que no, que lo más confiable es seguir este procedimiento bajo Linux. ¿Qué es badblocks?, bueno, sigan leyendo:

Primeramente les dejo aquí el comentario original en inglés tal cual está redactado:

Citar
What I'm about to tell you will potentially save you from future catastrophic failures including loss of data. Nothing beats having multiple good backup copies.; however, the following information will instruct you on how to test your new drive to make sure it's free from defects. Imagine, you have a spinning disk rotating thousands of times per minute separated by its recording/reading head by less thickness of a human hair. Just one wrong thing and .. "click..click..click". You don't want that. Generally speaking a bad hard drive will make itself known sooner vs later when it's tested fully. Not always. What YOU can do is put the hard drive through its paces to really give it a good solid work out and make sure every space designated by the drive as available/writeable space, is in fact GOOD. Its magnetic/electrical properties strong. This test is a LONG test. What it does is write all 0s, 1s, 0-1s. 1-0s (binary) to the disk. It does this in 4 passes (i.e. writes the disk fully) 4 times. After each write it will read what was just written beginning to end to ensure all bits were written exactly right. If they wern't, the drive's detection mechanism for errors (SMART) will notice (i.e. a bit was not written to a sector correctly) and flag the SMART COUNTER. For example, uncorrectable or reallocated sector count would show a non-0 value. During operation, if the drive encounters a fault with a sector it will swap that sector with another known good sector the drive has in reserve and will log it via SMART. A PERFECTLY WORKING HARD DRIVE WILL SHOW '0' for 'Reallocated Sector Count','Reported Uncorrectable Errors','Current Pending Sector Count','Uncorrectable Sector Count'.IF ANY OF THESE VALUES SHOWS ANYTHING OTHER THAN A 0 (zero), THEN YOU HAVE A FAILING HDD AND SHOULD REPLACE IT ASAP. DO NOT TRUST YOUR DATA ON IT. This command will erase everything on the disk if there is data already on there when you run this test. For a 5TB it took me over 4 days. But I am confident the data will be safe because it worked out the drive hard and pictures above show good numbers. Boot up your computer using a linux distribution boot usb/cd. Debian Ubuntu, any one will do--it doesn't matter. In a terminal type: sudo fdisk -l *Identiy which /dev is your HDD you wish to test. Also note if it says 512 or 4096 where it says "Sector size (logical/physical)". For example, if it's /dev/sde and says 4096 Sector Size (such as this 5tb drive) then type the following command: sudo badblocks -wsv -b 4096 -c 131072 /dev/sde This will 0,1,01,10 write and read/verify the drive back-to-back in 4 passes. On my slow computer via USB 3, this took around 4.5 days to complete. The ' -b ' option is the Block Size. This should match the drive. 512 or 4096. The '-c' option tells badblocks how many blocks to test at time. Changing this number will alter the speed and will either make the process go along faster or slower (dependant on Drive Interface, Ram/Cpu speed, etc.). Instead of '-c 131072' ,try '-c 65536 if it seems the test is taking too long to increment the %'s. In fact try it with '-c 65536' option. Let it run or 30 sec then CTRL-C to cancel it. Then run the command again but with '-c 131072' instead. Run it for 30 sec then CTRL-C to cancel. Compare the 2 and whichever command that had the higher % when you CTRL-C'd would be the number you would choose since that one ran a little bit faster. Google or man page 'badblocks' for more information. Whenever you buy a new hard drive get into the mindset/habit that you will NOT use them for at least a week (or 2) because you have to test them out first. Trust me on this and it's totally worth it. I'd like to think I avoid catastrophic failures because I did this test and it would have presented itself (or at least more likelihood) then vs months/years down the road. That's not a given--any drive can fail anytime or any reason but this is just an additional layer. Like a "shakedown cruise' if you will. Regarding this drive: Seagate Portable 5TB External Hard Drive HDD – USB 3.0, I can say that I am pleased it tested clean and I look forward to using this drive.And I'm confident it will keep my data intact. You are welcome!



Y por último me despido dejándoles la traducción al español y con formato:

Lo que estás a punto de leer podría salvarte de fallos catastróficos en el futuro, incluyendo la pérdida total de datos.
Nada supera tener varias copias de seguridad bien hechas, pero la información que sigue te enseñará cómo probar tu nuevo disco duro para asegurarte de que no tiene defectos.

Imagina esto: un disco girando miles de veces por minuto, separado de su cabezal de lectura/escritura por menos del grosor de un cabello humano. Basta un pequeño fallo para escuchar ese temido sonido: "clic... clic... clic". No quieres que eso pase.

En términos generales, un disco duro defectuoso suele mostrar síntomas más temprano que tarde si se le somete a una prueba exhaustiva. No siempre, pero muchas veces sí.

Lo que TÚ puedes hacer es someter el disco a una prueba intensiva que lo exprima al máximo, asegurándote de que cada espacio declarado como disponible y escribible sea efectivamente funcional, con propiedades magnéticas y eléctricas sólidas.

Esta es una prueba LARGA.
Lo que hace es escribir patrones binarios en el disco (todos 0s, luego 1s, luego 0-1s, y después 1-0s), en 4 pasadas completas.
Después de cada escritura, el programa lee todo el contenido de principio a fin para verificar que los bits escritos estén correctos.

Si algo falla, el sistema SMART del disco detectará errores (por ejemplo, que un bit no fue escrito correctamente en un sector) y marcará los contadores SMART.

Algunos valores clave que deben ser igual a cero en un disco perfectamente funcional:

  • Reallocated Sector Count
  • Reported Uncorrectable Errors
  • Current Pending Sector Count
  • Uncorrectable Sector Count



Si cualquiera de estos valores es distinto de 0, el disco está fallando y deberías reemplazarlo cuanto antes. NO confíes tus datos a él.

⚠️ Advertencia: Este test borra todo lo que haya en el disco. Si tiene información, se perderá.

En mi caso, con un disco de 5 TB, la prueba tomó más de 4 días. Pero ahora tengo confianza de que los datos estarán seguros, porque el disco superó la prueba con éxito.

Pasos para realizar la prueba:

    Arranca tu computadora usando un Live USB/CD con alguna distribución de Linux (Debian, Ubuntu, cualquiera sirve).

    Abre un terminal y escribe:

Código:
sudo fdisk -l

    Identifica cuál es tu disco (por ejemplo, /dev/sde) y fíjate en el tamaño del sector lógico/físico (512 o 4096).

Ejemplo: Si tu disco es /dev/sde y usa sectores de 4096, ejecuta:

Código:
sudo badblocks -wsv -b 4096 -c 131072 /dev/sde

Este comando escribirá los patrones binarios (0,1,01,10), luego los leerá y verificará, durante 4 pasadas completas.
En mi caso, vía USB 3.0 en un equipo lento, tomó aproximadamente 4.5 días.

Explicación de opciones:
Código:
-b
→ Tamaño del bloque. Debe coincidir con el tamaño de bloque del disco (512 o 4096).
Código:
-c
→ Cuántos bloques probar a la vez. Afecta la velocidad de la prueba.

Si ves que va lento con -c 131072, prueba con:

Código:
-c 65536

Puedes comparar la velocidad de ambos con CTRL+C tras 30 segundos y elegir el que haya avanzado más en porcentaje.

Para más información, busca en Google o consulta la man page de badblocks.

Consejo final:
Cada vez que compres un disco nuevo, acostúmbrate a no usarlo por al menos una semana o dos. Primero, ¡ponlo a prueba! Créeme, vale la pena.

Me gusta pensar que evité fallos catastróficos gracias a esta prueba. Es una capa adicional de protección, como un “viaje de prueba” antes de confiarle tus datos.

En cuanto a este modelo específico:
Seagate Portable 5TB External Hard Drive HDD – USB 3.0

Puedo decir que estoy satisfecho. Pasó la prueba sin errores y estoy tranquilo sabiendo que mis datos estarán bien protegidos en él.

¡De nada! 😊
6  Programación / Scripting / [APORTE] [PowerShell] Montar y desmontar una unidad virtual de CD/DVD/BD o VHD/VHDX/VHDS en: 2 Junio 2025, 02:17 am
El siguiente script, desarrollado en PowerShell, sirve para montar y desmontar una unidad virtual de CD/DVD/BD con el archivo de imagen ISO especificado. Opcionalmente se le podría dar el mismo uso para montar discos virtuales en formato .vhd, .vhdx y .vhds

Desarrollé este script para evitar tener que recurrir a software de terceros (ej. ImDisk) en escenarios donde necesito automatizar el montaje de archivos ISO, sin interacción humana y sin dependencias externas.

El script no tiene parámetros configurables. El archivo ISO a montar y desmontar está establecido directamente en el código fuente, en la siguiente línea:
Código:
$isoPath = Join-Path $PSScriptRoot "CD-ROM.iso"

Si se requiere que el script no interrumpa, solo hay que comentar las dos líneas que llaman a las funciones Confirm-Continue y Show-GoodbyeScreen:
Código
  1. ...
  2. Show-WelcomeScreen
  3. # Confirm-Continue
  4. Mount-ISO
  5. # Show-GoodbyeScreen



Mount virtual drive.ps1



Código
  1. <#PSScriptInfo
  2. .VERSION 1.0
  3. .GUID 14688e75-298c-1112-a2d0-1234567890aa
  4. .AUTHOR ElektroStudios
  5. .COMPANYNAME ElektroStudios
  6. .COPYRIGHT ElektroStudios © 2025
  7. #>
  8.  
  9. <#
  10. ===========================================================================================
  11. |                                                                                         |
  12. |                                        Variables                                        |
  13. |                                                                                         |
  14. ===========================================================================================
  15. #>
  16.  
  17. $isoPath = Join-Path $PSScriptRoot "CD-ROM.iso"
  18.  
  19. <#
  20. ===========================================================================================
  21. |                                                                                         |
  22. |                                    Functions                                            |
  23. |                                                                                         |
  24. ===========================================================================================
  25. #>
  26.  
  27. function Show-WelcomeScreen {
  28.    Clear-Host
  29.    Write-Host ""
  30.    Write-Host " $($host.ui.RawUI.WindowTitle)"
  31.    Write-Host " +==================================================+"
  32.    Write-Host " |                                                 |"
  33.    Write-Host " | This script will mount a virtual drive with the |"
  34.    Write-Host " | ISO file of the specified path.                 |"
  35.    Write-Host " |                                                 |"
  36.    Write-Host " +=================================================+"
  37.    Write-Host ""
  38.    Write-Host " Script Settings            " -ForegroundColor DarkGray
  39.    Write-Host " ===========================" -ForegroundColor DarkGray
  40.    Write-Host " ISO File: $([System.IO.Path]::GetFullPath($isoPath))" -ForegroundColor Gray
  41.    Write-Host ""
  42. }
  43.  
  44. function Confirm-Continue {
  45.    Write-Host " Press 'Y' key to continue or 'N' to exit."
  46.    Write-Host ""
  47.    Write-Host " -Continue? (Y/N)"
  48.    do {
  49.        $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
  50.        $char = $key.Character.ToString().ToUpper()
  51.        if ($char -ne "Y" -and $char -ne "N") {
  52.            [console]::beep(1500, 500)
  53.        }
  54.    } while ($char -ne "Y" -and $char -ne "N")
  55.    if ($char -eq "N") {Exit(1)} else {Clear-Host}
  56. }
  57.  
  58. function Mount-ISO {
  59.    if (Test-Path $isoPath) {
  60.        try {
  61.            $fullPath = (Resolve-Path $isoPath).Path
  62.            $alreadyMounted = $null
  63.            try {
  64.                $alreadyMounted = Get-DiskImage -ImagePath $fullPath -ErrorAction Stop
  65.            } catch {
  66.            }
  67.  
  68.            if ($alreadyMounted -and $alreadyMounted.Attached) {
  69.                Write-Host "ISO is already mounted. Skipping mount." -ForegroundColor Cyan
  70.            } else {
  71.                try {
  72.                    $image = Mount-DiskImage -ImagePath $fullPath -PassThru -ErrorAction Stop
  73.                    Write-Host "Virtual drive has been mounted successfully." -ForegroundColor Green
  74.                } catch {
  75.                    Write-Host "Error while mounting the ISO:" -ForegroundColor Red
  76.                    Write-Host $_.Exception.Message -ForegroundColor Yellow
  77.                }
  78.            }
  79.        }
  80.        catch {
  81.            Write-Host "Failed to mount the virtual drive." -ForegroundColor Red
  82.            Write-Host $_.Exception.Message -ForegroundColor Yellow
  83.        }
  84.    } else {
  85.        Write-Warning "ISO file not found at: $isoPath"
  86.    }
  87. }
  88.  
  89. function Show-GoodbyeScreen {
  90.    Write-Host "Operation Completed!" -BackgroundColor Black -ForegroundColor Green
  91.    Write-Host ""
  92.    Write-Host "Press any key to exit..."
  93.    $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown")
  94.    Exit(0)
  95. }
  96.  
  97. <#
  98. ===========================================================================================
  99. |                                                                                         |
  100. |                                         Main                                            |
  101. |                                                                                         |
  102. ===========================================================================================
  103. #>
  104.  
  105. [System.Console]::Title = "Mount ISO file - by Elektro"
  106. #[System.Console]::SetWindowSize(150, 45)
  107. [CultureInfo]::CurrentUICulture = "en-US"
  108.  
  109. try { Set-ExecutionPolicy -ExecutionPolicy "Unrestricted" -Scope "Process" } catch { }
  110.  
  111. Show-WelcomeScreen
  112. Confirm-Continue
  113. Mount-ISO
  114. Show-GoodbyeScreen
  115.  



Dismount virtual drive.ps1



Código
  1. <#PSScriptInfo
  2. .VERSION 1.0
  3. .GUID 14688e75-298c-1112-a2d0-1234567890ab
  4. .AUTHOR ElektroStudios
  5. .COMPANYNAME ElektroStudios
  6. .COPYRIGHT ElektroStudios © 2025
  7. #>
  8.  
  9. <#
  10. ===========================================================================================
  11. |                                                                                         |
  12. |                                        Variables                                        |
  13. |                                                                                         |
  14. ===========================================================================================
  15. #>
  16.  
  17. $isoPath = Join-Path $PSScriptRoot "CD-ROM.iso"
  18.  
  19. <#
  20. ===========================================================================================
  21. |                                                                                         |
  22. |                                    Functions                                            |
  23. |                                                                                         |
  24. ===========================================================================================
  25. #>
  26.  
  27. function Show-WelcomeScreen {
  28.    Clear-Host
  29.    Write-Host ""
  30.    Write-Host " $($host.ui.RawUI.WindowTitle)"
  31.    Write-Host " +======================================================+"
  32.    Write-Host " |                                                      |"
  33.    Write-Host " | This script will dismount a virtual drive previously |"
  34.    Write-Host " | mounted with the ISO file of the specified path.     |"
  35.    Write-Host " |                                                      |"
  36.    Write-Host " +======================================================+"
  37.    Write-Host ""
  38.    Write-Host " Script Settings            " -ForegroundColor DarkGray
  39.    Write-Host " ===========================" -ForegroundColor DarkGray
  40.    Write-Host " ISO File: $([System.IO.Path]::GetFullPath($isoPath))" -ForegroundColor Gray
  41.    Write-Host ""
  42. }
  43.  
  44. function Confirm-Continue {
  45.    Write-Host " Press 'Y' key to continue or 'N' to exit."
  46.    Write-Host ""
  47.    Write-Host " -Continue? (Y/N)"
  48.    do {
  49.        $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
  50.        $char = $key.Character.ToString().ToUpper()
  51.        if ($char -ne "Y" -and $char -ne "N") {
  52.            [console]::beep(1500, 500)
  53.        }
  54.    } while ($char -ne "Y" -and $char -ne "N")
  55.    if ($char -eq "N") {Exit(1)} else {Clear-Host}
  56. }
  57.  
  58. function Dismount-ISO {
  59.    if (Test-Path $isoPath) {
  60.        try {
  61.            $fullPath = (Resolve-Path $isoPath).Path
  62.            $alreadyMounted = $null
  63.            try {
  64.                $alreadyMounted = Get-DiskImage -ImagePath $fullPath -ErrorAction Stop
  65.            } catch {
  66.            }
  67.            if ($alreadyMounted -and $alreadyMounted.Attached) {
  68.                try {
  69.                    Dismount-DiskImage -ImagePath $fullPath -ErrorAction Stop
  70.                    Write-Host "Virtual drive has been dismounted successfully." -ForegroundColor Green
  71.                } catch {
  72.                    Write-Host "Error while dismounting the virtual drive:" -ForegroundColor Red
  73.                    Write-Host $_.Exception.Message -ForegroundColor Yellow
  74.                }
  75.            } else {
  76.                Write-Host "No virtual drive mounted for this ISO. Nothing to dismount." -ForegroundColor Cyan
  77.            }
  78.        }
  79.        catch {
  80.            Write-Host "Failed to dismount the virtual drive." -ForegroundColor Red
  81.            Write-Host $_.Exception.Message -ForegroundColor Yellow
  82.        }
  83.    } else {
  84.        Write-Warning "ISO file not found at: $isoPath"
  85.    }
  86. }
  87.  
  88. function Show-GoodbyeScreen {
  89.    Write-Host "Operation Completed!" -BackgroundColor Black -ForegroundColor Green
  90.    Write-Host ""
  91.    Write-Host "Press any key to exit..."
  92.    $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown")
  93.    Exit(0)
  94. }
  95.  
  96. <#
  97. ===========================================================================================
  98. |                                                                                         |
  99. |                                         Main                                            |
  100. |                                                                                         |
  101. ===========================================================================================
  102. #>
  103.  
  104. [System.Console]::Title = "Dismount ISO file - by Elektro"
  105. #[System.Console]::SetWindowSize(150, 45)
  106. [CultureInfo]::CurrentUICulture = "en-US"
  107.  
  108. try { Set-ExecutionPolicy -ExecutionPolicy "Unrestricted" -Scope "Process" } catch { }
  109.  
  110. Show-WelcomeScreen
  111. Confirm-Continue
  112. Dismount-ISO
  113. Show-GoodbyeScreen
  114.  
7  Programación / Scripting / [APORTE] [PowerShell] Ejemplo para modificar los niveles de integridad de directorios en: 15 Abril 2025, 07:57 am
El siguiente script, desarrollado en PowerShell, es una simple demostración de como podemos especificar un array de directorios para modificar su nivel de integridad, mediate el uso del comando ICACLS de Microsoft Windows.

Acerca de los niveles de integridad:
  👉 https://hacktricks.boitatech.com.br/windows/windows-local-privilege-escalation/integrity-levels

Cuando navegamos por un directorio con un nivel de integridad bajo, se nos mostrará la siguiente ventana de advertencia cuando se intenten copiar o mover archivos dentro o fuera de dicho directorio (utilizando el menú contextual de cortar / copiar / pegar):



Pueden comprobarlo en el directorio "C:\Users\{USUARIO}\AppData\LocalLow", que por defecto tiene un nivel de integridad bajo (Low) a menos que de alguna extraña forma esto se haya modificado en su sistema operativo.



Este comportamiento de advertencia puede resultar muy molesto, pero podemos deshacernos de esa ventana de advertencia cambiando el nivel de integridad por uno más alto (Medium):





El script lo he escrito de tal manera que se pueda embedir en un Batch-script:

Código
  1. powershell.exe -NoProfile -ExecutionPolicy Bypass -Command ^
  2. "$folders = @{^
  3.    \"$env:USERPROFILE\AppData\Local\"    = @{level = 'Medium'; recurse = $false};^
  4.    \"$env:USERPROFILE\AppData\LocalLow\" = @{level = 'Medium'; recurse = $true};^
  5.    \"$env:USERPROFILE\AppData\Roaming\"  = @{level = 'Medium'; recurse = $false};^
  6.    \"$env:USERPROFILE\Desktop\"          = @{level = 'Medium'; recurse = $false};^
  7.    \"$env:USERPROFILE\Documents\"        = @{level = 'Medium'; recurse = $false};^
  8.    \"$env:USERPROFILE\Downloads\"        = @{level = 'Medium'; recurse = $false};^
  9.    \"$env:USERPROFILE\Favorites\"        = @{level = 'Medium'; recurse = $false};^
  10.    \"$env:USERPROFILE\Links\"            = @{level = 'Medium'; recurse = $false};^
  11.    \"$env:USERPROFILE\Music\"            = @{level = 'Medium'; recurse = $false};^
  12.    \"$env:USERPROFILE\Pictures\"         = @{level = 'Medium'; recurse = $false};^
  13.    \"$env:USERPROFILE\Videos\"           = @{level = 'Medium'; recurse = $false};^
  14. };^
  15. $sortedFolders = $folders.Keys ^| Sort-Object;^
  16. Write-Output \"Applying folder integrity levels...\";^
  17. Write-Output \"\";^
  18. Write-Output \"Level  | Recursive | Directory\";^
  19. Write-Output \"-------|-----------|----------\";^
  20. foreach ($folder in $sortedFolders) {^
  21.    $level = $folders[$folder].level;^
  22.    $recurseFlag = if ($folders[$folder].recurse) { '/T' } else { '' };^
  23.    $recurseText = if ($folders[$folder].recurse) { 'Yes' } else { 'No ' };^
  24.    Write-Output \"$level | $recurseText       | $folder\";^
  25.    ICACLS.exe \"$folder\" $recurseFlag /Setintegritylevel \"(OI)(CI)$level\" 2^>^$null 1^>^$null^
  26. }"



El cambio de nivel de integridad tiene efecto inmediato, no es necesario reiniciar sesión de usuario ni el PC.

* ⚠️ Antes de utilizar ese script, configurar el array con las rutas de los directorios que deseen incluir.



Como alternativa, les dejo este módulo de PowerShell, basado en la API de Windows para quien desee llevar a cabo una gestión más directa y sofisticada de los niveles de integridad sin necesidad de recurrir a comandos externos del sistema operativo como ICACLS:

  👉 https://github.com/jborean93/PSIntegrity/blob/master/PSIntegrity/PSIntegrity.psm1

Cmdlets incluídos:
Citar
Get-IntegrityLabel: Gets an instance of BaseObjectLabel for the resource specified
Remove-IntegrityLabel: Removes the mandatory integrity label set on an object
Set-IntegrityLabel: Adds or changes the mandatory integrity label set on an object

Atentamente,
Elektro.
8  Informática / Software / Busco un software con interfaz gráfica para leer y modificar los niveles de integridad (Mandatory Label ACE) de archivos en: 14 Abril 2025, 00:09 am
Hola!

Busco un software de seguridad, con interfaz gráfica (GUI), que sea capaz de leer y modificar los 👉 niveles de integridad ('File Integrity Levels' en Inglés, o 👉 Mandatory Label ACE) de archivos y carpetas, de forma productiva, es decir, con una navegación de archivos fácil y fluida, que no te haga perder 5 minutos para navegar hasta un directorio en específico...

Básicamente lo que se puede hacer con el parámetro /SetIntegrtyLevel del executable ICACLS.exe en Windows:
  - https://learn.microsoft.com/es-es/windows-server/administration/windows-commands/icacls

O con el ya extinto programa Chml de Mr. Minasi:
  - https://web.archive.org/web/20131226134704/http://www.minasi.com/apps/
(se puede descargar el executable desde esa página)

O con este módulo de terceros (basado en C# — en el uso de Windows API) para el lenguaje de programación PowerShell:
  - https://github.com/jborean93/PSIntegrity/blob/master/PSIntegrity/PSIntegrity.psm1

etc.



He intentado buscar específicamente una GUI de ICACLS, pero no encontré nada. En fin. No me urge en absoluto encontrar un programa similar, más bien es por el capricho de poder tener un buen programa con interfaz gráfica, sencillito y productivo para estos menesteres. Que esté orientado a los niveles de integridad, más que a los ACL (como 👉 SetACL Studio, que por cierto es antiproductivo en todos los sentidos). Hay varias opciones por línea de comandos como las que por ejemplo ya he mencionado aquí, pero con interfaz gráfica no he encontrado nada. Parece estar bastante difícil, quizás no exista. O quizás alguien pueda sorprenderme...

Gracias de antemano.

Atentamente,
Elektro.
9  Foros Generales / Sugerencias y dudas sobre el Foro / ¡Es peligroso! - Solicito contactar con algún moderador global en: 12 Marzo 2025, 04:22 am
Hola.

He detectado un hilo que en mi opinión es muy peligroso y podría estar elaborado con fines maliciosos cuestionables. En mi opinión debería ser eliminado cuanto antes. No puedo reportarlo directamente usando el botón de reportar, por motivos que me reservo publicamente.

¿Con quien puedo hablar esto?. Tendría que ser con alguien que pueda eliminar temas del foro, y por mensaje privado, por que el hilo implica a un usuario con rango así que no quiero hablarlo aquí publicamente por respeto (para evitar hacer un señalamiento público).

¿Alguien que cumpla estas características (un moderador global o con rango superior) podría ponerse en contacto conmigo, por favor?.

¿O decirme con quien debo ponerme yo en contacto?.

Esto no lo hago por mi, sino por el foro y sus usuarios.

No pretendo perjudicar a nadie, solo que escuchen mis argumentos por los cuales considero que ese hilo debería ser eliminado cuanto antes por el bien estar de los usuarios. Solo eso, que se elimine ese tema y ya, sería el fin del asunto por mi parte.

Creo que si me escuchasen podrían comprender mis argumentos e incluso darme la razón total o parcialmente.

No seré pesado ni escribiré una biblia para explayarme, lo prometo.

Gracias.
10  Programación / Scripting / [APORTE] [PowerShell] Crear un archivo dummy de forma fácil e interactiva en: 3 Marzo 2025, 09:36 am
El siguiente script, desarrollado de manera híbrida en PowerShell y VisualBasic.NET, permite crear de manera interactiva un archivo dummy (vacío o con contenido aleatorio) con un tamaño determinado.

La creación de un archivo dummy resulta útil para realizar pruebas de escritura en discos, o para sobrescribir el espacio en blanco del disco dificultando o imposibilitando la recuperación de datos, por ejemplo, generando un archivo dummy (con datos aleatorios) que ocupe todo el espacio disponible en el disco.

Al ejecutar este script, aparecerá el siguiente formulario que permitirá seleccionar la ubicación del archivo a crear y configurar las opciones disponibles:



Este es el procedimiento completo:



La interfaz gráfica y el resto del procedimiento está contenido en un script de PowerShell de 31 kilobytes, ideal para incluirlo como herramienta adicional en entornos de pruebas y recuperación, sin dependencias adicionales ...más allá de PowerShell y .NET Framework.



Así se verá un archivo dummy en un editor hexadecimal:



Y así se verá el archivo dummy rellenado con datos aleatorios:





CreateDummyFile.ps1
Código
  1. <#PSScriptInfo
  2. .VERSION 1.0
  3. .GUID 26C67DF9-0F1E-4806-9D23-586DFBDECF88
  4. .AUTHOR ElektroStudios
  5. .COMPANYNAME ElektroStudios
  6. .COPYRIGHT ElektroStudios © 2025
  7. #>
  8.  
  9. $vbCode = @'
  10. #Region " Option Statements "
  11.  
  12. Option Strict On
  13. Option Explicit On
  14. Option Infer Off
  15.  
  16. #End Region
  17.  
  18. #Region " Imports "
  19.  
  20. Imports Microsoft.VisualBasic
  21.  
  22. Imports System
  23. Imports System.Collections.Generic
  24. Imports System.ComponentModel
  25. Imports System.Diagnostics
  26. Imports System.Diagnostics.CodeAnalysis
  27. Imports System.Drawing
  28. Imports System.Drawing.Design
  29. Imports System.Globalization
  30. Imports System.IO
  31. Imports System.Linq
  32. Imports System.Reflection
  33. Imports System.Runtime.CompilerServices
  34. Imports System.Runtime.InteropServices
  35. Imports System.Security
  36. Imports System.Text
  37. Imports System.Windows.Forms
  38. Imports System.Xml
  39. Imports System.Xml.Serialization
  40.  
  41. Imports DevCase.Core.IO.DigitalInformation
  42. Imports DevCase.Core.IO.FileSystem
  43. Imports DevCase.Runtime.TypeConverters
  44. Imports DevCase.Win32
  45. Imports DevCase.Win32.Enums
  46.  
  47. #End Region
  48.  
  49. #Region " CreateDummyFileOptionsForm "
  50.  
  51. Public NotInheritable Class CreateDummyFileOptionsForm : Inherits System.Windows.Forms.Form
  52.  
  53.    Public Sub New()
  54.        Me.InitializeComponent()
  55.    End Sub
  56.  
  57.    'Form overrides dispose to clean up the component list.
  58.    <System.Diagnostics.DebuggerNonUserCode()>
  59.    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
  60.        Try
  61.            If disposing AndAlso components IsNot Nothing Then
  62.                components.Dispose()
  63.            End If
  64.        Finally
  65.            MyBase.Dispose(disposing)
  66.        End Try
  67.    End Sub
  68.  
  69.    'Required by the Windows Form Designer
  70.    Private components As System.ComponentModel.IContainer
  71.    Friend WithEvents PropertyGrid1 As New PropertyGrid
  72.    Friend WithEvents ButtonCancel As Button
  73.    Friend WithEvents ButtonOk As Button
  74.    Friend WithEvents TableLayoutPanel1 As TableLayoutPanel
  75.    Friend WithEvents Panel1 As Panel
  76.  
  77.    'NOTE: The following procedure is required by the Windows Form Designer
  78.    'It can be modified using the Windows Form Designer.  
  79.    'Do not modify it using the code editor.
  80.    <System.Diagnostics.DebuggerStepThrough()>
  81.    Private Sub InitializeComponent()
  82.        Me.PropertyGrid1 = New System.Windows.Forms.PropertyGrid()
  83.        Me.ButtonCancel = New System.Windows.Forms.Button()
  84.        Me.ButtonOk = New System.Windows.Forms.Button()
  85.        Me.TableLayoutPanel1 = New System.Windows.Forms.TableLayoutPanel()
  86.        Me.Panel1 = New System.Windows.Forms.Panel()
  87.        Me.TableLayoutPanel1.SuspendLayout()
  88.        Me.Panel1.SuspendLayout()
  89.        Me.SuspendLayout()
  90.        '
  91.        'PropertyGrid1
  92.        '
  93.        Me.PropertyGrid1.Dock = System.Windows.Forms.DockStyle.Fill
  94.        Me.PropertyGrid1.Location = New System.Drawing.Point(3, 4)
  95.        Me.PropertyGrid1.Margin = New System.Windows.Forms.Padding(3, 4, 3, 4)
  96.        Me.PropertyGrid1.Name = "PropertyGrid1"
  97.        Me.PropertyGrid1.PropertySort = System.Windows.Forms.PropertySort.NoSort
  98.        Me.PropertyGrid1.Size = New System.Drawing.Size(733, 157)
  99.        Me.PropertyGrid1.TabIndex = 0
  100.        Me.PropertyGrid1.ToolbarVisible = False
  101.        '
  102.        'ButtonCancel
  103.        '
  104.        Me.ButtonCancel.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
  105.        Me.ButtonCancel.Location = New System.Drawing.Point(624, 6)
  106.        Me.ButtonCancel.Name = "ButtonCancel"
  107.        Me.ButtonCancel.Size = New System.Drawing.Size(100, 40)
  108.        Me.ButtonCancel.TabIndex = 1
  109.        Me.ButtonCancel.Text = "Cancel"
  110.        Me.ButtonCancel.UseVisualStyleBackColor = True
  111.        '
  112.        'ButtonOk
  113.        '
  114.        Me.ButtonOk.Anchor = CType((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
  115.        Me.ButtonOk.Location = New System.Drawing.Point(518, 6)
  116.        Me.ButtonOk.Name = "ButtonOk"
  117.        Me.ButtonOk.Size = New System.Drawing.Size(100, 40)
  118.        Me.ButtonOk.TabIndex = 2
  119.        Me.ButtonOk.Text = "Ok"
  120.        Me.ButtonOk.UseVisualStyleBackColor = True
  121.        '
  122.        'TableLayoutPanel1
  123.        '
  124.        Me.TableLayoutPanel1.ColumnCount = 1
  125.        Me.TableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
  126.        Me.TableLayoutPanel1.Controls.Add(Me.Panel1, 0, 1)
  127.        Me.TableLayoutPanel1.Controls.Add(Me.PropertyGrid1, 0, 0)
  128.        Me.TableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill
  129.        Me.TableLayoutPanel1.Location = New System.Drawing.Point(0, 0)
  130.        Me.TableLayoutPanel1.Name = "TableLayoutPanel1"
  131.        Me.TableLayoutPanel1.RowCount = 2
  132.        Me.TableLayoutPanel1.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 73.17073!))
  133.        Me.TableLayoutPanel1.RowStyles.Add(New System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 26.82927!))
  134.        Me.TableLayoutPanel1.Size = New System.Drawing.Size(739, 226)
  135.        Me.TableLayoutPanel1.TabIndex = 3
  136.        '
  137.        'Panel1
  138.        '
  139.        Me.Panel1.Controls.Add(Me.ButtonOk)
  140.        Me.Panel1.Controls.Add(Me.ButtonCancel)
  141.        Me.Panel1.Dock = System.Windows.Forms.DockStyle.Fill
  142.        Me.Panel1.Location = New System.Drawing.Point(3, 168)
  143.        Me.Panel1.Name = "Panel1"
  144.        Me.Panel1.Size = New System.Drawing.Size(733, 55)
  145.        Me.Panel1.TabIndex = 4
  146.        '
  147.        'CreateDummyFileOptionsForm
  148.        '
  149.        Me.AutoScaleDimensions = New System.Drawing.SizeF(7.0!, 17.0!)
  150.        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
  151.        Me.ClientSize = New System.Drawing.Size(739, 226)
  152.        Me.Controls.Add(Me.TableLayoutPanel1)
  153.        Me.Font = New System.Drawing.Font("Segoe UI", 10.0!)
  154.        Me.Margin = New System.Windows.Forms.Padding(3, 4, 3, 4)
  155.        Me.MaximizeBox = False
  156.        Me.Name = "CreateDummyFileOptionsForm"
  157.        Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
  158.        Me.Text = "Create Dummy File Options"
  159.        Me.TableLayoutPanel1.ResumeLayout(False)
  160.        Me.Panel1.ResumeLayout(False)
  161.        Me.ResumeLayout(False)
  162.  
  163.    End Sub
  164.  
  165.    Public Property DummyFileOptions As New DummyFileOptions
  166.  
  167.    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  168.  
  169.        Me.PropertyGrid1.SelectedObject = Me.DummyFileOptions
  170.        DevCase.Extensions.PropertyGridExtensions.SetSplitterPosition(Me.PropertyGrid1, 145)
  171.        Me.MinimumSize = Me.Size
  172.        Me.MaximumSize = New Size(3840, Me.Height)
  173.    End Sub
  174.  
  175.    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles ButtonCancel.Click
  176.        Me.DialogResult = DialogResult.Cancel
  177.        Me.Close()
  178.    End Sub
  179.  
  180.    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles ButtonOk.Click
  181.        Me.DialogResult = DialogResult.OK
  182.        Me.Close()
  183.    End Sub
  184.  
  185. End Class
  186.  
  187. #End Region
  188.  
  189. #Region " DummyFileOptions "
  190.  
  191. Public NotInheritable Class DummyFileOptions
  192.  
  193.    <Browsable(True)>
  194.    <Editor(GetType(SaveFileNameEditor), GetType(UITypeEditor))>
  195.    <DisplayName("File Path")>
  196.    <Description("File path where to create the dummy file.")>
  197.    Public Property FilePath As String = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "File.dummy")
  198.  
  199.    <TypeConverter(GetType(FileSizeConverter))>
  200.    <DisplayName("File Size")>
  201.    <Description("Size of the dummy file.")>
  202.    Public Property FileSize As New FileSize(1, DigitalStorageUnits.Megabyte)
  203.  
  204.    <Browsable(False)>
  205.    Public ReadOnly Property FileSizeBytes As ULong
  206.        Get
  207.            Return CULng(Me.FileSize.Size(DigitalStorageUnits.Byte))
  208.        End Get
  209.    End Property
  210.  
  211.    <TypeConverter(GetType(FileSizeConverter))>
  212.    <DisplayName("Buffer Size")>
  213.    <Description("Size of the buffer used to write the dummy file.")>
  214.    Public Property BufferSize As New FileSize(4, DigitalStorageUnits.Megabyte)
  215.  
  216.    <Browsable(False)>
  217.    Public ReadOnly Property BufferSizeBytes As Integer
  218.        Get
  219.            Return CInt(Me.BufferSize.Size(DigitalStorageUnits.Byte))
  220.        End Get
  221.    End Property
  222.  
  223.    <DisplayName("Use Random Data")>
  224.    <Description("If True, uses random bytes to fill the dummy file content; othewise, fills the dummy file with zero bytes.")>
  225.    Public Property UseRandomData As Boolean = False
  226.  
  227. End Class
  228.  
  229. #End Region
  230.  
  231. #Region " SaveFileNameEditor "
  232.  
  233. Public NotInheritable Class SaveFileNameEditor : Inherits UITypeEditor
  234.  
  235.    Public Overrides Function GetEditStyle(context As ITypeDescriptorContext) As UITypeEditorEditStyle
  236.        Return UITypeEditorEditStyle.Modal
  237.    End Function
  238.  
  239.    Public Overrides Function EditValue(context As ITypeDescriptorContext, provider As IServiceProvider, value As Object) As Object
  240.        If context Is Nothing OrElse context.Instance Is Nothing OrElse provider Is Nothing Then
  241.            Return MyBase.EditValue(context, provider, value)
  242.        End If
  243.  
  244.        Using saveFileDialog As New SaveFileDialog()
  245.            If value IsNot Nothing Then
  246.                saveFileDialog.FileName = value.ToString()
  247.            End If
  248.  
  249.            saveFileDialog.Title = "Select a location to save the dummy file"
  250.            saveFileDialog.Filter = "All files (*.*)|*.*"
  251.            saveFileDialog.FileName = "File.dummy"
  252.            If saveFileDialog.ShowDialog() = DialogResult.OK Then
  253.                value = saveFileDialog.FileName
  254.            End If
  255.        End Using
  256.  
  257.        Return value
  258.    End Function
  259. End Class
  260.  
  261. #End Region
  262.  
  263. #Region " NativeMethods "
  264.  
  265. Namespace DevCase.Win32.NativeMethods
  266.  
  267.    <HideModuleName>
  268.    <SuppressUnmanagedCodeSecurity>
  269.    <SuppressMessage("CodeQuality", "IDE0079:Remove unnecessary suppression", Justification:="Required to migrate this code to .NET Core")>
  270.    <SuppressMessage("Interoperability", "CA1401:P/Invokes should not be visible", Justification:="")>
  271.    Public Module ShlwApi
  272.  
  273. #Region " ShlwApi.dll "
  274.  
  275.        <DllImport("ShlwApi.dll", SetLastError:=True, ExactSpelling:=True, CharSet:=CharSet.Ansi, BestFitMapping:=False, ThrowOnUnmappableChar:=True)>
  276.        Public Function StrFormatByteSize64A(number As ULong,
  277.                                            buffer As StringBuilder,
  278.                                            bufferSize As UInteger
  279.        ) As IntPtr
  280.        End Function
  281.  
  282.        <DllImport("ShlwApi.dll", SetLastError:=False, ExactSpelling:=True, CharSet:=CharSet.Unicode)>
  283.        Public Function StrFormatByteSizeEx(number As ULong,
  284.                                            flags As StrFormatByteSizeFlags,
  285.                                            buffer As StringBuilder,
  286.                                            bufferSize As UInteger
  287.        ) As Integer ' HResult
  288.        End Function
  289.  
  290. #End Region
  291.  
  292.    End Module
  293.  
  294. End Namespace
  295.  
  296. #End Region
  297.  
  298. #Region " StrFormatByteSizeFlags "
  299.  
  300. Namespace DevCase.Win32.Enums
  301.  
  302.    Public Enum StrFormatByteSizeFlags
  303.        RoundToNearest = 1
  304.        Truncate = 2
  305.    End Enum
  306.  
  307. End Namespace
  308.  
  309. #End Region
  310.  
  311. #Region " Size Units "
  312.  
  313. Namespace DevCase.Core.IO.DigitalInformation
  314.  
  315.    Public Enum DigitalStorageUnits As Long
  316.        [Byte] = CLng(2 ^ 0)
  317.        Kilobyte = CLng(2 ^ 10)
  318.        Megabyte = CLng(2 ^ 20)
  319.        Gigabyte = CLng(2 ^ 30)
  320.        Terabyte = CLng(2 ^ 40)
  321.        Petabyte = CLng(2 ^ 50)
  322.        Exabyte = CLng(2 ^ 60)
  323.    End Enum
  324.  
  325. End Namespace
  326.  
  327. #End Region
  328.  
  329. #Region " Filesize "
  330.  
  331. Namespace DevCase.Core.IO.FileSystem
  332.  
  333.    Public NotInheritable Class FileSize
  334.  
  335. #Region " Private Fields "
  336.  
  337.        Private ReadOnly bytesB As Double
  338.  
  339. #End Region
  340.  
  341. #Region " Properties "
  342.  
  343.        Public ReadOnly Property Size(sizeUnit As DigitalStorageUnits) As Double
  344.            Get
  345.                Return Convert(size:=Me.bytesB, fromUnit:=DigitalStorageUnits.Byte, toUnit:=sizeUnit)
  346.            End Get
  347.        End Property
  348.  
  349.        Public ReadOnly Property Size(sizeUnit As DigitalStorageUnits, decimalPrecision As Integer, Optional numberFormatInfo As NumberFormatInfo = Nothing) As String
  350.            Get
  351.                If numberFormatInfo Is Nothing Then
  352.                    numberFormatInfo = CultureInfo.CurrentCulture.NumberFormat
  353.                End If
  354.                Return Me.Size(sizeUnit).ToString(String.Format("N{0}", decimalPrecision), numberFormatInfo)
  355.            End Get
  356.        End Property
  357.  
  358.        Public Property SizeRounded As Double
  359.  
  360.        Public ReadOnly Property SizeRounded(decimalPrecision As Integer, Optional numberFormatInfo As NumberFormatInfo = Nothing) As String
  361.            Get
  362.                If numberFormatInfo Is Nothing Then
  363.                    numberFormatInfo = CultureInfo.CurrentCulture.NumberFormat
  364.                End If
  365.                Return Me.SizeRounded.ToString(String.Format("N{0}", decimalPrecision), numberFormatInfo)
  366.            End Get
  367.        End Property
  368.  
  369.        Public Property SizeUnit As DigitalStorageUnits
  370.        Public Property SizeUnitNameShort As String
  371.        Public Property SizeUnitNameLong As String
  372.  
  373. #End Region
  374.  
  375. #Region " Constructors "
  376.  
  377.        Private Sub New()
  378.        End Sub
  379.  
  380.        <DebuggerStepThrough>
  381.        Public Sub New(size As Double, sizeUnit As DigitalStorageUnits)
  382.  
  383.            Me.bytesB = System.Convert.ToDouble(size * sizeUnit)
  384.  
  385.            Select Case System.Math.Abs(Me.bytesB)
  386.  
  387.                Case Is >= DigitalStorageUnits.Petabyte
  388.                    Me.SizeRounded = Me.bytesB / DigitalStorageUnits.Petabyte
  389.                    Me.SizeUnit = DigitalStorageUnits.Petabyte
  390.                    Me.SizeUnitNameShort = "PB"
  391.                    Me.SizeUnitNameLong = "PetaBytes"
  392.  
  393.                Case Is >= DigitalStorageUnits.Terabyte
  394.                    Me.SizeRounded = Me.bytesB / DigitalStorageUnits.Terabyte
  395.                    Me.SizeUnit = DigitalStorageUnits.Terabyte
  396.                    Me.SizeUnitNameShort = "TB"
  397.                    Me.SizeUnitNameLong = "TeraBytes"
  398.  
  399.                Case Is >= DigitalStorageUnits.Gigabyte
  400.                    Me.SizeRounded = Me.bytesB / DigitalStorageUnits.Gigabyte
  401.                    Me.SizeUnit = DigitalStorageUnits.Gigabyte
  402.                    Me.SizeUnitNameShort = "GB"
  403.                    Me.SizeUnitNameLong = "GigaBytes"
  404.  
  405.                Case Is >= DigitalStorageUnits.Megabyte
  406.                    Me.SizeRounded = Me.bytesB / DigitalStorageUnits.Megabyte
  407.                    Me.SizeUnit = DigitalStorageUnits.Megabyte
  408.                    Me.SizeUnitNameShort = "MB"
  409.                    Me.SizeUnitNameLong = "MegaBytes"
  410.  
  411.                Case Is >= DigitalStorageUnits.Kilobyte
  412.                    Me.SizeRounded = Me.bytesB / DigitalStorageUnits.Kilobyte
  413.                    Me.SizeUnit = DigitalStorageUnits.Kilobyte
  414.                    Me.SizeUnitNameShort = "KB"
  415.                    Me.SizeUnitNameLong = "KiloBytes"
  416.  
  417.                Case Is >= DigitalStorageUnits.Byte, Is = 0
  418.                    Me.SizeRounded = Me.bytesB / DigitalStorageUnits.Byte
  419.                    Me.SizeUnit = DigitalStorageUnits.Byte
  420.                    Me.SizeUnitNameShort = "Bytes"
  421.                    Me.SizeUnitNameLong = "Bytes"
  422.            End Select
  423.  
  424.        End Sub
  425.  
  426. #End Region
  427.  
  428. #Region " Public Methods "
  429.  
  430.        Public Overrides Function ToString() As String
  431.            Return Me.ToString(CultureInfo.InvariantCulture.NumberFormat)
  432.        End Function
  433.  
  434.        Public Overloads Function ToString(provider As IFormatProvider) As String
  435.            Return If(Me.SizeUnit = DigitalStorageUnits.Byte,
  436.                String.Format(provider, "{0:0.##} {1}", System.Math.Floor(Me.SizeRounded * 100) / 100, Me.SizeUnitNameShort),
  437.                String.Format(provider, "{0:0.00} {1}", System.Math.Floor(Me.SizeRounded * 100) / 100, Me.SizeUnitNameShort))
  438.        End Function
  439.  
  440.        Public Function ToStringFormatByteSize(flags As StrFormatByteSizeFlags) As String
  441.  
  442.            Dim buffer As New StringBuilder(8, 16)
  443.            Dim result As Integer = NativeMethods.StrFormatByteSizeEx(CULng(Me.bytesB), flags, buffer, 16) ' HRESULT
  444.            If result <> 0 Then
  445.                Marshal.ThrowExceptionForHR(result)
  446.            End If
  447.  
  448.            Return buffer.ToString()
  449.        End Function
  450.  
  451. #End Region
  452.  
  453. #Region " Private Methods "
  454.  
  455.        <DebuggerStepThrough>
  456.        Private Shared Function Convert(size As Double,
  457.                                 fromUnit As DigitalStorageUnits,
  458.                                 toUnit As DigitalStorageUnits) As Double
  459.  
  460.            Dim bytes As Double = If(fromUnit = DigitalStorageUnits.Byte, size, System.Convert.ToDouble(size * fromUnit))
  461.  
  462.            If toUnit < fromUnit Then
  463.                Select Case toUnit
  464.                    Case DigitalStorageUnits.Byte
  465.                        Return bytes
  466.  
  467.                    Case DigitalStorageUnits.Kilobyte
  468.                        Return bytes / DigitalStorageUnits.Kilobyte
  469.  
  470.                    Case DigitalStorageUnits.Megabyte
  471.                        Return bytes / DigitalStorageUnits.Megabyte
  472.  
  473.                    Case DigitalStorageUnits.Gigabyte
  474.                        Return bytes / DigitalStorageUnits.Gigabyte
  475.  
  476.                    Case DigitalStorageUnits.Terabyte
  477.                        Return bytes / DigitalStorageUnits.Terabyte
  478.  
  479.                    Case DigitalStorageUnits.Petabyte
  480.                        Return bytes / DigitalStorageUnits.Petabyte
  481.  
  482.                    Case Else
  483.                        Throw New InvalidEnumArgumentException(argumentName:="toUnit", invalidValue:=CInt(toUnit),
  484.                                                               enumClass:=GetType(DigitalStorageUnits))
  485.                End Select
  486.  
  487.            ElseIf toUnit > fromUnit Then
  488.                Select Case toUnit
  489.  
  490.                    Case DigitalStorageUnits.Byte
  491.                        Return bytes
  492.  
  493.                    Case DigitalStorageUnits.Kilobyte
  494.                        Return bytes * DigitalStorageUnits.Kilobyte / (DigitalStorageUnits.Kilobyte ^ 2)
  495.  
  496.                    Case DigitalStorageUnits.Megabyte
  497.                        Return bytes * DigitalStorageUnits.Megabyte / (DigitalStorageUnits.Megabyte ^ 2)
  498.  
  499.                    Case DigitalStorageUnits.Gigabyte
  500.                        Return bytes * DigitalStorageUnits.Gigabyte / (DigitalStorageUnits.Gigabyte ^ 2)
  501.  
  502.                    Case DigitalStorageUnits.Terabyte
  503.                        Return bytes * DigitalStorageUnits.Terabyte / (DigitalStorageUnits.Terabyte ^ 2)
  504.  
  505.                    Case DigitalStorageUnits.Petabyte
  506.                        Return bytes * DigitalStorageUnits.Petabyte / (DigitalStorageUnits.Petabyte ^ 2)
  507.  
  508.                    Case Else
  509.                        Throw New InvalidEnumArgumentException(argumentName:="toUnit", invalidValue:=CInt(toUnit),
  510.                                                               enumClass:=GetType(DigitalStorageUnits))
  511.                End Select
  512.  
  513.            Else ' If toUnit = fromUnit
  514.                Return bytes
  515.  
  516.            End If
  517.        End Function
  518.  
  519. #End Region
  520.  
  521.    End Class
  522.  
  523. End Namespace
  524.  
  525. #End Region
  526.  
  527. #Region " FileSizeConverter "
  528.  
  529. Namespace DevCase.Runtime.TypeConverters
  530.  
  531.    Public Class FileSizeConverter : Inherits TypeConverter
  532.  
  533. #Region " Private Fields "
  534.  
  535.        Private ReadOnly sizeUnitsDictionary As Dictionary(Of String(), ULong)
  536.  
  537. #End Region
  538.  
  539. #Region " Constructors "
  540.  
  541.        Public Sub New()
  542.            Me.sizeUnitsDictionary = New Dictionary(Of String(), ULong)(StringComparison.OrdinalIgnoreCase) From {
  543.                {{"b", "byte", "bytes"}, 1UL},
  544.                {{"KB", "kilo", "kilos", "kilobyte", "kilobytes", "kilo byte", "kilo bytes"}, 1024UL},
  545.                {{"MB", "mega", "megas", "megabyte", "megabytes", "mega byte", "mega bytes"}, CULng(1024UL ^ 2UL)},
  546.                {{"GB", "giga", "gigas", "gigabyte", "gigabytes", "giga byte", "giga bytes"}, CULng(1024UL ^ 3UL)},
  547.                {{"TB", "tera", "teras", "terabyte", "terabytes", "tera byte", "tera bytes"}, CULng(1024UL ^ 4UL)},
  548.                {{"PB", "peta", "petas", "petabyte", "petabytes", "peta byte", "peta bytes"}, CULng(1024UL ^ 5UL)},
  549.                {{"EB", "exa", "exas", "exabyte", "exabytes", "exa byte", "exa bytes"}, CULng(1024UL ^ 6UL)}
  550.            }
  551.        End Sub
  552.  
  553. #End Region
  554.  
  555. #Region " Public Methods "
  556.  
  557.        Public Overrides Function CanConvertFrom(context As ITypeDescriptorContext, sourceType As Type) As Boolean
  558.  
  559.            Return sourceType Is GetType(String) OrElse
  560.                   MyBase.CanConvertFrom(context, sourceType)
  561.        End Function
  562.  
  563.        Public Overrides Function CanConvertTo(context As ITypeDescriptorContext, destinationType As Type) As Boolean
  564.  
  565.            Return destinationType Is GetType(ULong) OrElse
  566.                   destinationType Is GetType(String) OrElse
  567.                   MyBase.CanConvertTo(context, destinationType)
  568.        End Function
  569.  
  570.        <DebuggerStepThrough>
  571.        Public Overrides Function ConvertFrom(context As ITypeDescriptorContext, culture As CultureInfo, value As Object) As Object
  572.  
  573.            If TypeOf value Is String Then
  574.                Dim strValue As String = DirectCast(value, String)
  575.                If strValue.Contains("("c) Then
  576.                    strValue = strValue.Substring(0, strValue.IndexOf("("c))
  577.                End If
  578.                Dim bytes As ULong
  579.                If ULong.TryParse(strValue, bytes) Then
  580.                    Return bytes
  581.                End If
  582.                bytes = Me.ParseFileSizeString(strValue)
  583.                If bytes <> 0UL Then
  584.                    If context.PropertyDescriptor IsNot Nothing AndAlso context.PropertyDescriptor.PropertyType Is GetType(FileSize) Then
  585.                        Return New FileSize(bytes, DigitalStorageUnits.Byte)
  586.                    Else
  587.                        Return DirectCast(bytes, Object)
  588.                    End If
  589.                End If
  590.            End If
  591.  
  592.            Return MyBase.ConvertFrom(context, culture, value)
  593.        End Function
  594.  
  595.        <DebuggerStepThrough>
  596.        Public Overrides Function ConvertTo(context As ITypeDescriptorContext, culture As CultureInfo, value As Object, destinationType As Type) As Object
  597.            If destinationType Is GetType(String) Then
  598.                Dim bytes As ULong = If((TypeOf value Is FileSize), CULng(DirectCast(value, FileSize).Size(DigitalStorageUnits.Byte)), DirectCast(value, ULong))
  599.                Dim formattedSize As String = Me.FormatByteFileSize(bytes)
  600.                Return If(bytes < 1024, String.Format("{0}", formattedSize), String.Format("{0} ({1:N0} bytes)", formattedSize, bytes))
  601.            End If
  602.  
  603.            Return MyBase.ConvertTo(context, culture, value, destinationType)
  604.        End Function
  605.  
  606. #End Region
  607.  
  608. #Region " Private Methods "
  609.  
  610.        <DebuggerStepThrough>
  611.        Private Function ParseFileSizeString(sizeString As String) As ULong
  612.  
  613.            Dim trimmedSizeString As String = sizeString.Trim()
  614.            If trimmedSizeString.Contains("("c) Then
  615.                trimmedSizeString = trimmedSizeString.Substring(0, trimmedSizeString.IndexOf("("c))
  616.            End If
  617.  
  618.            For Each kvp As KeyValuePair(Of String(), ULong) In sizeUnitsDictionary
  619.                For Each sizeUnitName As String In kvp.Key
  620.                    If trimmedSizeString.EndsWith(sizeUnitName, StringComparison.OrdinalIgnoreCase) Then
  621.                        Dim numString As String = trimmedSizeString.Substring(0, trimmedSizeString.Length - sizeUnitName.Length).Trim()
  622.                        Dim num As Double
  623.                        Dim numberFormat As IFormatProvider
  624. #If NETCOREAPP Then
  625.                        numberFormat = Thread.CurrentThread.CurrentUICulture.NumberFormat
  626. #Else
  627.                        numberFormat = My.Application.UICulture.NumberFormat
  628. #End If
  629.                        If Double.TryParse(numString, NumberStyles.Number, numberFormat, num) Then
  630.                            Try
  631.                                Return CULng((num * kvp.Value))
  632.                            Catch ex As OverflowException
  633.                                Return ULong.MaxValue
  634.                            Catch ex As Exception
  635.                                Throw
  636.                            End Try
  637.                        End If
  638.                    End If
  639.                Next sizeUnitName
  640.            Next kvp
  641.  
  642.            Throw New Exception("Cannot parse the specified file size value.")
  643.        End Function
  644.  
  645.  
  646.        <DebuggerStepThrough>
  647.        Private Function FormatByteFileSize(bytes As ULong) As String
  648.            Dim unitIndex As Integer = 0
  649.            Dim fileSize As Double = bytes
  650.  
  651.            While (fileSize >= 1024) AndAlso (unitIndex < sizeUnitsDictionary.Count - 1)
  652.                fileSize /= 1024
  653.                unitIndex += 1
  654.            End While
  655.  
  656.            Return If(unitIndex = 0,
  657.                       String.Format("{0} bytes", fileSize),
  658.                       String.Format("{0:F2} {1}", fileSize, sizeUnitsDictionary.ElementAt(unitIndex).Key(0)).Replace(",00", ""))
  659.        End Function
  660.  
  661. #End Region
  662.  
  663.    End Class
  664.  
  665. End Namespace
  666.  
  667. #End Region
  668.  
  669. #Region " PropertyGridExtensions "
  670.  
  671. Namespace DevCase.Extensions.PropertyGridExtensions
  672.  
  673.    <HideModuleName>
  674.    Public Module PropertyGridExtensions
  675.  
  676. #Region " Public Extension Methods "
  677.  
  678.        <DebuggerStepThrough>
  679.        <Extension>
  680.        <EditorBrowsable(EditorBrowsableState.Always)>
  681.        Public Function IsInitialized(propGrid As PropertyGrid) As Boolean
  682.  
  683.            Return PropertyGridExtensions.GetInternalLabelWidth(propGrid) <> -1
  684.        End Function
  685.  
  686.        <DebuggerStepThrough>
  687.        <Extension>
  688.        <EditorBrowsable(EditorBrowsableState.Always)>
  689.        Public Sub SetSplitterPosition(propGrid As PropertyGrid, xPos As Integer)
  690.  
  691.            If Not PropertyGridExtensions.IsInitialized(propGrid) Then
  692.                Throw New InvalidOperationException("The PropertyGrid must be initialized in order to set the splitter control position.")
  693.            End If
  694.  
  695.            Dim internalGridView As Control = PropertyGridExtensions.GetPropertyGridInternal(propGrid)
  696.            Dim moveSplitterToMethod As MethodInfo = internalGridView.GetType().GetMethod("MoveSplitterTo", BindingFlags.NonPublic Or BindingFlags.Instance)
  697.            moveSplitterToMethod.Invoke(internalGridView, {xPos})
  698.        End Sub
  699.  
  700. #End Region
  701.  
  702. #Region " Private Methods "
  703.  
  704.        Private Function GetPropertyGridInternal(propGrid As PropertyGrid) As Control
  705.  
  706.            ' Class: System.Windows.Forms.PropertyGridInternal.PropertyGridView
  707.  
  708.            Dim getPropertyGridViewMethod As MethodInfo = GetType(PropertyGrid).GetMethod("GetPropertyGridView", BindingFlags.NonPublic Or BindingFlags.Instance)
  709.            Dim gridView As Control = DirectCast(getPropertyGridViewMethod.Invoke(propGrid, Array.Empty(Of Object)()), Control)
  710.            Return gridView
  711.  
  712.            ' We can also retrieve the internal PropertyGridView this other way:
  713.            ' ------------------------------------------------------------------
  714.            ' Dim gridViewFieldInfo As FieldInfo = propGrid.GetType().GetField("gridView", BindingFlags.Instance Or BindingFlags.NonPublic)
  715.            ' Dim gridView As Control = DirectCast(gridViewFieldInfo.GetValue(propGrid), Control)
  716.            ' Return gridView
  717.        End Function
  718.  
  719.        Private Function GetInternalLabelWidth(propGrid As PropertyGrid) As Integer
  720.  
  721.            Dim internalGridView As Control = PropertyGridExtensions.GetPropertyGridInternal(propGrid)
  722.            Dim propInfo As PropertyInfo = internalGridView.GetType().GetProperty("InternalLabelWidth", BindingFlags.NonPublic Or BindingFlags.Instance)
  723.            Return CInt(propInfo.GetValue(internalGridView))
  724.        End Function
  725.  
  726. #End Region
  727.  
  728.    End Module
  729.  
  730. End Namespace
  731.  
  732. #End Region
  733. '@
  734. $assembly = Add-Type -TypeDefinition $vbCode `
  735.                      -CodeDomProvider (New-Object Microsoft.VisualBasic.VBCodeProvider) `
  736.                      -PassThru `
  737.                      -ReferencedAssemblies "Microsoft.VisualBasic.dll", `
  738.                                            "System.Windows.Forms.dll", `
  739.                                            "System.Security.dll", `
  740.                                            "System.Collections.dll", `
  741.                                            "System.Drawing.dll", `
  742.                                            "System.Globalization.dll", `
  743.                                            "System.Reflection.dll", `
  744.                                            "System.Linq.dll", `
  745.                                            "System.IO.dll", `
  746.                                            "System.Xml.dll", `
  747.                                            "System.Xml.Serialization.dll", `
  748.                                            "System.dll" `
  749.                      | where { $_.IsPublic }
  750.  
  751.  
  752. function Get-FormattedSize {
  753.    param (
  754.        [int64]$sizeInBytes
  755.    )
  756.  
  757.    $buffer = New-Object System.Text.StringBuilder 24
  758.    $resultPtr = [DevCase.Win32.NativeMethods.ShlwApi]::StrFormatByteSize64A($sizeInBytes, $buffer, $buffer.Capacity)
  759.  
  760.    if ($resultPtr -eq [IntPtr]::Zero) {
  761.        return "Error formatting the file size."
  762.    } else {
  763.        return $buffer.ToString()
  764.    }
  765. }
  766.  
  767. function WriteDummyFile {
  768.    param (
  769.        [string]$FilePath,
  770.        [uint64]$FileSize,
  771.        [uint64]$BufferSize = 4MB,
  772.        [bool]$randomData = $false
  773.    )
  774.  
  775.    $formattedFileSize = Get-FormattedSize -sizeInBytes $FileSize
  776.  
  777.    $fs = [System.IO.File]::Create($FilePath)
  778.  
  779.    if ($BufferSize -ge $FileSize) {
  780.        $BufferSize = [math]::Floor($FileSize / 2)
  781.    }
  782.  
  783.    [int64]$bytesWritten = 0
  784.    $buffer = New-Object byte[] $BufferSize
  785.    $rand = New-Object Random
  786.  
  787.    Write-Host "Creating dummy file at '$FilePath' with a size of $formattedFileSize..."
  788.  
  789.    while ($bytesWritten -lt $FileSize) {
  790.        $bytesToWrite = [math]::Min($BufferSize, $FileSize - $bytesWritten)
  791.  
  792.        if ($randomData) {
  793.            $rand.NextBytes($buffer)
  794.        } else {
  795.            [Array]::Clear($buffer, 0, $bytesToWrite)
  796.        }
  797.  
  798.        $fs.Write($buffer, 0, $bytesToWrite)
  799.  
  800.        $bytesWritten += $bytesToWrite
  801.        $formattedBytesWritten = Get-FormattedSize -sizeInBytes $bytesWritten
  802.  
  803.        $progressPercent = [math]::Min(($bytesWritten / $FileSize) * 100, 100)
  804.  
  805.        Write-Progress -PercentComplete $progressPercent -Status "$FilePath" -Activity "Writing dummy file..." -CurrentOperation "$formattedBytesWritten written."
  806.    }
  807.        Write-Progress -PercentComplete 100 -Status "$FilePath" -Activity "Dummy file has been written." -CurrentOperation "$formattedBytesWritten written."
  808.  
  809.    $fs.Close()
  810.  
  811.    Write-Host ""
  812.    Write-Host ""
  813.    Write-Host ""
  814.    Write-Host ""
  815.    Write-Host ""
  816.    Write-Host ""
  817.    Write-Host ""
  818.    Write-Host ""
  819.    Write-Host ""
  820.    Write-Host "Dummy file successfully created at '$FilePath' with a size of $formattedFileSize."
  821. }
  822.  
  823.  
  824. $form = New-Object CreateDummyFileOptionsForm
  825. $dlgResult = $form.ShowDialog()
  826.  
  827. if ($dlgResult -eq [System.Windows.Forms.DialogResult]::OK) {
  828.    $fileOptions = $form.DummyFileOptions
  829.    WriteDummyFile -FilePath $fileOptions.FilePath -FileSize $fileOptions.FileSizeBytes -BufferSize $fileOptions.BufferSizeBytes -randomData $fileOptions.UseRandomData
  830. } else {
  831.    Write-Host "Operation canceled. No file selected."
  832. }
  833.  
  834. Write-Host "Press any key to exit..."
  835. $key = [System.Console]::ReadKey($true)
  836. Exit(0)
  837.  
Páginas: [1] 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ... 107
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines