InputOutput.psm1

function Get-FileEncoding {
    <#
  .SYNOPSIS
  Gets the encoding of a file
  .DESCRIPTION
  This function finds out the encoding of a file by converting it byte. Created by Cansin Aldanmaz - 30-06-2017
  .EXAMPLE
  Get-FileEncoding -Path c:\Users\Cansin.txt
  .EXAMPLE
  "c:\Users\Cansin.txt" | Get-FileEncoding
  .PARAMETER Path
  Specify the path of a file
  #>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$True,
            ValueFromPipeline=$True,
            ValueFromPipelineByPropertyName=$True,
            HelpMessage='The path of file which you want to find out the encoding')]
            [ValidateNotNullOrEmpty()]
            [String]$Path)
    $bytes = [byte[]](Get-Content $Path -Encoding byte -ReadCount 4 -TotalCount 4 -ErrorAction Stop -ErrorVariable Err)
    Write-Verbose -Message "Checking encoding type for file:$Path"
    $result = $null 
        if ($null -ne $bytes) {
            if ($bytes.Count -ge 4) {
                if ( $bytes[0] -eq 0xef -and $bytes[1] -eq 0xbb -and $bytes[2] -eq 0xbf ) {
                    $result = 'UTF8' 
                } elseif ($bytes[0] -eq 0xfe -and $bytes[1] -eq 0xff) {
                    $result = 'Unicode'
                } elseif ($bytes[0] -eq 0 -and $bytes[1] -eq 0 -and $bytes[2] -eq 0xfe -and $bytes[3] -eq 0xff) {
                    $result = 'UTF32'
                } elseif ($bytes[0] -eq 0x2b -and $bytes[1] -eq 0x2f -and $bytes[2] -eq 0x76) {
                    $result = 'UTF7'
                } else {
                    $result = 'ASCII'
                }
                Write-Verbose -Message "Found encoding type: $result"
            } 
            else {
                Write-Error -Message ($Path + " is only " + $byte.Count + " bytes in size, unable to determine file encoding") -Category InvalidData -ErrorAction Stop -ErrorVariable Error
            }
        } 
        else {
            $Err = ($Path + " is zero byte(s) in size")
            Write-Error -Message $Err -Category InvalidData -ErrorAction Stop 
            }
        return $result    
}

