Close-OpenFile.ps1

Function Close-OpenFile {
<#
.SYNOPSIS
Closes open files on local or remote computers
 
.DESCRIPTION
This command uses Windows openfiles.exe to close files that are open by a user or process.
the command requires administrative access on the remote/local computer where task is been executed.
 
.PARAMETER ComputerName
one or more computers names to query
 
.PARAMETER ID
File ID can be retrived by running Get-RemoteOpenFile
 
.PARAMETER User
User with file open
 
.PARAMETER ErrorLogfilePath
if provided, this is a path and filename of the text file where failed computer names will be logged
 
.EXAMPLE
Import-csv FileList.csv | Close-OpenFile -ErrorLogfilePath C:\Logs\Logs.txt
 
.EXAMPLE
 
Get-RemoteOpenFile -ComputerName Test-PC.test.local -filter D:\Files\* | Close-OpenFile -ErrorLogfilePath C:\Logs\Logs.txt
 
.NOTES
Input from pipeline is supported for ComputerName & FileID. This command works together with Get-RemoteOpenFile command run first
to get required file's to close.
 
#>


    [cmdletbinding(SupportsShouldProcess=$True,ConfirmImpact='high')]
    param (
    [parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True,Mandatory=$True)]
    [string[]]$ComputerName,
    [parameter(ValueFromPipelineByPropertyName=$True,Mandatory=$True)]
    [String]$ID,
    [parameter(ValueFromPipelineByPropertyName=$True,Mandatory=$False)]
    [String]$User,
    [parameter(ValueFromPipelineByPropertyName=$False,Mandatory=$False)]
    $ErrorLogfilePath
    )

BEGIN{

    Write-Verbose "[$((get-date).TimeOfDay.ToString()) BEGIN ] Starting: $($MyInvocation.MyCommand)"
    Write-Verbose "[$((get-date).TimeOfDay.ToString()) BEGIN ] PSVersion = $($PSVersionTable.PSVersion)"
    Write-Verbose "[$((get-date).TimeOfDay.ToString()) BEGIN ] OS = $((Get-CimInstance win32_OperatingSystem).Caption)"
    Write-Verbose "[$((get-date).TimeOfDay.ToString()) BEGIN ] User = $($env:userdomain)\$($env:USERNAME)"
    $UserId = [System.Security.Principal.WindowsIdentity]::GetCurrent()
    $IsAdmin = [System.Security.Principal.WindowsPrincipal]::new($UserId).IsInRole('administrators')
    Write-Verbose "[$((get-date).TimeOfDay.ToString()) BEGIN ] Is Admin = $IsAdmin"
}



PROCESS {

    try {  
            If ($PSCmdlet.ShouldProcess($ComputerName)){
                ForEach($Computer in $ComputerName){   
                    Write-Verbose "[$((get-date).TimeOfDay.ToString()) PROCESS ] trying to close files"    
                    $ClosedFile = openfiles /s "$Computer" /disconnect /id $ID 
                    
                    $Props = [Ordered]@{
                                        "User" = $User;
                                        "Computer" = $Computer
                                        "Status" = $ClosedFile
                                        }
                    $FileStauts = New-Object -TypeName psobject -Property $Props
                    $FileStauts 
                }#ForEach
            
                
            }#IF
            
        }#Try
    Catch {
            $($_.Exception.Message)
            if($ErrorLogfilePath){
                Write-Verbose "ErrorLog file created in path $($ErrorLogfilePath)"
                Write-Output "[$((get-date).TimeOfDay.ToString()) ERROR ] closing file $($ClosedFile) in $($Computer) accessed by user $($User)" | Out-File $ErrorLogfilePath -Append  
            }#IF


    }#Catch

}#Process
END{
#LeftBlank
}
}#Function