├── Convert-ListToString.ps1 ├── Extract-HTMLTable.ps1 ├── Get-ClipboardHistory.ps1 ├── Get-MSIFileInformation.ps1 ├── Get-ObjectUnique.ps1 ├── Get-ObjectsInTwoArrays.ps1 ├── Invoke-AutoType.ps1 ├── Invoke-ConcatenateCSV.ps1 ├── New-FlatObject.ps1 ├── README.md ├── Save-Download.ps1 ├── Uninstall-PowerShellModuleAndDependencies.ps1 ├── Update-AllPowerShellModules.ps1 ├── VideoAndAudio ├── Concatenate-VideoWithFFMpeg.ps1 └── Trim-VideoWithFFMpeg.ps1 └── Windows └── Block-OutboundConnectionsForAnApp.ps1 /Convert-ListToString.ps1: -------------------------------------------------------------------------------- 1 | function Convert-ListToString { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter()] 5 | $InputArray 6 | ) 7 | 8 | $string = New-Object -TypeName System.Text.StringBuilder 9 | foreach ($object in $InputArray) { 10 | [void]$string.Append($object) 11 | } 12 | 13 | return $string.ToString() 14 | } -------------------------------------------------------------------------------- /Extract-HTMLTable.ps1: -------------------------------------------------------------------------------- 1 | function Extract-HTMLTable { 2 | param( 3 | [Parameter(Mandatory)] 4 | [String] $URL, 5 | 6 | [Parameter(Mandatory = $false)] 7 | [int] $TableNumber, 8 | 9 | # Either we know the table number, otherwise we extract all tables 10 | [Parameter(Mandatory = $false)] 11 | [switch] $AllTables, 12 | 13 | [Parameter(Mandatory = $false)] 14 | [boolean] $LocalFile 15 | 16 | ) 17 | 18 | [System.Collections.Generic.List[PSObject]]$tablesArray = @() 19 | 20 | if ($LocalFile) { 21 | $html = New-Object -ComObject 'HTMLFile' 22 | $source = Get-Content -Path $URL -Raw 23 | $html.IHTMLDocument2_write($source) 24 | 25 | # html does not have ParseHTML because it already an HTMLDocumentClass 26 | # Cast in array in case of only one element 27 | $tables = @($html.getElementsByTagName('TABLE')) 28 | } 29 | else { 30 | $WebRequest = Invoke-WebRequest $URL 31 | 32 | # Cast in array in case of only one element 33 | $tables = @($WebRequest.ParsedHtml.getElementsByTagName('TABLE')) 34 | } 35 | 36 | ## Extract the tables out of the web request 37 | if ($TableNumber) { 38 | #$table = $tables[$TableNumber] 39 | # Cast in array because only one element 40 | $tables = @($tables[$TableNumber]) 41 | } 42 | 43 | ## Go through all of the rows in the table 44 | $tableNumber = 0 45 | foreach ($table in $tables) { 46 | $titles = @() 47 | $rows = @($table.Rows) 48 | 49 | $tableNumber++ 50 | 51 | foreach ($row in $rows) { 52 | $cells = @($row.Cells) 53 | 54 | ## If we've found a table header, remember its titles 55 | if ($cells[0].tagName -eq 'TH') { 56 | $titles = @($cells | ForEach-Object { ('' + $_.InnerText).Trim() }) 57 | continue 58 | } 59 | 60 | ## If we haven't found any table headers, make up names "P1", "P2", etc. 61 | if (-not $titles) { 62 | $titles = @(1..($cells.Count + 2) | ForEach-Object { "P$_" }) 63 | } 64 | 65 | ## Now go through the cells in the the row. For each, try to find the 66 | ## title that represents that column and create a hashtable mapping those 67 | ## titles to content 68 | $resultObject = [Ordered] @{ 69 | "TableNumber" = $tableNumber 70 | } 71 | 72 | for ($counter = 0; $counter -lt $cells.Count; $counter++) { 73 | $title = $titles[$counter] 74 | if (-not $title) { continue } 75 | $resultObject[$title] = ('' + $cells[$counter].InnerText).Trim() 76 | } 77 | 78 | ## And finally cast that hashtable to a PSCustomObject and add to $array 79 | $tablesArray.Add([PSCustomObject] $resultObject) 80 | } 81 | } 82 | 83 | return $tablesArray 84 | } -------------------------------------------------------------------------------- /Get-ClipboardHistory.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | 3 | from: https://gist.githubusercontent.com/mutaguchi/019ad33e156637585a22a656d8fd3f46/raw/38cba2de838e52004e75c400c254877a4f8e6ad3/ClipboardHistory.ps1 4 | Get-ClipboardHistory: Get the texts contained in the clipboard history. 5 | Clear-ClipboardHistory: Clearing the clipboard history 6 | 7 | In PowerShell 7.1 or later, use the following command to install Microsoft.Windows.SDK.NET.Ref with administrative privileges. 8 | Find-Package -ProviderName NuGet -Source https://www.nuget.org/api/v2 -Name Microsoft.Windows.SDK.NET.Ref | Install-Package 9 | #> 10 | 11 | $needsSDK = $PSVersionTable.PSVersion -ge "7.1.0" 12 | 13 | if ($needsSDK) { 14 | $sdkLib = Split-Path -Path (Get-Package -ProviderName NuGet -Name Microsoft.Windows.SDK.NET.Ref | Select-Object -ExpandProperty Source) -Parent | Join-Path -ChildPath "\lib" 15 | Add-Type -Path "$sdkLib\Microsoft.Windows.SDK.NET.dll" 16 | Add-Type -Path "$sdkLib\WinRT.Runtime.dll" 17 | } 18 | else { 19 | Add-Type -AssemblyName System.Runtime.WindowsRuntime 20 | } 21 | 22 | $clipboard = if ($needsSDK) { 23 | [Windows.ApplicationModel.DataTransfer.Clipboard] 24 | } 25 | else { 26 | [Windows.ApplicationModel.DataTransfer.Clipboard, Windows.ApplicationModel.DataTransfer, ContentType = WindowsRuntime] 27 | } 28 | get- 29 | function await { 30 | param($AsyncTask, [Type]$ResultType) 31 | 32 | $method = [WindowsRuntimeSystemExtensions].GetMember("GetAwaiter") | Where-Object { $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' } | Select-Object -First 1 $method.MakeGenericMethod($ResultType).Invoke($null, @($AsyncTask)).GetResult() 33 | } 34 | 35 | function Get-ClipboardHistory { 36 | $type = if ($script:needsSDK) { 37 | [Windows.ApplicationModel.DataTransfer.ClipboardHistoryItemsResult] 38 | } 39 | else { 40 | [Windows.ApplicationModel.DataTransfer.ClipboardHistoryItemsResult, Windows.ApplicationModel.DataTransfer, ContentType = WindowsRuntime] 41 | } 42 | 43 | $result = await $script:clipboard::GetHistoryItemsAsync() $type 44 | 45 | $outItems = if ($script:needsSDK) { 46 | @($result.Items.AdditionalTypeData.Values) 47 | } 48 | else { 49 | @($result.Items) 50 | } 51 | 52 | $outItems | Where-Object { $_.Content.Contains("Text") } | ForEach-Object { 53 | await $_.Content.GetTextAsync() ([string]) 54 | } 55 | } 56 | 57 | function Clear-ClipboardHistory { 58 | $null = $script:clipboard::ClearHistory() 59 | } -------------------------------------------------------------------------------- /Get-MSIFileInformation.ps1: -------------------------------------------------------------------------------- 1 | function Get-MSIFileInformation { 2 | param( 3 | [Parameter(Mandatory = $true, ValueFromPipeline = $true)] 4 | [ValidateNotNullOrEmpty()] 5 | [System.IO.FileInfo[]]$FilePath 6 | ) 7 | 8 | # https://learn.microsoft.com/en-us/windows/win32/msi/installer-opendatabase 9 | $msiOpenDatabaseModeReadOnly = 0 10 | 11 | $productLanguageHashTable = @{ 12 | '1025' = 'Arabic' 13 | '1026' = 'Bulgarian' 14 | '1027' = 'Catalan' 15 | '1028' = 'Chinese - Traditional' 16 | '1029' = 'Czech' 17 | '1030' = 'Danish' 18 | '1031' = 'German' 19 | '1032' = 'Greek' 20 | '1033' = 'English' 21 | '1034' = 'Spanish' 22 | '1035' = 'Finnish' 23 | '1036' = 'French' 24 | '1037' = 'Hebrew' 25 | '1038' = 'Hungarian' 26 | '1040' = 'Italian' 27 | '1041' = 'Japanese' 28 | '1042' = 'Korean' 29 | '1043' = 'Dutch' 30 | '1044' = 'Norwegian' 31 | '1045' = 'Polish' 32 | '1046' = 'Brazilian' 33 | '1048' = 'Romanian' 34 | '1049' = 'Russian' 35 | '1050' = 'Croatian' 36 | '1051' = 'Slovak' 37 | '1053' = 'Swedish' 38 | '1054' = 'Thai' 39 | '1055' = 'Turkish' 40 | '1058' = 'Ukrainian' 41 | '1060' = 'Slovenian' 42 | '1061' = 'Estonian' 43 | '1062' = 'Latvian' 44 | '1063' = 'Lithuanian' 45 | '1081' = 'Hindi' 46 | '1087' = 'Kazakh' 47 | '2052' = 'Chinese - Simplified' 48 | '2070' = 'Portuguese' 49 | '2074' = 'Serbian' 50 | } 51 | 52 | $summaryInfoHashTable = @{ 53 | 1 = 'Codepage' 54 | 2 = 'Title' 55 | 3 = 'Subject' 56 | 4 = 'Author' 57 | 5 = 'Keywords' 58 | 6 = 'Comment' 59 | 7 = 'Template' 60 | 8 = 'LastAuthor' 61 | 9 = 'RevisionNumber' 62 | 10 = 'EditTime' 63 | 11 = 'LastPrinted' 64 | 12 = 'CreationDate' 65 | 13 = 'LastSaved' 66 | 14 = 'PageCount' 67 | 15 = 'WordCount' 68 | 16 = 'CharacterCount' 69 | 18 = 'ApplicationName' 70 | 19 = 'Security' 71 | } 72 | 73 | $properties = @('ProductVersion', 'ProductCode', 'ProductName', 'Manufacturer', 'ProductLanguage', 'UpgradeCode') 74 | 75 | try { 76 | $file = Get-ChildItem $FilePath -ErrorAction Stop 77 | } 78 | catch { 79 | Write-Warning "Unable to get file $FilePath $($_.Exception.Message)" 80 | return 81 | } 82 | 83 | $object = [PSCustomObject][ordered]@{ 84 | FileName = $file.Name 85 | FilePath = $file.FullName 86 | 'Length(MB)' = $file.Length / 1MB 87 | } 88 | 89 | # Read property from MSI database 90 | $windowsInstallerObject = New-Object -ComObject WindowsInstaller.Installer 91 | 92 | # open read only 93 | $msiDatabase = $windowsInstallerObject.GetType().InvokeMember('OpenDatabase', 'InvokeMethod', $null, $windowsInstallerObject, @($file.FullName, $msiOpenDatabaseModeReadOnly)) 94 | 95 | foreach ($property in $properties) { 96 | $view = $null 97 | $query = "SELECT Value FROM Property WHERE Property = '$($property)'" 98 | $view = $msiDatabase.GetType().InvokeMember('OpenView', 'InvokeMethod', $null, $msiDatabase, ($query)) 99 | $view.GetType().InvokeMember('Execute', 'InvokeMethod', $null, $view, $null) 100 | $record = $view.GetType().InvokeMember('Fetch', 'InvokeMethod', $null, $view, $null) 101 | 102 | try { 103 | $value = $record.GetType().InvokeMember('StringData', 'GetProperty', $null, $record, 1) 104 | } 105 | catch { 106 | Write-Verbose "Unable to get '$property' $($_.Exception.Message)" 107 | $value = '' 108 | } 109 | 110 | if ($property -eq 'ProductLanguage') { 111 | $value = "$value ($($productLanguageHashTable[$value]))" 112 | } 113 | 114 | $object | Add-Member -MemberType NoteProperty -Name $property -Value $value 115 | } 116 | 117 | $summaryInfo = $msiDatabase.GetType().InvokeMember('SummaryInformation', 'GetProperty', $null, $msiDatabase, $null) 118 | $summaryInfoPropertiesCount = $summaryInfo.GetType().InvokeMember('PropertyCount', 'GetProperty', $null, $summaryInfo, $null) 119 | 120 | (1..$summaryInfoPropertiesCount) | ForEach-Object { 121 | $value = $SummaryInfo.GetType().InvokeMember("Property", "GetProperty", $Null, $SummaryInfo, $_) 122 | 123 | if ($null -eq $value) { 124 | $object | Add-Member -MemberType NoteProperty -Name $summaryInfoHashTable[$_] -Value '' 125 | } 126 | else { 127 | $object | Add-Member -MemberType NoteProperty -Name $summaryInfoHashTable[$_] -Value $value 128 | } 129 | } 130 | 131 | #$msiDatabase.GetType().InvokeMember('Commit', 'InvokeMethod', $null, $msiDatabase, $null) 132 | $view.GetType().InvokeMember('Close', 'InvokeMethod', $null, $view, $null) 133 | 134 | # Run garbage collection and release ComObject 135 | $null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($windowsInstallerObject) 136 | [System.GC]::Collect() 137 | 138 | return $object 139 | } -------------------------------------------------------------------------------- /Get-ObjectUnique.ps1: -------------------------------------------------------------------------------- 1 | function Get-ObjectUnique { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter()] 5 | $InputArray 6 | ) 7 | 8 | return [System.Collections.Generic.HashSet[string]]$InputArray 9 | } -------------------------------------------------------------------------------- /Get-ObjectsInTwoArrays.ps1: -------------------------------------------------------------------------------- 1 | function Get-ObjectsInTwoArrays { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter()] 5 | $Array, 6 | [Parameter()] 7 | $ArrayToCompare, 8 | [Parameter(Mandatory)] 9 | [ValidateSet('In', 'NotIn')] 10 | $ComparisonMethod, 11 | [Parameter(Mandatory)] 12 | [ValidateSet('String', 'int','PSObject')] 13 | $ObjectType 14 | ) 15 | 16 | if($ObjectType -eq 'String'){ 17 | $arrayIndex = [System.Collections.Generic.HashSet[String]]$Array 18 | } 19 | elseif($ObjectType -eq 'int'){ 20 | $arrayIndex = [System.Collections.Generic.HashSet[int]]$Array 21 | } 22 | elseif($ObjectType -eq 'PSObject'){ 23 | $arrayIndex = [System.Collections.Generic.HashSet[PSObject]]$Array 24 | } 25 | 26 | [System.Collections.Generic.List[PSObject]]$res = @() 27 | 28 | if ($ComparisonMethod -eq 'In') { 29 | foreach ($object in $ArrayToCompare) { 30 | if ($arrayIndex.Contains($object)) { 31 | $res.Add($object) 32 | } 33 | } 34 | } 35 | elseif ($ComparisonMethod -eq 'NotIn') { 36 | foreach ($object in $ArrayToCompare) { 37 | if (-not($arrayIndex.Contains($object))) { 38 | $res.Add($object) 39 | } 40 | } 41 | } 42 | 43 | Write-Host "$($res.count) $ComparisonMethod two arrays" 44 | return $res 45 | } -------------------------------------------------------------------------------- /Invoke-AutoType.ps1: -------------------------------------------------------------------------------- 1 | 2 | <# 3 | feat: Add PowerShell script for automating typing 4 | 5 | This commit adds a new PowerShell script, `Invoke-AutoType.ps1`, which allows for automating typing on both Windows and macOS operating systems. The script takes a string as input and types it character by character with a small delay between each character. 6 | 7 | The script includes separate logic for Windows and macOS, utilizing the `System.Windows.Forms.SendKeys` class for Windows and AppleScript for macOS. 8 | 9 | This feature will be useful for automating repetitive typing tasks, such as filling out forms or entering text in applications. 10 | #> 11 | 12 | # The string to type 13 | $type = '' 14 | 15 | $sleepMillisecondsBetweenCharacters = 1 16 | 17 | # Sleep for 5 seconds before starting to type to go to the right window 18 | Start-Sleep -Seconds 5 19 | 20 | # If Operating System is Windows 21 | if ($IsWindows) { 22 | # Loop over each character in the string 23 | foreach ($char in $type.ToCharArray()) { 24 | # Send the character 25 | [System.Windows.Forms.SendKeys]::SendWait($char) 26 | 27 | # Sleep for 5 milliseconds between characters 28 | Start-Sleep -Milliseconds $sleepMillisecondsBetweenCharacters 29 | } 30 | } 31 | 32 | if ($IsMacOS) { 33 | # Boucle sur chaque caractère de la chaîne 34 | foreach ($char in $type.ToCharArray()) { 35 | $script = @" 36 | tell application "System Events" 37 | keystroke "$char" 38 | end tell 39 | "@ 40 | } 41 | 42 | # Exécution du script AppleScript pour chaque caractère 43 | osascript -e $script 44 | 45 | # Pause de 5 millisecondes entre les caractères 46 | Start-Sleep -Milliseconds $sleepMillisecondsBetweenCharacters 47 | } -------------------------------------------------------------------------------- /Invoke-ConcatenateCSV.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script concatenates multiple CSV files into a single CSV file. 4 | 5 | .DESCRIPTION 6 | The Invoke-ConcatenateCSV.ps1 script concatenates multiple CSV files from a specified directory into a single CSV file, adding the source filename as the first column. 7 | A oneliner exists: 8 | Get-ChildItem -Filter *.csv | Select-Object -ExpandProperty FullName | Import-Csv | Export-Csv .\merged.csv -NoTypeInformation -Append 9 | But we don't have the source file name in the output file and we can handle different properties in the CSV files. 10 | 11 | .PARAMETER InputDirectory 12 | Specifies the directory containing the CSV files to be concatenated. 13 | 14 | .PARAMETER OutputFile 15 | Specifies the path and name of the output CSV file that will contain the concatenated data. 16 | 17 | .EXAMPLE 18 | PS C:\> .\Invoke-ConcatenateCSV.ps1 -InputDirectory "C:\CSVFiles" -OutputFile "C:\Output\Combined.csv" 19 | 20 | .NOTES 21 | Author: Bastien Perez 22 | Date: 2024/11/22 23 | Version: 1.2 24 | #> 25 | 26 | function Invoke-ConcatenateCSV { 27 | [CmdletBinding()] 28 | param( 29 | [Parameter(Mandatory = $false)] 30 | [string]$InputDirectory = '.', 31 | 32 | [Parameter(Mandatory = $false)] 33 | [string]$OutputFile = 'Concatenated.csv', 34 | 35 | [Parameter(Mandatory = $false)] 36 | [string]$Delimiter = ';' , 37 | 38 | [Parameter(Mandatory = $false)] 39 | [switch]$AddSourceFile 40 | ) 41 | 42 | # Create empty array to store all data 43 | [System.Collections.Generic.List[Object]]$allData = @() 44 | # Get all CSV files in the specified directory 45 | $files = Get-ChildItem -Path $InputDirectory -Filter '*.csv' 46 | 47 | if ($files.Count -eq 0) { 48 | Write-Warning "No CSV files found in directory: $InputDirectory" 49 | return 50 | } 51 | 52 | foreach ($file in $files) { 53 | Write-Verbose "Processing file: $($file.Name)" 54 | 55 | try { 56 | # Import CSV content 57 | Write-Verbose "Importing CSV content from: $($file.FullName)" 58 | $csvContent = Import-Csv -Path $file.FullName -Delimiter $Delimiter 59 | 60 | # Add source filename to each row 61 | foreach ($row in $csvContent) { 62 | if ($AddSourceFile) { 63 | Write-Verbose "Adding source file = $($file.Name) to the row" 64 | $row.PSObject.Properties.Add('SourceFile', $file.Name) 65 | } 66 | 67 | $newRow = @{} 68 | # Add all other properties from the original row 69 | foreach ($property in $row.PSObject.Properties) { 70 | Write-Verbose "Adding property: $($property.Name) = $($property.Value)" 71 | $newRow[$property.Name] = $property.Value 72 | } 73 | 74 | # Add the modified row to our collection 75 | $allData.Add([PSCustomObject]$newRow) 76 | } 77 | } 78 | catch { 79 | Write-Warning "Error processing file $($file.Name): $_" 80 | continue 81 | } 82 | } 83 | 84 | if ($allData.Count -gt 0) { 85 | try { 86 | # Export all data to the output file 87 | $allData | Export-Csv -Path $OutputFile -NoTypeInformation -Encoding UTF8 88 | Write-Host "Successfully concatenated $($files.Count) files to: $OutputFile" 89 | Write-Host "Total rows: $($allData.Count)" 90 | } 91 | catch { 92 | Write-Error "Error writing output file: $_" 93 | } 94 | } 95 | else { 96 | Write-Warning 'No data was collected from the CSV files' 97 | } 98 | } -------------------------------------------------------------------------------- /New-FlatObject.ps1: -------------------------------------------------------------------------------- 1 | function New-FlatObject { 2 | Param 3 | ( 4 | [Parameter(Mandatory, ValueFromPipeline)] 5 | $object 6 | ) 7 | 8 | process { 9 | $returnHashTable = [ordered]@{ } 10 | foreach ($prop in $object.psobject.Properties) { 11 | if ($prop.Value -is [array]) { 12 | #if (($prop.Value -ne $null) -and (-not $prop.Value.GetType().isValueType)) 13 | $counter = 0 14 | foreach ($value in $prop.Value) { 15 | if ($value -is [array]) { 16 | #if (($prop.Value -ne $null) -and (-not $prop.Value.GetType().isValueType)) 17 | foreach ($recurse in (New-FlatObject -object $value).psobject.Properties) { 18 | $returnHashTable["$($prop.Name)-$($recurse.Name)"] = $recurse.Value 19 | } 20 | } 21 | $returnHashTable["$($prop.Name)-$counter"] = $value 22 | $counter++ 23 | } 24 | } 25 | else { 26 | $returnHashTable[$prop.Name] = $prop.Value 27 | } 28 | } 29 | return [PSCustomObject]$returnHashTable | Sort-Object @{Expression = { (($_.psobject.properties) | Measure-Object).count } } -Descending 30 | } 31 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowerShell-Toolbox 2 | Some useful scripts 3 | -------------------------------------------------------------------------------- /Save-Download.ps1: -------------------------------------------------------------------------------- 1 | function Save-Download { 2 | <# 3 | .SYNOPSIS 4 | Given a the result of WebResponseObject, will download the file to disk without having to specify a name. 5 | .DESCRIPTION 6 | Given a the result of WebResponseObject, will download the file to disk without having to specify a name. 7 | .PARAMETER WebResponse 8 | A WebResponseObject from running an Invoke-WebRequest on a file to download 9 | .EXAMPLE 10 | # Download Microsoft Edge 11 | $download = Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/?linkid=2109047&Channel=Stable&language=en&consent=1" 12 | $download | Save-Download 13 | #> 14 | [CmdletBinding()] 15 | param ( 16 | [Parameter(Mandatory = $true, ValueFromPipeline)] 17 | [Microsoft.PowerShell.Commands.WebResponseObject] 18 | $WebResponse, 19 | 20 | [Parameter(Mandatory = $false)] 21 | [string] 22 | $Directory = '.' 23 | ) 24 | 25 | $errorMessage = 'Cannot determine filename for download.' 26 | 27 | if (!($WebResponse.Headers.ContainsKey('Content-Disposition'))) { 28 | Write-Error $errorMessage -ErrorAction Stop 29 | } 30 | 31 | $content = [System.Net.Mime.ContentDisposition]::new($WebResponse.Headers['Content-Disposition']) 32 | 33 | $fileName = $content.FileName 34 | 35 | if (!$fileName) { 36 | Write-Error $errorMessage -ErrorAction Stop 37 | } 38 | 39 | if (!(Test-Path -Path $Directory)) { 40 | New-Item -Path $Directory -ItemType Directory 41 | } 42 | 43 | $fullPath = Join-Path -Path $Directory -ChildPath $fileName 44 | 45 | Write-Verbose "Downloading to $fullPath" 46 | 47 | $file = [System.IO.FileStream]::new($fullPath, [System.IO.FileMode]::Create) 48 | $file.Write($WebResponse.Content, 0, $WebResponse.RawContentLength) 49 | $file.Close() 50 | } -------------------------------------------------------------------------------- /Uninstall-PowerShellModuleAndDependencies.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | do{ 3 | $mod=Get-InstalledModule Vmware* -ErrorAction SilentlyContinue 4 | $mod | % {$_.Name 5 | $_ | Uninstall-Module}}until($(Get-InstalledModule Vmware* -ErrorAction SilentlyContinue) -eq $null) 6 | #> 7 | 8 | function Uninstall-PowerShellModuleAndDependencies { 9 | param ( 10 | [Parameter(Mandatory = $true)] 11 | [string]$Module 12 | ) 13 | 14 | [System.Collections.Generic.List[String]] $script:modulesOrDependencies = @() 15 | 16 | function Get-RecursivePowerShellDepencies { 17 | param ( 18 | [Parameter(Mandatory = $true)] 19 | [string]$Module 20 | ) 21 | 22 | $target = Find-Module $Module 23 | 24 | if ($target.Dependencies.count -eq 0) { 25 | if ($script:modulesOrDependencies -notcontains $target.Name) { 26 | $script:modulesOrDependencies.Add($target.name) 27 | } 28 | } 29 | else { 30 | $target.Dependencies | ForEach-Object { 31 | # add current dependency 32 | if ($script:modulesOrDependencies -notcontains $target.Name) { 33 | $script:modulesOrDependencies.Add($target.name) 34 | } 35 | 36 | # search for dependencies of current dependency 37 | Get-RecursivePowerShellDepencies -Module $_.name 38 | } 39 | } 40 | } 41 | 42 | Write-Host "$module - Creating list of dependencies" -ForegroundColor Cyan 43 | 44 | Get-RecursivePowerShellDepencies -Module $Module 45 | 46 | foreach ($mod in $modulesOrDependencies) { 47 | Write-Host "$mod - Uninstalling" -ForegroundColor Cyan 48 | 49 | try { 50 | Uninstall-Module -Name $mod -Force -ErrorAction Stop 51 | } 52 | catch { 53 | Write-Warning "modulesOrDependency $($_.Exception.Message)" 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Update-AllPowerShellModules.ps1: -------------------------------------------------------------------------------- 1 | # https://itpro-tips.com/2020/update-all-powershell-modules-at-once/ 2 | # https://itpro-tips.com/2020/mettre-a-jour-tous-les-modules-powershell-en-une-fois/ 3 | [CmdletBinding()] 4 | param ( 5 | [Parameter()] 6 | # To exclude modules from the update process 7 | [String[]]$ExcludedModules, 8 | # To include only these modules for the update process 9 | [String[]]$IncludedModules, 10 | [switch]$SkipPublisherCheck, 11 | [switch]$SimulationMode 12 | ) 13 | <# 14 | /!\/!\/!\ PLEASE READ /!\/!\/!\ 15 | 16 | /!\ If you look for a quick way to update, please keep in mind Microsoft has a built-in CMDlet to update ALL the PowerShell modules installed: 17 | /!\ Update-Module [-Verbose] 18 | 19 | /!\ This script is intended as a replacement of the Update-Module: 20 | /!\ - to provide more human readable output than the -Verbose option of Update-Module 21 | /!\ - to force install with -SkipPublisherCheck (Authenticode change) because Update-Module has not this option 22 | /!\ - to exclude some modules from the update process 23 | /!\ - to remove older versions because Update-Module does not remove older versions (it only installs a new version in the $env:PSModulePath\ and keep the old module) 24 | 25 | This script provides informations about the module version (current and the latest available on PowerShell Gallery) and update to the latest version 26 | If you have a module with two or more versions, the script delete them and reinstall only the latest. 27 | 28 | #> 29 | 30 | #Requires -Version 5.0 31 | #Requires -RunAsAdministrator 32 | 33 | Write-Host -ForegroundColor cyan 'Define PowerShell to add TLS1.2 in this session, needed since 1st April 2020 (https://devblogs.microsoft.com/powershell/powershell-gallery-tls-support/)' 34 | [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 35 | 36 | # if needed, register PSGallery 37 | # Register PSGallery PSprovider and set as Trusted source 38 | # Register-PSRepository -Default -ErrorAction SilentlyContinue 39 | # Set-PSRepository -Name PSGallery -InstallationPolicy trusted -ErrorAction SilentlyContinue 40 | 41 | if ($SimulationMode) { 42 | Write-Host -ForegroundColor yellow 'Simulation mode is ON, nothing will be installed / removed / updated' 43 | } 44 | 45 | function Remove-OldPowerShellModules { 46 | param ( 47 | [string]$ModuleName, 48 | [string]$GalleryVersion 49 | ) 50 | 51 | try { 52 | $oldVersions = Get-InstalledModule -Name $ModuleName -AllVersions -ErrorAction Stop | Where-Object { $_.Version -ne $GalleryVersion } 53 | 54 | foreach ($oldVersion in $oldVersions) { 55 | Write-Host -ForegroundColor Cyan "$ModuleName - Uninstall previous version" -NoNewline 56 | Write-Host -ForegroundColor White " ($($oldVersion.Version))" 57 | 58 | if (-not($SimulationMode)) { 59 | Remove-Module $ModuleName -ErrorAction SilentlyContinue 60 | Uninstall-Module $oldVersion -Force -ErrorAction Stop 61 | } 62 | } 63 | } 64 | catch { 65 | Write-Warning "$module - $($_.Exception.Message)" 66 | } 67 | } 68 | 69 | if ($IncludedModules) { 70 | Write-Host -ForegroundColor Cyan "Get PowerShell modules like $IncludedModules" 71 | $modules = Get-InstalledModule | Where-Object { $_.Name -like $IncludedModules } 72 | } 73 | else { 74 | Write-Host -ForegroundColor Cyan 'Get all PowerShell modules' 75 | $modules = Get-InstalledModule 76 | } 77 | 78 | foreach ($module in $modules.Name) { 79 | if ($ExcludedModules -contains $module) { 80 | Write-Host -ForegroundColor Yellow "Module $module is excluded from the update process" 81 | continue 82 | } 83 | elseif ($module -like "$excludedModules") { 84 | Write-Host -ForegroundColor Yellow "Module $module is excluded from the update process (match $excludeModules)" 85 | continue 86 | } 87 | 88 | $currentVersion = $null 89 | 90 | try { 91 | $currentVersion = (Get-InstalledModule -Name $module -AllVersions -ErrorAction Stop).Version 92 | } 93 | catch { 94 | Write-Warning "$module - $($_.Exception.Message)" 95 | continue 96 | } 97 | 98 | try { 99 | $moduleGalleryInfo = Find-Module -Name $module -ErrorAction Stop 100 | } 101 | catch { 102 | Write-Warning "$module not found in the PowerShell Gallery. $($_.Exception.Message)" 103 | continue 104 | } 105 | 106 | # $current version can also be a version follow by -preview 107 | if ($currentVersion -like '*-preview') { 108 | Write-Warning "The module installed is a preview version, it will not tested by this script" 109 | } 110 | 111 | if ($moduleGalleryInfo.Version -like '*-preview') { 112 | Write-Warning "The module in PowerShell Gallery is a preview version, it will not tested bt this script" 113 | continue 114 | } 115 | else { 116 | $moduleGalleryVersion = $moduleGalleryInfo.Version 117 | } 118 | 119 | # Convert published date to YYYY/MM/DD HH:MM:SS format 120 | $publishedDate = [datetime]$moduleGalleryInfo.PublishedDate 121 | $publishedDate = $publishedDate.ToString("yyyy/MM/dd HH:mm:ss") 122 | 123 | if ($null -eq $currentVersion) { 124 | Write-Host -ForegroundColor Cyan "$module - Install from PowerShellGallery version $($moduleGalleryInfo.Version) - Release date: $publishedDate" 125 | 126 | if (-not($SimulationMode)) { 127 | try { 128 | Install-Module -Name $module -Force -SkipPublisherCheck -ErrorAction Stop 129 | } 130 | catch { 131 | Write-Warning "$module - $($_.Exception.Message)" 132 | } 133 | } 134 | } 135 | elseif ($moduleGalleryInfo.Version -eq $currentVersion) { 136 | Write-Host -ForegroundColor Green "$module - already in latest version: " -NoNewline 137 | Write-Host -ForegroundColor White "$currentVersion" -NoNewline 138 | Write-Host -ForegroundColor Green " - Release date:" -NoNewline 139 | Write-Host -ForegroundColor White " $publishedDate" 140 | } 141 | elseif ($currentVersion.count -gt 1) { 142 | Write-Host -ForegroundColor Yellow "$module is installed in $($currentVersion.count) versions:" -NoNewline 143 | Write-Host -ForegroundColor White " $($currentVersion -join ' | ')" 144 | Write-Host -ForegroundColor Cyan "$module - Uninstall previous $module version(s) below the latest version" -NoNewline 145 | Write-Host -ForegroundColor White " ($($moduleGalleryInfo.Version))" 146 | 147 | Remove-OldPowerShellModules -ModuleName $module -GalleryVersion $moduleGalleryInfo.Version 148 | 149 | # Check again the current Version as we uninstalled some old versions 150 | $currentVersion = (Get-InstalledModule -Name $module).Version 151 | 152 | if ($moduleGalleryVersion -ne $currentVersion) { 153 | Write-Host -ForegroundColor Cyan "$module - Install from PowerShellGallery version" -NoNewline 154 | Write-Host -ForegroundColor White " $($moduleGalleryInfo.Version)" -NoNewline 155 | Write-Host -ForegroundColor Cyan " - Release date:" -NoNewline 156 | Write-Host -ForegroundColor White " $publishedDate" 157 | 158 | if (-not($SimulationMode)) { 159 | try { 160 | Install-Module -Name $module -Force -ErrorAction Stop 161 | 162 | Remove-OldPowerShellModules -ModuleName $module -GalleryVersion $moduleGalleryInfo.Version 163 | } 164 | catch { 165 | Write-Warning "$module - $($_.Exception.Message)" 166 | } 167 | } 168 | } 169 | } 170 | # https://invoke-thebrain.com/2018/12/comparing-version-numbers-powershell/ 171 | elseif ([version]$currentVersion -gt [version]$moduleGalleryVersion) { 172 | Write-Host -ForegroundColor Yellow "$module - the current version $currentVersion is newer than the version available on PowerShell Gallery $($moduleGalleryInfo.Version) (Release date: $publishedDate). Sometimes happens when you install a module from another repository or via .exe/.msi or if you change the version number manually." 173 | } 174 | elseif ([version]$currentVersion -lt [version]$moduleGalleryVersion) { 175 | Write-Host -ForegroundColor Cyan "$module - Update from PowerShellGallery version" -NoNewline 176 | Write-Host -ForegroundColor White " $currentVersion -> $($moduleGalleryInfo.Version)" -NoNewline 177 | Write-Host -ForegroundColor Cyan " - Release date:" -NoNewline 178 | Write-Host -ForegroundColor White " $publishedDate" 179 | 180 | if (-not($SimulationMode)) { 181 | try { 182 | Update-Module -Name $module -Force -ErrorAction Stop 183 | Remove-OldPowerShellModules -ModuleName $module -GalleryVersion $moduleGalleryInfo.Version 184 | } 185 | catch { 186 | if ($_.Exception.Message -match 'Authenticode') { 187 | Write-Host -ForegroundColor Yellow "$module - The module certificate used by the creator is either changed since the last module install or the module sign status has changed." 188 | 189 | if ($SkipPublisherCheck.IsPresent) { 190 | Write-Host -ForegroundColor Cyan "$module - SkipPublisherCheck Parameter is present, so install will run without Authenticode check" 191 | Write-Host -ForegroundColor Cyan "$module - Install from PowerShellGallery version $($moduleGalleryInfo.Version) - Release date: $publishedDate" 192 | try { 193 | Install-Module -Name $module -Force -SkipPublisherCheck 194 | } 195 | catch { 196 | Write-Warning "$module - $($_.Exception.Message)" 197 | } 198 | 199 | Remove-OldPowerShellModules -ModuleName $module -GalleryVersion $moduleGalleryInfo.Version 200 | } 201 | else { 202 | Write-Warning "$module - If you want to update this module, run again with -SkipPublisherCheck switch, but please keep in mind the security risk" 203 | } 204 | } 205 | else { 206 | Write-Warning "$module - $($_.Exception.Message)" 207 | } 208 | } 209 | } 210 | } 211 | } -------------------------------------------------------------------------------- /VideoAndAudio/Concatenate-VideoWithFFMpeg.ps1: -------------------------------------------------------------------------------- 1 | # Get the list of video files from a specific directory 2 | $videoDirectory = "." 3 | $videoFiles = Get-ChildItem -Path $videoDirectory -Filter "*.mp4" 4 | 5 | # Create a temporary file to list all video files for ffmpeg 6 | $tempFile = New-TemporaryFile 7 | foreach ($videoFile in $videoFiles) { 8 | Add-Content -Path $tempFile.FullName -Value "file '$($videoFile.FullName)'" 9 | } 10 | 11 | # Output file name 12 | $outputVideo = "outputVideo.mp4" 13 | 14 | # Concatenate videos using ffmpeg 15 | & ffmpeg -f concat -safe 0 -i $tempFile.FullName -c copy $outputVideo 16 | 17 | # Clean up the temporary file 18 | Remove-Item -Path $tempFile.FullName -------------------------------------------------------------------------------- /VideoAndAudio/Trim-VideoWithFFMpeg.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [Parameter(Mandatory = $false)] 3 | [string]$InputVideo, 4 | [Parameter(Mandatory = $false)] 5 | [string]$OutputVideo, 6 | [Parameter(Mandatory = $true)] 7 | [string]$StartCut, 8 | [Parameter(Mandatory = $false)] 9 | [string]$EndCut 10 | ) 11 | 12 | # function to get time in hh:mm:ss format 13 | function Get-TimeInHHMMSSFormat { 14 | param( 15 | [string]$Time 16 | ) 17 | 18 | $timeParts = $time.Split(':') 19 | 20 | switch ($timeParts.Count) { 21 | 1 { return [TimeSpan]::FromSeconds([int]$timeParts[0]) } 22 | 2 { return [TimeSpan]::FromMinutes([int]$timeParts[0]).Add([TimeSpan]::FromSeconds([int]$timeParts[1])) } 23 | 3 { return [TimeSpan]::FromHours([int]$timeParts[0]).Add([TimeSpan]::FromMinutes([int]$timeParts[1])).Add([TimeSpan]::FromSeconds([int]$timeParts[2])) } 24 | default { throw 'Invalid time format. Please use one of the following formats: SS, MM:SS, or HH:MM:SS.' } 25 | } 26 | } 27 | 28 | # Get video duration using FFmpeg 29 | $duration = & ffmpeg -i $InputVideo 2>&1 | Select-String -Pattern 'Duration: (\d+):(\d+):(\d+\.\d+)' | ForEach-Object { $_.Matches.Groups[1].Value, $_.Matches.Groups[2].Value, $_.Matches.Groups[3].Value -join ':' } 30 | 31 | # Use the custom Parse-Time function 32 | $startCutTimeSpan = Get-TimeInHHMMSSFormat -Time $StartCut 33 | 34 | # If no end cut time is provided, set it to the duration of the video 35 | if ([string]::IsNullOrWhitespace($EndCut)) { 36 | Write-Host -ForegroundColor Cyan "No end cut time provided. Using the full duration of the video $duration" 37 | $endCut = $duration 38 | } 39 | 40 | $endCutTimeSpan = Get-TimeInHHMMSSFormat -Time $EndCut 41 | 42 | # Calculate new duration by subtracting start cut from end cut 43 | $newDuration = $endCutTimeSpan.Subtract($startCutTimeSpan) 44 | 45 | # Format new duration for FFmpeg 46 | $newDuration = '{0:00}:{1:00}:{2:00}.{3:000}' -f $newDuration.Hours, $newDuration.Minutes, $newDuration.Seconds, $newDuration.Milliseconds 47 | 48 | # Use FFmpeg to cut the video 49 | & ffmpeg -ss $StartCut -i $InputVideo -t $newDuration -c copy $OutputVideo -------------------------------------------------------------------------------- /Windows/Block-OutboundConnectionsForAnApp.ps1: -------------------------------------------------------------------------------- 1 | # block outbound connections for an .exe path 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter(Mandatory = $true, HelpMessage = "The path to the application")] 5 | [String]$ApplicationPath 6 | ) 7 | 8 | 9 | # Test if application exists 10 | if (-not (Test-Path $ApplicationPath)) { 11 | Write-Warning "'$ApplicationPath' does not exist" 12 | return 13 | } 14 | 15 | $fileInfo = Get-Item $ApplicationPath 16 | $appName = $fileInfo.Name 17 | $productName = $fileInfo.VersionInfo.ProductName 18 | $string = "" 19 | 20 | if (-not [string]::IsNullOrEmpty($productName)) { 21 | $string = $productName.Trim() 22 | } 23 | else { 24 | $string = $fileInfo.BaseName.Trim() 25 | } 26 | 27 | if (-not [string]::IsNullOrEmpty($appName)) { 28 | $string = $string + " - " + $appName 29 | } 30 | 31 | $ruleName = "[Custom] Block outbound access for $string ($applicationPath)" 32 | 33 | # Test if the rule already exists 34 | try { 35 | $ruleExists = [boolean](Get-NetFirewallRule -Direction Outbound | Where-Object { $_.DisplayName -eq "$ruleName" }) 36 | } 37 | catch { 38 | Write-Warning "Failed to check if the rule already exists $($_.Exception.Message)." 39 | } 40 | 41 | if ($ruleExists) { 42 | Write-Warning "The rule '$ruleName' already exists" 43 | return 44 | } 45 | 46 | # create a new rule 47 | try { 48 | Write-Host -ForegroundColor Cyan "Creating a new rule to block outbound connections for the application: $ApplicationPath" 49 | New-NetFirewallRule -DisplayName $ruleName -Direction Outbound -Program $ApplicationPath -Action Block -Enabled True -ErrorAction Stop 50 | Write-Host -ForegroundColor Green "The rule has been created successfully." 51 | } 52 | catch { 53 | Write-Host "Failed to create the rule. The rule may already exist." 54 | } --------------------------------------------------------------------------------