openfiles.ps1

<#PSScriptInfo
 
.VERSION 1.2
 
.GUID 579b9002-4c7a-4f16-b5ab-91f434aa9854
 
.AUTHOR Christoph Weste
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
Fixed bug in terminate switch
 
#>
 











<#
 
.DESCRIPTION
dealing with openfiles using openfiles.exe
 
#>
 

Param()


#!/usr/bin/env powershell
#Requires -RunAsAdministrator
function Get-OpenFiles
{
  <#
      .SYNOPSIS
      This function will display open files from a given Sever / PC
      .DESCRIPTION
      This function will use openfiles.exe to get information about open files against a given Sever / PC.
      It will return an DataTable object with all openfiles or if the -filter property is used it will return an filter Dataview object.
      You can also close open files if you use the terminate switch
      .EXAMPLE
      Will return all openfiles on fileserver1
      Get-OpenFiles -ComputerName fileserver1
      .EXAMPLE
      Will return all openfiles from fs2 where the filname contains \share\
      Get-OpenFiles -computername fs2 -Filter Open_File -query \share\
      .EXAMPLE
      Will return all openfiles from all servers (which are in the clipboard) which are accessed by backupadmin
      get-clippboard|Get-OpenFiles -Filter Accessed_By -query backupadmin
      .EXAMPLE
      You can also skip the -filter and only working with -User_q or -File_q
      Get-OpenFiles -User_q backupadmin
      .EXAMPLE
      You can also skip the -filter and only working with -User_q or -File_q
      Get-OpenFiles -File_q \share\
      .EXAMPLE
      It also possible to combine queries. This example will return all files which are opend by the user backupadmin with \share\ in the pathname
      Get-OpenFiles localhost -Filter Combo -User_q backupadmin -File_q \share\
      .EXAMPLE
      This will close/terminate all sessions from the user backupadmin
      Get-OpenFiles -Filter Accessed_By -query backupadmin -terminate
      .PARAMETER computername
      The computer name to query. Just one or multiple.
      .PARAMETER Filter
      Here you can select which poperty is interesting for your result.
      .PARAMETER User_q
      This is your user search query , you dont have to provide the exact search query the function will always use LIKE
      .PARAMETER File_q
      This is your File search query , you dont have to provide the exact search query the function will always use LIKE
      .PARAMETER terminate
      This parameter will trigger an close/discconect against the openfiles which are returned
 
  #>


  [CmdletBinding(SupportsShouldProcess,ConfirmImpact = 'Low')]
  [CmdletBinding(DefaultParameterSetName = 'set1')]
  




  Param
  (
    [Parameter(Position = 0,
        Mandatory,
        ValueFromPipeline,
        ValueFromPipelineByPropertyName,
       
    HelpMessage = 'What computer name would you like to target?')]
       
    [string[]]$computername,

    [Parameter(Position = 1)]
    [ValidateSet('Open_File','Accessed_By','Combo')]
    [AllowEmptyString()] 
    [String]$Filter,


    
        
    [Parameter(Position = 2)]
    [AllowEmptyString()] 
    [String]$User_q,
        
    [Parameter(Position = 3)]
    [AllowEmptyString()] 
    [String]$File_q,

    [Parameter(Position = 4)]
        
    [switch]$Terminate = $false

  )


  begin {
    If ([bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match 'S-1-5-32-544')) 
    {
      Write-Verbose -Message 'You are an administrator'
    }
    else 
    {
      Write-Verbose -Message 'You need Admin rights to execute openfiles.exe'
      break
    }



   
  }


  process {

    Write-Verbose -Message ('Beginning query {0}' -f $computername)

       

    # openfile execution
    $temp = & "$env:windir\system32\openfiles.exe" /query /s $computername /fo csv /V
    
    #modify the header row , this makes filtering easier , lazy me
    $temp[0] = '"Hostname","ID","Accessed_By","Type","Locks","Open_Mode","Open_File"'
   
    $csv = $temp | ConvertFrom-Csv
  
    

    
    # Create Datatable
    $dtFileAccess = New-Object -TypeName System.Data.DataTable -ArgumentList ('FileAccess')
    $cols = @('Hostname', 'ID', 'Accessed_By', 'Locks', 'Open_Mode', 'Open_File')

    # Schema (columns)
    foreach ($col in $cols) 
    {
      $null = $dtFileAccess.Columns.Add($col)
    }

    # Fill the Datatable with Values (rows)
    foreach ($c in $csv) 
    {
      $row = $dtFileAccess.NewRow()
      foreach ($col in $cols) 
      {
        $row[$col] = $c.$col
      }
      $null = $dtFileAccess.Rows.Add($row)
    }

    # This will be used for filtering
       
    # DataView rapid filter
    $dvFileAccess    = New-Object -TypeName System.Data.DataView -ArgumentList ($dtFileAccess)
    

    switch ($Filter){
        
      'Accessed_By' 
      {
        If ($Terminate -ne $True)
        {
          $dvFileAccess.RowFilter = 'Accessed_By'+(" LIKE '%{0}%'" -f $User_q)
          return $dvFileAccess
        }
      }
        
      'Open_File' 
      {
        If ($Terminate -ne $True)
        {
          $dvFileAccess.RowFilter = ("Open_File LIKE '%{0}%'" -f $File_q)
          return $dvFileAccess
        }
      }
            
      'combo'
      {
        If ($Terminate -ne $True)
        {
          $dvFileAccess.RowFilter = "Accessed_By LIKE '%{0}%'AND Open_file LIKE '%{1}%'" -f $User_q, $File_q
          return $dvFileAccess
        }
      }
      default 
      {
        If ($Terminate -ne $True)
        {
          If ($File_q -ne $null -or $User_q -ne $null)
    
          {
            $dvFileAccess.RowFilter = "Accessed_By LIKE '%{0}%'AND Open_file LIKE '%{1}%'" -f $User_q, $File_q
            return $dvFileAccess
          }
          else 
          {
            return $dtFileAccess
          }
        }
      } 
      
    }
    
    
    # Result


    if ( $Terminate -eq $True )
    {
      #-and $dvFileAccess.GetEnumerator() -gt 0){
      If ($File_q -ne $null -or $User_q -ne $null)
    
      {
        $dvFileAccess.RowFilter = "Accessed_By LIKE '%{0}%'AND Open_file LIKE '%{1}%'" -f $User_q, $File_q
      }
      
      
      $result = [System.Collections.ArrayList]@()
      
      foreach ($id in $dvFileAccess.GetEnumerator().id)
      {
        $r = & "$env:windir\system32\openfiles.exe" /disconnect /s $computername /id $id
        if ($r -ne $null)
        {
          $null = $result.Add($r)
        }
      }
      return $result
    }
    
    
    
        
  }
}