Last active
January 30, 2025 13:10
-
-
Save lumiobrie/eef3064b115cdafe11742ad326420ebc to your computer and use it in GitHub Desktop.
Módulo multipropósito para configuraciones varias en Windows y análisis y tratamiento de archivos de audio
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using namespace System.IO; | |
function Get-GistContent { | |
param ( | |
[Parameter(Position = 0, Mandatory = $true)] | |
[string] $gistId | |
) | |
# Define the Gist API URL using the provided gistId | |
$apiUrl = "https://api.github.com/gists/$gistId" | |
# Make the request to the GitHub API | |
$response = Invoke-RestMethod -Uri $apiUrl -UseBasicParsing | |
# Get the first file from the gist (assumes there's only one file | |
$gistFiles = $response.files | |
$firstFile = $gistFiles.PSObject.Properties.Name | Select-Object -First 1 | |
# Get the content of the first file | |
$content = $gistFiles.$firstFile.content | |
# Return the content | |
return $content | |
} | |
function Import-PowerToolkit { | |
if (-not (Get-Module -Name PowerToolkit)) { | |
$psModulePath = "$(($env:PSModulePath -split ([System.IO.Path]::PathSeparator))[0])\PowerToolkit\PowerToolkit.psm1" | |
New-Item -Path $psModulePath -ItemType File -Force | |
Get-GistContent "eef3064b115cdafe11742ad326420ebc" | Out-File -FilePath $psModulePath | |
} | |
Import-Module PowerToolkit -Force | |
} | |
#region Partitions Manager | |
function Split-VolumeFromC { | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory, Position = 0)] | |
[string] | |
$DriveLetter, | |
[Parameter(Mandatory = $false, Position = 1)] | |
[string] | |
$DriveLabel = "Data", | |
[Parameter(Mandatory = $false, Position = 2)] | |
[double] | |
$RemainingPercentageOnDriveC = 0.7 | |
) | |
if (Get-Partition -DiskNumber 0 | Where-Object DriveLetter -eq $DriveLetter) { | |
Write-Error "There was already a $DriveLetter partition" | |
return | |
} | |
$DriveFormatInfo = Get-Partition -DiskNumber 0 | Where-Object DriveLetter -eq "C" | Select-Object -First 1 | ForEach-Object { | |
$newVolumeSize = $_.Size - [math]::Round($_.Size * $RemainingPercentageOnDriveC) | |
[PSCustomObject]@{ | |
CurrentPartitionNumber = $_.PartitionNumber; | |
NewVolumeLetter = $DriveLetter; | |
NewVolumeFileSystem = "ntfs"; | |
NewVolumeLabel = "Data"; | |
NewVolumeSize = $newVolumeSize | |
NewVolumeSizeMB = [math]::floor($newVolumeSize / 1MB) | |
} } | |
if ((Get-Volume -DriveLetter "C").SizeRemaining -le $DriveFormatInfo.NewVolumeSize) { | |
Write-Error "There is not enough size on C drive" | |
return | |
} | |
# Step 2: Create DiskPart Script | |
$diskpartScriptContent = @" | |
select disk 0 | |
select partition $($DriveFormatInfo.CurrentPartitionNumber) | |
shrink desired=$($DriveFormatInfo.NewVolumeSizeMB) | |
create partition primary size=$($DriveFormatInfo.NewVolumeSizeMB) | |
format fs=$($DriveFormatInfo.NewVolumeFileSystem) quick label=$($DriveFormatInfo.NewVolumeLabel) | |
assign letter=$($DriveFormatInfo.NewVolumeLetter) | |
"@ | |
# Step 3: Save DiskPart Script to a Temporary File | |
# Save with a `.txt` extension for compatibility | |
$tempScript = "$env:temp\diskpart_script.txt" | |
Set-Content -Path $tempScript -Value $diskpartScriptContent -Encoding ASCII | |
# Step 4: Run DiskPart with the Script | |
Start-Process -FilePath "diskpart.exe" -ArgumentList "/s $tempScript" -Wait -NoNewWindow | |
# Cleanup: Remove the temporary file | |
Remove-Item -Path $tempScript -Force | |
Get-Volume -DriveLetter $DriveLetter | |
} | |
function Merge-VolumeWithC { | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory, Position = 0)] | |
[ValidateSet("D", "E", "F", "G", "H", "I", "J", "K")] | |
[char] | |
$DriveLetter | |
) | |
$Drive = Get-Partition -DiskNumber 0 | Where-Object DriveLetter -eq $DriveLetter; | |
if (-not $Drive) { | |
Write-Error "There is not a $DriveLetter Drive" | |
return | |
} | |
$DriveC = Get-Partition -DiskNumber 0 | Where-Object DriveLetter -eq "C"; | |
# Step 2: Create DiskPart Script | |
$diskpartScriptContent = @" | |
select disk 0 | |
select partition $($Drive.PartitionNumber) | |
delete partition override | |
select partition $($DriveC.PartitionNumber) | |
extend | |
exit | |
"@ | |
$tempScript = "$env:temp\diskpart_script.txt" | |
Set-Content -Path $tempScript -Value $diskpartScriptContent -Encoding ASCII | |
# Step 4: Run DiskPart with the Script | |
Start-Process -FilePath "diskpart.exe" -ArgumentList "/s $tempScript" -Wait -NoNewWindow | |
# Cleanup: Remove the temporary file | |
Remove-Item -Path $tempScript -Force | |
Get-Volume -DriveLetter C | |
} | |
#endregion | |
#region Special Folders | |
function Set-SpecialFolders { | |
param ( | |
[Parameter(Mandatory, Position = 0)] | |
[ValidateSet("C", "D")] | |
[string]$TargetVolume | |
) | |
if ($TargetVolume.ToUpper() -eq "C") { | |
$prefix = $env:USERPROFILE | |
} | |
else { | |
$prefix = "D:" | |
} | |
# Consolidate paths and icons into $shellFolders | |
# Dynamically retrieve GUIDs from the User Shell Folders registry key | |
$regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" | |
$specialFolders = Get-ItemProperty -Path $regPath | Select-Object * -ExcludeProperty PS* | |
# Helper function to match GUIDs by associated folder names | |
function Get-GUIDForFolder { | |
param ( | |
[Parameter(Mandatory)] | |
[string]$FolderName | |
) | |
foreach ($key in $specialFolders.PSObject.Properties) { | |
# Ensure we're only processing GUID keys (not friendly names like "Downloads") | |
if ($key.Name -match "^{[A-Fa-f0-9\-]+}$") { | |
$folderPath = $specialFolders.$($key.Name) | |
# Match folder name based on its path (e.g., ends with "\Downloads") | |
if ($folderPath -like "*\$FolderName") { | |
return $key.Name # Return the GUID | |
} | |
} | |
} | |
throw "Could not find GUID for $FolderName" | |
} | |
# Consolidate paths and icons into $shellFolders | |
$shellFolders = @{ | |
"Personal" = @{ | |
Path = Join-Path $prefix "Documents"; Icon = "%SystemRoot%\system32\imageres.dll,-112"; GUID = "" | |
} | |
"Desktop" = @{ | |
Path = Join-Path $prefix "Desktop"; Icon = "%SystemRoot%\system32\imageres.dll,-183"; GUID = "" | |
} | |
"Downloads" = @{ | |
Path = Join-Path $prefix "Downloads"; Icon = "%SystemRoot%\system32\imageres.dll,-184"; GUID = (Get-GUIDForFolder -FolderName "Downloads") | |
} | |
"My Pictures" = @{ | |
Path = Join-Path $prefix "Pictures"; Icon = "%SystemRoot%\system32\imageres.dll,-113"; GUID = "" | |
} | |
"My Music" = @{ | |
Path = Join-Path $prefix "Music"; Icon = "%SystemRoot%\system32\imageres.dll,-108"; GUID = "" | |
} | |
"My Video" = @{ | |
Path = Join-Path $prefix "Videos"; Icon = "%SystemRoot%\system32\imageres.dll,-189"; GUID = "" | |
} | |
} | |
# Registry paths for User Shell Folders and Shell Folders | |
$regPathUserShellFolders = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" | |
$regPathShellFolders = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" | |
# Process each special folder | |
foreach ($key in $shellFolders.Keys) { | |
$newPath = $shellFolders[$key].Path | |
$iconResource = $shellFolders[$key].Icon | |
if ($key -eq "Downloads") { | |
$key = $shellFolders[$key].GUID | |
} | |
# Get the current path (oldPath) before modifying the registry | |
$oldPath = (Get-ItemProperty -Path $regPathUserShellFolders -Name $key).$key | |
if ($oldPath -eq $newPath) { | |
continue; | |
} | |
# Create the new folder path if it doesn't exist | |
if (-not (Test-Path $newPath)) { | |
Write-Host "Creating folder: $newPath" | |
New-Item -ItemType Directory -Path $newPath -Force | Out-Null | |
} | |
# Update registry for both User Shell Folders and Shell Folders | |
Set-ItemProperty -Path $regPathUserShellFolders -Name $key -Value $newPath | |
Set-ItemProperty -Path $regPathShellFolders -Name $key -Value $newPath | |
Write-Host "Configured '$key' to '$newPath'" | |
# Move files from the old location to the new location | |
if (Test-Path $oldPath) { | |
Write-Host "Moving files from '$oldPath' to '$newPath'..." | |
Move-Item -Path "$oldPath\*" -Destination $newPath -Force -ErrorAction SilentlyContinue | |
# Remove the old folder if it's empty | |
if ((Get-ChildItem -Path $oldPath -Recurse -ErrorAction SilentlyContinue | Measure-Object).Count -eq 0) { | |
Write-Host "Deleting empty folder: $oldPath" | |
Remove-Item -Path $oldPath -Recurse -Force | |
} | |
else { | |
Write-Host "Skipped deleting $oldPath because it contains remaining files or folders." | |
} | |
} | |
# Create or update the desktop.ini file for special icons | |
$desktopIniPath = Join-Path $newPath "desktop.ini" | |
$desktopIniContent = @" | |
[.ShellClassInfo] | |
IconResource=$iconResource | |
"@ | |
Set-Content -Path $desktopIniPath -Value $desktopIniContent -Force | |
# Set desktop.ini as hidden and system | |
attrib +h +s $desktopIniPath | |
# Set folder as System and ReadOnly | |
attrib +s +r $newPath | |
Write-Host "Special icon configured for '$key' in '$newPath'" | |
} | |
# Refresh Explorer to apply changes | |
Stop-Process -Name explorer -Force | |
Start-Process explorer | |
} | |
function Get-SpecialFolders { | |
# Create the Shell.Application object | |
$shell = New-Object -ComObject Shell.Application | |
# List of common special folders with their Shell folder names | |
$specialFolders = @( | |
'shell:Desktop', | |
'shell:Personal', | |
'shell:Downloads', | |
'shell:My Music', | |
'shell:My Pictures', | |
'shell:My Video' | |
) | |
# Loop through and retrieve each special folder's path | |
foreach ($folder in $specialFolders) { | |
$path = $shell.Namespace($folder).Self.Path | |
Write-Output "${folder}: $path" | |
} | |
} | |
function Get-SpecialFolder { | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory, Position = 0)] | |
[ValidateSet("Desktop", "Documents", "Downloads", "Music", "Pictures", "Videos")] | |
[String] | |
$FolderName | |
) | |
# Create the Shell.Application object | |
$shell = New-Object -ComObject Shell.Application | |
$folderName = $FolderName.ToUpper(); | |
# List of common special folders with their Shell folder names | |
$specialFolders = @{ | |
Desktop = 'shell:Desktop' | |
Documents = 'shell:Personal' | |
Downloads = 'shell:Downloads' | |
Music = 'shell:My Music' | |
Pictures = 'shell:My Pictures' | |
Videos = 'shell:My Video' | |
} | |
try { | |
$path = $shell.Namespace($specialFolders[$folderName]).Self.Path | |
if (-not $path) { | |
throw "Could not resolve the path for folder: $FolderName" | |
} | |
} | |
catch { | |
Write-Error $_.Exception.Message | |
return $null | |
} | |
Write-Output $path | |
} | |
#endregion | |
#region Windows Configuration | |
function New-InitialAdminSetup { | |
if (-not (Get-Partition -DiskNumber 0 | Where-Object DriveLetter -eq "D")) { | |
Split-VolumeFromC "D" | |
} | |
Set-SpecialFolders "D" | |
Remove-Telemetry | |
Get-Fonts | |
Set-HiddenItemsVisibility | |
} | |
function Get-Fonts { | |
# Step 1: Get the latest version tag from the GitHub API | |
$apiUrl = "https://api.github.com/repos/ryanoasis/nerd-fonts/releases/latest" | |
$response = Invoke-RestMethod -Uri $apiUrl -UseBasicParsing | |
# Extract the tag name (the version number, e.g., v3.2.1) | |
$latestVersion = $response.tag_name | |
Write-Host "The latest version of nerd-fonts is: $latestVersion" | |
# Step 2: Define the URL for the CascadiaCode.zip based on the latest version | |
$zipUrl = "https://github.com/ryanoasis/nerd-fonts/releases/download/$latestVersion/CascadiaCode.zip" | |
# Step 3: Define where to download the file (in this example, the Downloads folder) | |
$downloadPath = "$(Get-SpecialFolder Downloads)\CascadiaCode.zip" | |
# Step 4: Download the zip file | |
Invoke-WebRequest -Uri $zipUrl -OutFile $downloadPath | |
Write-Host "Downloaded CascadiaCode.zip to $downloadPath" | |
# Step 5: Unzip the file to a destination folder (e.g., "UnzippedCascadiaCode" in Downloads) | |
$destinationPath = "$(Get-SpecialFolder Downloads)\UnzippedCascadiaCode" | |
# Cargar el ensamblado necesario en PowerShell 5 | |
Add-Type -AssemblyName System.IO.Compression.FileSystem | |
[System.IO.Compression.ZipFile]::ExtractToDirectory($downloadPath, $destinationPath) | |
Write-Host "Extracted CascadiaCode.zip to $destinationPath" | |
# Step 6: Define the system fonts directory (or user fonts directory) | |
$fontsDirectory = "$env:WINDIR\Fonts" | |
# Alternatively, to install fonts for the current user only (without admin privileges), use: | |
# $fontsDirectory = "$env:USERPROFILE\AppData\Local\Microsoft\Windows\Fonts" | |
# Step 7: Find all font files (.ttf or .otf) in the unzipped folder | |
$fontFiles = Get-ChildItem -Path $destinationPath -Include *.ttf, *.otf -Recurse | |
# Step 8: Copy the font files to the system fonts directory (requires admin privileges) | |
foreach ($fontFile in $fontFiles) { | |
$destinationFontPath = Join-Path $fontsDirectory $fontFile.Name | |
Copy-Item -Path $fontFile.FullName -Destination $destinationFontPath -Force | |
Write-Host "Installed $($fontFile.Name) to $fontsDirectory" | |
} | |
# Step 9: Register the fonts in the Windows registry | |
foreach ($fontFile in $fontFiles) { | |
$fontName = [System.IO.Path]::GetFileNameWithoutExtension($fontFile.Name) | |
$fontRegistryPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" | |
New-ItemProperty -Path $fontRegistryPath -Name "$fontName (TrueType)" -Value $fontFile.Name -PropertyType String -Force | |
Write-Host "Registered $($fontFile.Name) in the registry." | |
} | |
Write-Host "All fonts have been installed successfully!" | |
} | |
function Update-ProfileDependencies { | |
Install-Module -Name Terminal-Icons -Repository PSGallery -Scope CurrentUser | |
winget upgrade --id JanDeDobbeleer.OhMyPosh -s winget --accept-source-agreements --accept-package-agreements | |
if ($LASTEXITCODE -ne 0) { | |
Write-Host "Oh My Posh is not installed. Installing it now..." | |
winget install JanDeDobbeleer.OhMyPosh -s winget --accept-source-agreements --accept-package-agreements | |
} | |
else { | |
Write-Host "Oh My Posh is already up to date." | |
} | |
} | |
<# | |
Para que el PROFILE funcione, ejecutar primero los siguientes dos comandos comentados: | |
Install-Module -Name Terminal-Icons -Repository PSGallery | |
winget install JanDeDobbeleer.OhMyPosh -s winget | |
#> | |
function Set-PSProfile { | |
$ohMyPoshConfigGistId = "1f69b28bfcc4f7716e49eb5bb34d7b2c" | |
$ohMyPoshConfigurationPath = "$env:POSH_THEMES_PATH\ohmyposhv3-v2.json" | |
Get-GistContent $ohMyPoshConfigGistId | Out-File -FilePath $ohMyPoshConfigurationPath | |
$powerShellProfileGistId = "25f5550ad186189e0e68916c6d7f44c3" | |
New-Item -Path $PROFILE -ItemType File -Force | |
(Get-GistContent $powerShellProfileGistId) ` | |
-replace 'Import-Module z', '#Import-Module z' ` | |
-replace 'c:\\Users\\scottha\\OneDrive\\poshv4.json', '$env:POSH_THEMES_PATH/ohmyposhv3-v2.json' | ` | |
Out-File -FilePath $PROFILE | |
. $PROFILE | |
} | |
function Set-HiddenItemsVisibility { | |
#region Registry Helpers | |
function Set-RegistryValue { | |
param ( | |
[string]$RegistryPath, | |
[string]$PropertyName, | |
[string]$PropertyType = "DWORD", | |
[int]$PropertyValue = 0 | |
) | |
try { | |
# Verificar si la ruta existe, si no, crearla | |
if (-not (Test-Path $RegistryPath)) { | |
New-Item -Path $RegistryPath -Force | |
} | |
# Crear o actualizar el valor del registro | |
New-ItemProperty -Path $RegistryPath -Name $PropertyName -Value $PropertyValue -PropertyType $PropertyType -Force | |
# Confirmar que el valor se ha creado o actualizado correctamente | |
$result = Get-ItemProperty -Path $RegistryPath -Name $PropertyName | |
Write-Host "Clave creada/actualizada: $($result.$PropertyName) en $RegistryPath" | |
} | |
catch { | |
Write-Host "Error al crear/actualizar la clave o valor: $_" -ForegroundColor Red | |
} | |
} | |
# Función para crear una clave vacía en el registro | |
function Set-EmptyRegistryKey { | |
param ( | |
[string]$RegistryPath, | |
[string]$SubKeyName | |
) | |
try { | |
# Verificar si la ruta de la clave padre existe, si no, crearla | |
if (-not (Test-Path $RegistryPath)) { | |
New-Item -Path $RegistryPath -Force | |
} | |
# Verificar si la subclave existe, si no, crearla | |
$subKeyPath = "$RegistryPath\$SubKeyName" | |
if (-not (Test-Path $subKeyPath)) { | |
New-Item -Path $subKeyPath -Force | |
} | |
# Vaciar el valor predeterminado de la subclave | |
Set-ItemProperty -Path $subKeyPath -Name "(default)" -Value "" | |
Write-Host "Subclave creada y valor predeterminado vaciado en: $subKeyPath" | |
} | |
catch { | |
Write-Host "Error al crear la subclave o vaciar el valor predeterminado: $_" -ForegroundColor Red | |
} | |
} | |
#endregion | |
# 1. Desactivar la telemetría | |
Set-RegistryValue -RegistryPath "HKLM:\Software\Policies\Microsoft\Windows\DataCollection" -PropertyName "AllowTelemetry" -PropertyValue 0 | |
# 2. Desactivar sugerencias de la barra de búsqueda | |
Set-RegistryValue -RegistryPath "HKCU:\Software\Policies\Microsoft\Windows\Explorer" -PropertyName "DisableSearchBoxSuggestions" -PropertyValue 1 | |
# 3. Crear clave CLSID y vaciar el valor predeterminado en InprocServer32 | |
Set-EmptyRegistryKey -RegistryPath "HKCU:\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}" -SubKeyName "InprocServer32" | |
# 4. Mostrar extensiones de archivos conocidos | |
Set-RegistryValue -RegistryPath "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -PropertyName "HideFileExt" -PropertyValue 0 | |
# 5. Mostrar archivos y carpetas ocultas | |
Set-RegistryValue -RegistryPath "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -PropertyName "Hidden" -PropertyValue 1 | |
# 6. Mostrar archivos protegidos del sistema | |
# Set-RegistryValue -RegistryPath "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -PropertyName "ShowSuperHidden" -PropertyValue 1 | |
# Reiniciar el proceso explorer.exe para aplicar los cambios | |
Stop-Process -Name explorer -Force | |
Start-Process explorer | |
} | |
function Remove-Telemetry { | |
# Define the URL for the hosts file to be downloaded | |
$downloadUrl = "https://raw.githubusercontent.com/hagezi/dns-blocklists/main/hosts/native.winoffice.txt" | |
# Define the path to the system hosts file | |
$hostsFilePath = "C:\Windows\System32\drivers\etc\hosts" | |
# Download the content from the URL | |
$hostsContent = Invoke-WebRequest -Uri $downloadUrl -UseBasicParsing | |
# Check if the content was successfully downloaded | |
if ($hostsContent.StatusCode -eq 200) { | |
Write-Host "Downloaded new hosts content successfully." | |
# Overwrite the system hosts file with the downloaded content | |
$hostsContent.Content | Set-Content -Path $hostsFilePath -Force -Encoding UTF8 | |
Write-Host "Hosts file has been replaced successfully." | |
} | |
else { | |
Write-Host "Failed to download the content. Status code: $($hostsContent.StatusCode)" | |
} | |
} | |
#endregion | |
#region Audio tools | |
<# | |
.SYNOPSIS | |
Converts audio files of a specified format to WAV format. | |
.DESCRIPTION | |
The ConvertTo-Wav function searches for audio files in the specified format within a directory (non-recursively) | |
and converts each file to WAV format. You can specify the directory to search and an optional output directory. | |
.PARAMETER Format | |
Specifies the format of the input audio files (e.g., "mp3", "ogg", "opus"). | |
.PARAMETER Path | |
Specifies the path to the directory containing the input files. Defaults to the current directory. | |
.PARAMETER OutputDirectory | |
Specifies the directory to save the converted WAV files. Defaults to a folder named "Output" in the current directory. | |
.EXAMPLE | |
ConvertTo-Wav -Format "mp3" -Path "C:\path\to\source" -OutputDirectory "C:\path\to\output" | |
Description: | |
Converts all MP3 files in the specified source directory to WAV format and saves them in the specified output directory. | |
.EXAMPLE | |
ConvertTo-Wav -Format "ogg" | |
Description: | |
Converts all OGG files in the current directory to WAV format, saving the converted files in a folder named "Output" in the current directory. | |
.NOTES | |
Requires FFmpeg to be installed and accessible in the system PATH. | |
#> | |
function ConvertTo-Wav { | |
[CmdletBinding()] # Enables support for -Verbose and advanced function features | |
param ( | |
[Parameter( | |
Mandatory = $true, | |
Position = 0, | |
HelpMessage = "Specify the input audio format (e.g., 'opus', 'mp3', 'ogg')" | |
)] | |
[ValidateSet("opus", "mp3", "ogg")] | |
[string]$Format, | |
[Parameter( | |
Position = 1, | |
Mandatory = $false, | |
HelpMessage = "Specify the directory path with the input files." | |
)] | |
[string]$Path = (Get-Location).Path, | |
#Specify an optional output directory | |
[Parameter( | |
Position = 2, | |
Mandatory = $false, | |
HelpMessage = "Specify the directory to save converted WAV files." | |
)] | |
[string]$OutputDirectory = "./Output" | |
) | |
# Resolve absolute paths for input and output directories | |
$resolvedPath = Resolve-Path -Path $Path | |
# Validate that the input directory exists | |
if (!(Test-Path -Path $resolvedPath -PathType Container)) { | |
Write-Error "The directory $resolvedPath doesn't exist." | |
return | |
} | |
# Check if FFmpeg is installed and available | |
if (!(Get-Command ffmpeg -ErrorAction SilentlyContinue)) { | |
Write-Error "FFmpeg is not installed or is not in your system PATH. Please install it to use this function." | |
return | |
} | |
# Process each file of the specified format | |
$files = Get-ChildItem -Path $resolvedPath -Filter *.$Format -File -ErrorAction Stop | |
if ($files.Count -eq 0) { | |
Write-Output "No *.$Format files found in $resolvedPath." | |
return | |
} | |
# Create the output directory if it doesn't exist | |
$resolvedOutputDir = Resolve-Path -Path $OutputDirectory -ErrorAction SilentlyContinue | |
if (-not $resolvedOutputDir) { | |
$resolvedOutputDir = New-Item -Path $OutputDirectory -ItemType Directory -Force -Verbose | |
} | |
foreach ($file in $files) { | |
$inputFile = $file.FullName; | |
$outputFile = Join-Path -Path $resolvedOutputDir -ChildPath $([Path]::ChangeExtension($file.Name, ".wav")) | |
Write-Verbose "Converting: $inputFile to $outputFile" | |
ffmpeg -i $inputFile -ac 2 -ar 48000 -acodec pcm_s16le $outputFile | |
# Check if the output file was created successfully | |
if (Test-Path -Path $outputFile) { | |
Write-Host "Converted: $($file.Name) to $([Path]::GetFileName($outputFile))" | |
} | |
else { | |
Write-Warning "Conversion failed for: $inputFile" | |
} | |
} | |
} | |
function ConvertTo-WavWithNoiseGate { | |
[CmdletBinding()] # Enables support for -Verbose and advanced function features | |
param ( | |
[Parameter( | |
Mandatory = $true, | |
Position = 0, | |
HelpMessage = "Specify the input audio format (e.g., 'opus', 'mp3', 'ogg')" | |
)] | |
[ValidateSet("opus", "mp3", "ogg")] | |
[string]$Format, | |
[Parameter( | |
Position = 1, | |
Mandatory = $false, | |
HelpMessage = "Specify the directory path with the input files." | |
)] | |
[string]$Path = (Get-Location).Path, | |
#Specify an optional output directory | |
[Parameter( | |
Position = 2, | |
Mandatory = $false, | |
HelpMessage = "Specify the directory to save converted WAV files." | |
)] | |
[string]$OutputDirectory = "./Output" | |
) | |
# Resolve absolute paths for input and output directories | |
$resolvedPath = Resolve-Path -Path $Path | |
# Validate that the input directory exists | |
if (!(Test-Path -Path $resolvedPath -PathType Container)) { | |
Write-Error "The directory $resolvedPath doesn't exist." | |
return | |
} | |
# Check if FFmpeg is installed and available | |
if (!(Get-Command ffmpeg -ErrorAction SilentlyContinue)) { | |
Write-Error "FFmpeg is not installed or is not in your system PATH. Please install it to use this function." | |
return | |
} | |
# Process each file of the specified format | |
$files = Get-ChildItem -Path $resolvedPath -Filter *.$Format -File -ErrorAction Stop | |
if ($files.Count -eq 0) { | |
Write-Output "No *.$Format files found in $resolvedPath." | |
return | |
} | |
# Create the output directory if it doesn't exist | |
$resolvedOutputDir = Resolve-Path -Path $OutputDirectory -ErrorAction SilentlyContinue | |
if (-not $resolvedOutputDir) { | |
$resolvedOutputDir = New-Item -Path $OutputDirectory -ItemType Directory -Force -Verbose | |
} | |
foreach ($file in $files) { | |
$inputFile = $file.FullName; | |
$outputFile = Join-Path -Path $resolvedOutputDir -ChildPath $([Path]::ChangeExtension($file.Name, ".wav")) | |
Write-Verbose "Converting: $inputFile to $outputFile" | |
ffmpeg -i $inputFile -ac 2 -ar 48000 -acodec pcm_s16le $outputFile | |
# Check if the output file was created successfully | |
if (Test-Path -Path $outputFile) { | |
$astatsData = & ffprobe -f lavfi -i "amovie='$($outputFile -replace "\\", "/" -replace ":", "\:")',astats=metadata=1:reset=0" -show_entries frame_tags="lavfi.astats.Overall.Peak_level,lavfi.astats.Overall.RMS_level" -of csv 2>&1 | |
$noiseFloorMatch = [regex]::Matches($astatsData, "Noise floor dB:\s*(-?\d+\.\d+)")[2] | |
$noiseFloor = [math]::Round([float]$noiseFloorMatch.Groups[1].Value, 2) | |
Write-Host "Noise floor: $noiseFloor" | |
$threshold = "$($noiseFloor + 5) dB" | |
$ratio = "4" | |
$attack = "5" # Attack in milliseconds | |
$release = "250" | |
ffmpeg -i $outputFile -af "agate=threshold=${threshold}:ratio=${ratio}:attack=${attack}:release=${release}" "./NoiseGate/$([Path]::ChangeExtension($file.Name, ".wav"))" | |
Write-Host "Converted: $($file.Name) to $([Path]::GetFileName($outputFile))" | |
} | |
else { | |
Write-Warning "Conversion failed for: $inputFile" | |
} | |
} | |
} | |
function Get-AudioAnalysis() { | |
[CmdletBinding()] | |
param ( | |
[Parameter( | |
Mandatory = $true, | |
ValueFromPipeline, | |
Position = 0, | |
HelpMessage = "Specify the input audio file" | |
)] | |
[string]$InputFile, | |
[Switch]$Parallel, # Add a -Parallel switch | |
[int]$ThrottleLimit = 5 # Optional: Control max parallel threads | |
) | |
process { | |
if ($Parallel) { | |
$InputFile | ForEach-Object -Parallel { | |
$LocalInputFile = $using:InputFile | |
if (!(Test-Path $LocalInputFile)) { | |
Write-Error "Error: Input file [$LocalInputFile] does not exist." | |
return | |
} | |
$FormattedFilePath = $LocalInputFile -replace "\\", "/" -replace ":", "\:" | |
#lavfi.astats.Overall.Min_level_dB, | |
# Run FFprobe with astats filter to get Peak and RMS levels | |
$astatsData = & ffprobe -f lavfi -i "amovie='$FormattedFilePath', astats=metadata=1:reset=0" -show_entries frame_tags="lavfi.astats.Overall.Peak_level, lavfi.astats.Overall.RMS_level" -of csv 2>&1 | |
# Regex patterns for Peak level dB and RMS level dB in Overall section | |
$peakLevelMatch = [regex]::Matches($astatsData, "Peak level dB:\s*(-?\d+\.\d+)")[2] | |
$rmsLevelMatch = [regex]::Matches($astatsData, "RMS level dB:\s*(-?\d+\.\d+)")[2] | |
# $noiseFloorMatch = [regex]::Matches($astatsData, "Noise floor dB:\s*( - ?\d+\.\d+)")[2] | |
$noiseFloorMatch = [regex]::Matches($astatsData, "Noise floor dB:\s*(-(?:inf|\d+\.\d+))")[2] | |
# Extract the values | |
if ($peakLevelMatch.Success -and $rmsLevelMatch.Success) { | |
$peakLevel = [math]::Round([float]$peakLevelMatch.Groups[1].Value, 2) | |
$rmsLevel = [math]::Round([float]$rmsLevelMatch.Groups[1].Value, 2) | |
if ($noiseFloorMatch.Groups[1].Value -eq "-inf") { | |
$noiseFloor = [float]-999 | |
} | |
else { | |
$noiseFloor = [math]::Round([float]$noiseFloorMatch.Groups[1].Value, 2) | |
} | |
} | |
else { | |
Write-Host "Failed to extract the Peak Level and/or RMS Level from the Overall section." | |
} | |
# Extract Peak Level and RMS Level | |
# Run FFmpeg with loudnorm filter to get Loudness Range (LRA) | |
$loudnormOutput = & ffmpeg -i $LocalInputFile -af "loudnorm=print_format=json" -f null - 2>&1 | |
# Extract JSON portion from the output | |
$jsonData = ($loudnormOutput | Select-String -Pattern '^\s*{|\}$|^\s*".*"\s*:' -Raw) -join "`n" | ConvertFrom-Json | |
$lra = $jsonData.input_lra | |
$truePeakLevel = $jsonData.input_tp | |
$integratedLoudness = $jsonData.input_i | |
# Calculate Dynamic Range | |
$dynamicRange = [math]::Abs($peakLevel - $rmsLevel) | |
$result = [PSCustomObject]@{ | |
FileName = [System.IO.Path]::GetFileName($LocalInputFile) | |
NoiseFloorDB = $noiseFloor | |
PeakLevelDB = $peakLevel | |
TruePeakLevelDBTP = $truePeakLevel | |
RMSLevelDB = $rmsLevel | |
DynamicRangeDB = $dynamicRange | |
LoudnesRangeLUFS = $lra | |
IntegratedLoudnessLUFS = $integratedLoudness | |
} | |
Write-Output $result | |
} -ThrottleLimit $ThrottleLimit | |
} | |
else { | |
# Check if the input file exists | |
if (!(Test-Path $InputFile)) { | |
Write-Error "Error: Input file [$InputFile] does not exist." | |
return | |
} | |
$FormattedFilePath = $InputFile -replace "\\", "/" -replace ":", "\:" | |
#lavfi.astats.Overall.Min_level_dB, | |
# Run FFprobe with astats filter to get Peak and RMS levels | |
$astatsData = & ffprobe -f lavfi -i "amovie='$FormattedFilePath', astats=metadata=1:reset=0" -show_entries frame_tags="lavfi.astats.Overall.Peak_level, lavfi.astats.Overall.RMS_level" -of csv 2>&1 | |
# Regex patterns for Peak level dB and RMS level dB in Overall section | |
$peakLevelMatch = [regex]::Matches($astatsData, "Peak level dB:\s*(-?\d+\.\d+)")[2] | |
$rmsLevelMatch = [regex]::Matches($astatsData, "RMS level dB:\s*(-?\d+\.\d+)")[2] | |
# $noiseFloorMatch = [regex]::Matches($astatsData, "Noise floor dB:\s*( - ?\d+\.\d+)")[2] | |
$noiseFloorMatch = [regex]::Matches($astatsData, "Noise floor dB:\s*(-(?:inf|\d+\.\d+))")[2] | |
# Extract the values | |
if ($peakLevelMatch.Success -and $rmsLevelMatch.Success) { | |
$peakLevel = [math]::Round([float]$peakLevelMatch.Groups[1].Value, 2) | |
$rmsLevel = [math]::Round([float]$rmsLevelMatch.Groups[1].Value, 2) | |
if ($noiseFloorMatch.Groups[1].Value -eq "-inf") { | |
$noiseFloor = [float]-999 | |
} | |
else { | |
$noiseFloor = [math]::Round([float]$noiseFloorMatch.Groups[1].Value, 2) | |
} | |
# Output the results | |
Write-Host "Extracted Peak Level dB: $peakLevel" | |
Write-Host "Extracted RMS Level dB: $rmsLevel" | |
Write-Host "Extracted Noise Floor dB: $noiseFloor" | |
} | |
else { | |
Write-Host "Failed to extract the Peak Level and/or RMS Level from the Overall section." | |
} | |
# Extract Peak Level and RMS Level | |
# Run FFmpeg with loudnorm filter to get Loudness Range (LRA) | |
$loudnormOutput = & ffmpeg -i $InputFile -af "loudnorm=print_format=json" -f null - 2>&1 | |
# Extract JSON portion from the output | |
$jsonData = ($loudnormOutput | Select-String -Pattern '^\s*{|\}$|^\s*".*"\s*:' -Raw) -join "`n" | ConvertFrom-Json | |
$lra = $jsonData.input_lra | |
$truePeakLevel = $jsonData.input_tp | |
$integratedLoudness = $jsonData.input_i | |
# Calculate Dynamic Range | |
$dynamicRange = [math]::Abs($peakLevel - $rmsLevel) | |
# Output results | |
Write-Host "Analysis of: $InputFile" | |
Write-Host "----------------------------------" | |
Write-Host "Noise Floor: $noiseFloor dB" | |
Write-Host "Peak Level: $peakLevel dB" | |
Write-Host "True Peak Level: $truePeakLevel dBTP" | |
Write-Host "RMS Level: $rmsLevel dB" | |
Write-Host "Dynamic Range (DR): $dynamicRange dB" | |
Write-Host "Loudness Range (LRA): $lra LUFS" | |
Write-Host "Integrated Loudness: $integratedLoudness LUFS" | |
[PSCustomObject]@{ | |
FileName = [Path]::GetFileName($InputFile) | |
NoiseFloorDB = $noiseFloor | |
PeakLevelDB = $peakLevel | |
TruePeakLevelDBTP = $truePeakLevel | |
RMSLevelDB = $rmsLevel | |
DynamicRangeDB = $dynamicRange | |
LoudnesRangeLUFS = $lra | |
IntegratedLoudnessLUFS = $integratedLoudness | |
} | |
} | |
} | |
} | |
function Export-ToExcel { | |
param ( | |
[Parameter(Mandatory, ValueFromPipeline)] | |
[PSObject[]]$Data, # Array of PSCustomObjects | |
[Parameter()] | |
[string]$FilePath = "./ExportedData.csv" # Default CSV path | |
) | |
# Ensure the input data is not null or empty | |
if (-not $Data -or $Data.Count -eq 0) { | |
Write-Host "Error: No data to export." -ForegroundColor Red | |
return | |
} | |
try { | |
# Export data to CSV | |
$Data | Export-Csv -Path $FilePath -NoTypeInformation -Force | |
Write-Host "Data successfully exported to $FilePath." -ForegroundColor Green | |
# Open the CSV in Excel | |
Start-Process -FilePath "excel.exe" -ArgumentList $FilePath | |
Write-Host "CSV opened in Excel." -ForegroundColor Green | |
} | |
catch { | |
Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red | |
} | |
} | |
function ConvertTo-Wav48 { | |
[CmdletBinding()] # Enables support for -Verbose and advanced function features | |
param ( | |
[Parameter( | |
Mandatory = $true, | |
Position = 0, | |
HelpMessage = "Specify the input audio format (e.g., 'wav', 'flac')" | |
)] | |
[ValidateSet("wav", "flac")] | |
[string]$Format, | |
[Parameter( | |
Position = 1, | |
Mandatory = $false, | |
HelpMessage = "Specify the directory path with the input files." | |
)] | |
[string]$Path = (Get-Location).Path, | |
#Specify an optional output directory | |
[Parameter( | |
Position = 2, | |
Mandatory = $false, | |
HelpMessage = "Specify the directory to save converted WAV files." | |
)] | |
[string]$OutputDirectory = "./Output" | |
) | |
# Resolve absolute paths for input and output directories | |
$resolvedPath = Resolve-Path -Path $Path | |
# Validate that the input directory exists | |
if (!(Test-Path -Path $resolvedPath -PathType Container)) { | |
Write-Error "The directory $resolvedPath doesn't exist." | |
return | |
} | |
# Check if FFmpeg is installed and available | |
if (!(Get-Command ffmpeg -ErrorAction SilentlyContinue)) { | |
Write-Error "FFmpeg is not installed or is not in your system PATH. Please install it to use this function." | |
return | |
} | |
# Process each file of the specified format | |
$files = Get-ChildItem -Path $resolvedPath -Filter *.$Format -File -ErrorAction Stop | |
if ($files.Count -eq 0) { | |
Write-Output "No *.$Format files found in $resolvedPath." | |
return | |
} | |
# Create the output directory if it doesn't exist | |
$resolvedOutputDir = Resolve-Path -Path $OutputDirectory -ErrorAction SilentlyContinue | |
if (-not $resolvedOutputDir) { | |
$resolvedOutputDir = New-Item -Path $OutputDirectory -ItemType Directory -Force -Verbose | |
} | |
foreach ($file in $files) { | |
$inputFile = $file.FullName; | |
$outputFile = Join-Path -Path $resolvedOutputDir -ChildPath $([Path]::ChangeExtension($file.Name, ".wav")) | |
Write-Verbose "Converting: $inputFile to $outputFile" | |
ffmpeg -i $inputFile -ar 48000 $outputFile | |
# Check if the output file was created successfully | |
if (Test-Path -Path $outputFile) { | |
Write-Host "Converted: $($file.Name) to $([Path]::GetFileName($outputFile))" | |
} | |
else { | |
Write-Warning "Conversion failed for: $inputFile" | |
} | |
} | |
} | |
#endregion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment