Skip to content

Instantly share code, notes, and snippets.

@mklement0
Last active April 1, 2019 18:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mklement0/79bfa6697244ca3d432f4e85a10e5376 to your computer and use it in GitHub Desktop.
Save mklement0/79bfa6697244ca3d432f4e85a10e5376 to your computer and use it in GitHub Desktop.
Get-OpenFiles: PowerShell function for locating open files in a given directory [subtree]
function Get-OpenFiles {
<#
.SYNOPSIS
Finds open files.
.DESCRIPTION
Finds files currently being held open by any process and reports them as
[System.IO.FileInfo] instances, as Get-ChildItem would.
In fact, this function supports all parameters that Get-ChildItem does and
uses the latter behind the scenes, while filtering the output to Include
only in-use files.
Files that cannot be accessed due to lack of permissions cause
non-terminating errors.
.EXAMPLE
Get-OpenFiles
Lists all open files in the current directory, if any.
.EXAMPLE
Get-OpenFiles *.txt
Lists open files among those with extension *.txt in the current directory.
.Example
Get-OpenFiles $HOME/Documents -Recurse
Lists open files located anywhere in the user's Documents folder and its
entire subtree.
Note that running with -Recurse can take a while.
.Example
[bool] (Get-OpenFiles ./someFile.txt)
Indicates if the specified file is open or not.
#>
[CmdletBinding(DefaultParameterSetName = 'Items', PositionalBinding = $False)]
param(
[Parameter(ParameterSetName = 'Items', Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[string[]]
${Path},
[Parameter(ParameterSetName = 'LiteralItems', Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
[Alias('PSPath', 'LP')]
[string[]]
${LiteralPath},
[Parameter(Position = 1)]
[string]
${Filter},
[string[]]
${Include},
[string[]]
${Exclude},
[Alias('s')]
[switch]
${Recurse},
[uint32]
${Depth},
[switch]
${Force},
[switch]
${Name})
dynamicparam {
try {
$targetCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Get-ChildItem', [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters)
$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object { $_.Value.IsDynamic })
if ($dynamicParams.Length -gt 0) {
$paramDictionary = [Management.Automation.RuntimeDefinedParameterDictionary]::new()
foreach ($param in $dynamicParams) {
$param = $param.Value
if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {
$dynParam = [Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes)
$paramDictionary.Add($param.Name, $dynParam)
}
}
return $paramDictionary
}
}
catch {
throw
}
}
begin {
try {
$outBuffer = $null
if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) {
$PSBoundParameters['OutBuffer'] = 1
}
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Get-ChildItem', [System.Management.Automation.CommandTypes]::Cmdlet)
$scriptCmd = {
& $wrappedCmd @PSBoundParameters | Where-Object {
if ($_.PSIsContainer) { return $false } # ignore directories
$file = $_
try {
[IO.File]::Open($file.FullName, 'Open', 'Read', 'None').Close()
return $false # file NOT open elsewhere
}
catch {
# See if the exception is a sharing / locking error, which indicates that the file is open.
if (
$_.Exception.InnerException -is [System.IO.IOException] -and
($_.Exception.InnerException.HResult -band 0x21) -in 0x21, 0x20
) {
return $true # file IS open elsewhere
}
else {
# Unexpected error, relay the exception as a non-terminating error.
$PSCmdlet.WriteError([System.Management.Automation.ErrorRecord]::new(
$_.Exception.InnerException, # the exception to wrap
$null, # a custom error ID (string)
[System.Management.Automation.ErrorCategory]::InvalidOperation,
$file # the target object (what object the error relates to)
))
}
}
}
}
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
$steppablePipeline.Begin($PSCmdlet)
}
catch {
throw
}
}
process {
try {
$steppablePipeline.Process($_)
}
catch {
throw
}
}
end {
try {
$steppablePipeline.End()
}
catch {
throw
}
}
}
# If this script is invoked directly - as opposed to being dot-sourced in order
# to define the embedded function for later use - invoke the embedded function,
# relaying any arguments passed.
if (-not ($MyInvocation.InvocationName -eq '.' -or $MyInvocation.Line -eq '')) {
Get-OpenFiles @Args
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment