Drag and Drop PowerShell
Today I'm going back to my old school DOS batch file days and bring back an automation technique to the PowerShell world. Let me show you how to bring drag and drop automation to your PowerShell scripts. This technique doesn't necessarily scale very well, but it is an interesting way to pass data to your code. After reading this and testing it out, you'll have to think about where it makes sense for you.
Dropping to a File
Back in the day you could create a simple batch file like this:
@echo off
REM DropIt.bat
echo You dropped %1
pause
The only thing this batch file does is echo the argument, %1
.
C:\> c:\work\drop\dropit.bat "Testing 123"
You dropped "Testing 123"
Press any key to continue . . .
I've copied this batch file to C:\Work\Drop.

From here, I can drag and drop an item from the file explorer on to the batch file. I'll drag my Downloads folder and drop it on the DropIt.bat file.

You can see the prompt that I'm going to open the dropped item with DropIt.bat
. As soon as I release my mouse, a DOS prompt will open and echo the dropped item.

This suggests that I could pass the path of a file or folder to a script by dragging and dropping it on to the script file. However, there is a catch for our PowerShell needs. For security reasons, you can't arbitrarily invoke a PowerShell script. Which means you can't simply replace the DOS batch file with a PowerShell script. Instead, you'll need to wrap the PowerShell script in a batch file.
I'm going to test with this function.
#requires -version 7.5
#Get-FileExtensionInfo.ps1
using namespace System.Collections.generic
Function Get-FileExtensionInfo {
[cmdletbinding()]
[alias("gfei")]
[OutputType("FileExtensionInfo")]
Param(
[Parameter(
Position = 0,
ValueFromPipeline,
HelpMessage = "Specify the root directory path to search"
)]
[ValidateNotNullOrEmpty()]
[ValidateScript( { Test-Path $_ })]
[string]$Path = ".",
[Parameter(HelpMessage = "Recurse through all folders.")]
[switch]$Recurse,
[Parameter(HelpMessage = "Include files in hidden folders")]
[switch]$Hidden,
[Parameter(HelpMessage = "Add the corresponding collection of files")]
[Switch]$IncludeFiles
)
Begin {
$ver = "1.1.0"
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand) v$ver"
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running PowerShell version $($PSVersionTable.PSVersion)"
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Using PowerShell Host $($Host.Name)"
#capture the current date and time for the audit date
$report = Get-Date
$enumOpt = [System.IO.EnumerationOptions]::new()
if ($Recurse) {
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Getting files recursively"
}
$enumOpt.RecurseSubdirectories = $Recurse
if ($Hidden) {
Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Including hidden files"
$enumOpt.AttributesToSkip -= 2
}
#initialize a list to hold the results
$list = [list[object]]::new()
} #begin
Process {
#convert the path to a file system path
$cPath = Convert-Path -Path $Path
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Processing $cPath"
$dir = Get-Item -Path $cPath
$files = $dir.GetFiles('*', $enumOpt)
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Found $($files.count) files"
$group = $files | Group-Object -Property extension
#Group and measure
foreach ($item in $group) {
Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Measuring $($item.count) $($item.name) files"
$measure = $item.Group | Measure-Object -Property length -Minimum -Maximum -Average -Sum
#create a custom object
$out = [PSCustomObject]@{
PSTypeName = "FileExtensionInfo"
Path = $cPath
Extension = $item.Name.Replace('.', '')
Count = $item.Count
TotalSize = $measure.Sum
SmallestSize = $measure.Minimum
LargestSize = $measure.Maximum
AverageSize = $measure.Average
Computername = [System.Environment]::MachineName
ReportDate = $report
Files = $IncludeFiles ? $item.group : $null
IsLargest = $False
}
$list.Add($out)
}
} #process
End {
#mark the extension with the largest total size
($list | Sort-Object -Property TotalSize,Count)[-1].IsLargest = $true
#write the results to the pipeline
$list
Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)"
} #end
}
Update-TypeData -TypeName FileExtensionInfo -MemberType AliasProperty -MemberName Total -Value TotalSize -Force
The function breaks down file extensions in a given folder and provides a summary.
PS C:\> Get-FileExtensionInfo d:\temp -Recurse
Path: D:\temp [PROSPERO]
Extension Count TotalSize Smallest Average Largest
--------- ----- --------- -------- ------- -------
html 1 836 836 836 836
png 1 154085 154085 154085 154085
txt 2 2069090 290 1034545 2068800
The function also includes a custom format file which will highlight the extension with the largest total size.