function Update-ContentOfFile {
    <#
  .SYNOPSIS
  Change the content of a file
  .DESCRIPTION
  This function replaces the keywords in a file and|or let's you to keep/specify the encoding and take a backup of file. Created by Cansin Aldanmaz - 30-06-2017
  .EXAMPLE
  Replace-Content -Path "C:\Users\Cansin Aldanmaz\Desktop\vpn\successfull.txt" -To "MSI file" -From "Cansin File" -Encoding "UTF8"
  .EXAMPLE
  Replace-Content -Path "C:\Users\Cansin Aldanmaz\Desktop\successfull.txt" -To "MSI file" -From "Cansin File" -TakeBackup -Verbose
  .PARAMETER Path
  Specify the path of the file
  .PARAMETER From
  Specify the keyword you want to change from
  .PARAMETER To
  Specify the keyword you want to change to
  .PARAMETER Encoding
  Specify the Encoding that you want to set for the file. If you don't specify, current encoding of file value will be saved.
  .PARAMETER TakeBackup
  If you want to take a backup of the file before you make changes, enable this switch.
  #>

 [CmdletBinding(            
    SupportsShouldProcess = $true            
    )]
 Param (
        [Parameter(Mandatory=$True,
            ValueFromPipeline=$True,
            ValueFromPipelineByPropertyName=$True,
            HelpMessage='The path of file which you want change content')]
            [ValidateNotNullOrEmpty()]
            [String]$Path,
        
        [Parameter(Mandatory=$True,
            ValueFromPipeline=$False,
            ValueFromPipelineByPropertyName=$True,
            HelpMessage='The keyword that will be replaced from')]
            [String]$From,
        
        [Parameter(Mandatory=$True,
            ValueFromPipeline=$False,
            ValueFromPipelineByPropertyName=$True,
            HelpMessage='The keyword that will be replaced to')]
            [String]$To,

        [Parameter(Mandatory=$False,
            ValueFromPipeline=$False,
            ValueFromPipelineByPropertyName=$True,
            HelpMessage='The keyword that will be replaced to')]
            [String]$Encoding,
        
        [Parameter(Mandatory=$False,
            ValueFromPipeline=$False,
            ValueFromPipelineByPropertyName=$True,
            HelpMessage='Want to take a backup of file before changing it?')]
            [Switch]$TakeBackup = $False
    )
    $Error = $null
    $Item  = $null
    $Date  = $(Get-Date -Format 'yyyyMMddHHmm')
    Write-Verbose -Message "Take backup value: $TakeBackup"
    try {
        Write-Verbose -Message "$(Get-Date)-Getting file: $Path"
        $Item = Get-Item -Path $Path -ErrorAction Stop -ErrorVariable Error
        if($TakeBackup)
        {
            $Destination = "$($Item.FullName)__$Date.backup"
            Write-Verbose -Message "$(Get-Date)-Taking a backup: $Destination"
            Copy-Item -Path $Item.FullName -Destination $Destination -ErrorAction Stop -ErrorVariable Error
        }
        Write-Verbose -Message "$(Get-Date)-Getting encoding"
        $CurrentEncoding = $(Get-FileEncoding -Path $Item.FullName -ErrorAction Stop -ErrorVariable Error)
        Write-Verbose -Message "$(Get-Date)-Encoding:$CurrentEncoding"
        Write-Verbose -Message "$(Get-Date)-Getting content and replacing from '$from' to '$to'"
        $Content = $(Get-Content -Path $Item.FullName -Raw -Encoding $CurrentEncoding -ErrorAction Stop -ErrorVariable Error).Replace($from,$to)
        Write-Verbose -Message "$(Get-Date)-Setting new content"
        If( (-not [String]::IsNullOrEmpty($Encoding)) -and ($Encoding -ne $CurrentEncoding))
        {
            Write-Verbose -Message "$(Get-Date)-Setting new Encoding:$Encoding"
        }
        else
        {
            $Encoding = $CurrentEncoding
            Write-Verbose -Message "$(Get-Date)-Encoding will not change:$Encoding"
        }
        Set-Content -Value $Content -Path $Item.FullName -Force -ErrorAction Stop -ErrorVariable Error -Encoding $Encoding
    }
    catch {
            throw $Error
        }
    }

 function Search-BigFile {
    <#
  .SYNOPSIS
  This function searchs keyword(s) in huge files which have milions of lines in a fast way.
  .DESCRIPTION
  This function searchs keyword(s) in huge files which have milions of lines in a fast way and return a hash list which contains results. Created by Cansin Aldanmaz - 30-06-2017
  .EXAMPLE
  Search-Fast -Path c:\Users\Cansin.txt -KeyWords ('deneme','deneme2')
  .EXAMPLE
  "c:\Users\Cansin.txt","c:\Users\Cansin.txt" | Search-Fast -KeyWords 'deneme','deneme2'
  .EXAMPLE
  Get-ChildItem -Path c:\temp -File|ForEach-Object{Search-Fast $_.FullName -Keywords 'Deneme','asd' -Highlight}
  .PARAMETER Path
  Specify the path of large file(s)
  .PARAMETER Keywords
  Specify the keyword(s) that you want to search for.
  .PARAMETER Highlight
  Specify the Highlight switch if you want to highlight your keyword(s) in the line
  #>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$True,
            ValueFromPipeline=$True,
            ValueFromPipelineByPropertyName=$True,
            HelpMessage='The path of file(s)')]
            [ValidateNotNullOrEmpty()]
            [String[]]$Path,
        [Parameter(Mandatory=$True,
            ValueFromPipeline=$false,
            ValueFromPipelineByPropertyName=$True,
            HelpMessage='Create a list that contains keywords.')]
            [ValidateNotNullOrEmpty()]
            [String[]]$Keywords,
        [Parameter(Mandatory=$False,
            ValueFromPipeline=$false,
            ValueFromPipelineByPropertyName=$True,
            HelpMessage='Highlights keyword(s) in line')]
            [switch]$Highlight
    )
    $t1 = Get-Date
    write-verbose -Message "Search will start for file:�n$Path and Keywords:�n$($Keywords|Out-String -Stream)"
    $file = [IO.File]::OpenText($Path)
    $lineNumber = 0
    $Results = New-Object Collections.ArrayList
    while ($file.Peek() -ge 0) {
        $lineNumber=$lineNumber+1 
        $line = $file.ReadLine()
        $Counter = 0
        $continueToSearch = $true
        $Result = $null
        while($continueToSearch -and ($Counter -lt $Keywords.Count))
        {
            if($line -Match $Keywords[$Counter])
            {
                if($Highlight)
                {
                    $line = $line.Replace($Keywords[$Counter],"*$($Keywords[$Counter])*")
                }
                write-verbose -Message "Found keyword($($Keywords[$Counter])) on line $lineNumber"
                $Counter=$Counter+1
            }
            else
            {
                if($Counter -ne 0)
                {
                    write-verbose -Message "Couldn't find keyword($($Keywords[$Counter])) on line $lineNumber"
                }
                $continueToSearch = $false
            }
        }
        if($continueToSearch)
        {
                $Result = @{
                    Keywords = $Keywords
                    LineNumber = $lineNumber
                    Content = $line.Trim()
                    Path = $Path
                }
                [Void]$Results.Add($Result)
                write-verbose -Message "All keywords matched, added result to List �n$($($result[1]) | out-string -Stream)"
            }
        }
    $file.Dispose()
    $t2 = Get-Date
    Write-Verbose -Message "Search completed in $(($t2-$t1).TotalSeconds) seconds."
    return $Results
}

function Find-Handle {
    <#
  .SYNOPSIS
  This function searchs for handles
  .DESCRIPTION
  This function searchs for handles. You can list handles created by process(es) or the processes that makes handle for a file. If you don't specify any thing, it will list all handles in operating system .Created by Cansin Aldanmaz - 13-07-2017
  .EXAMPLE
  Find-Handle -Path c:\Users\Cansin.txt
    .EXAMPLE
  Find-Handle -Path "c:\Users\Cansin.txt","C:\Program Files (x86)\Google\Chrome\Application\59.0.3071.115\chrome_child.dll"
  .EXAMPLE
  Find-Handle -Process chrome
  .PARAMETER Path
  Specify the path of large file(s)
  .PARAMETER Process
  Specify the name(s) of processes that you want to search for.
  #>

    
Param(
        [Parameter(Mandatory=$False,
            ValueFromPipeline=$True,
            ValueFromPipelineByPropertyName=$True,
            HelpMessage='Enter the path(s) of file(s)')]
            [String[]]$Path,
        [Parameter(Mandatory=$False,
            ValueFromPipeline=$False,
            ValueFromPipelineByPropertyName=$True,
            HelpMessage='Enter the name(s) of process(es)')]
            [String[]]$Process)
    $ProcessName = "*"
    If($Process.Count -gt 0)
    {
        $ProcessName = $Process
    }
    $Results = New-Object Collections.ArrayList
    Write-Verbose -Message "Getting all processes named $($ProcessName | Out-String -Stream)"
    $Procs = Get-Process -Name $ProcessName -ErrorAction SilentlyContinue
    If($null -ne $procs)
    {
        $Procs | ForEach-Object{
            $Proc = $_
            if($Path.Count -gt 0)
            {
                $Path | ForEach-Object{
                $p = $_
                $Proc.Modules | ForEach-Object{
                    if($_.FileName -eq $p)
                    {
                        $Result = @{
                            ProcessName = $Proc.Name
                            ProcessID   = $Proc.Id
                            File = $p
                        }
                        $object = New-Object -TypeName PSObject -Property $Result
                        [Void]$Results.Add($object)
                    }
                }
            }
            }
            else
            {
                
                $_.Modules | ForEach-Object{
                    $Result = @{
                            ProcessName = $Proc.Name
                            ProcessID   = $Proc.Id
                            File = $_.FileName
                        }
                    $object = New-Object -TypeName PSObject -Property $Result
                    [Void]$Results.Add($object)
                    }
            }
        }
        if($Results.Count -eq 0)
        {
            Write-Verbose -Message "No handles found!"
        }
    }
    else
    {
        Write-Warning -Message "No processes found for the process $($Process | out-string) . Please check process name!"
    }
    return $Results
}

function Remove-Handle {
        <#
  .SYNOPSIS
  This function removes handles from a file
  .DESCRIPTION
  This function searchs for handles. You can list handles created by process(es) or the processes that makes handle for a file. If you don't specify any thing, it will list all handles in operating system .Created by Cansin Aldanmaz - 13-07-2017
  .EXAMPLE
  Remove-Handle -Path c:\Users\Cansin.txt -Force
    .EXAMPLE
  Remove-Handle -Path "c:\Users\Cansin.txt","C:\Program Files (x86)\Google\Chrome\Application\59.0.3071.115\chrome_child.dll"
  .EXAMPLE
  Find-Handle -Process chrome
  .PARAMETER Path
  Specify the path of large file(s)
  .PARAMETER Process
  Specify the name(s) of processes that you want to search for.
  #>

  [CmdletBinding(            
    SupportsShouldProcess = $true            
    )]    
Param(
        [Parameter(Mandatory=$True,
            ValueFromPipeline=$True,
            ValueFromPipelineByPropertyName=$True,
            HelpMessage='Enter the path(s) of file(s)')]
            [ValidateNotNullOrEmpty()]
            [String[]]$Path
    )
    foreach($p in $Path)
    {
        Write-Verbose -Message "Finding handles for path $p"
        $handles = Find-Handle -Path $p
        Write-Verbose -Message "$($handles.Count) handles found, removing handles"
        $handles | ForEach-Object {
            $handle = $_
            Stop-Process -Id $handle.ProcessID -Confirm:$(-not $Confirm) -Force -ErrorAction Continue
        }
    }
}