Powershell - txt file search - powershell

Im currently trying to get a script to do the following:
search a file location and obtain any .txt,.ini,.config file.
filter this file on an input from the user.
move all the files to a location.
Im having a problem trying to feed in the variable and its probably really simple but im currently struggling to figure out what I need to do without splitting the string up manually. any ideas?
$QQ = Read-Host -Prompt "String your searching for:"
$QL = Read-Host -Prompt "Enter the file location you wish to search:"
$FT = Get-ChildItem -Path "$QL" -recurse | where {$_.extension -eq ".txt"} | % {$_.fullname}
$FI = Get-ChildItem -Path "$QL" -recurse | where {$_.extension -eq ".ini"} | % {$_.fullname}
$FC = Get-ChildItem -Path "$QL" -recurse | where {$_.extension -eq ".config"} | % {$_.fullname}
$FTS = Get-Content -Path "$FT" -Filter "$QQ"
$FIS = Get-Content -Path "$FI" -Filter "$QQ"
$FCS = Get-Content -Path "$FC" -Filter "$QQ"
$FD = "C:\Search-$QQ"
$FD1 = Get-ChildItem $FD
function folder {
if ($FD -eq $Null) {New-Item "$FD" -ItemType directory}}
function search{
if ($FTS -ne $null){Copy-Item -Path $ft -Destination "$fd" | Write-Host "$FT" | Format-List}
if ($FIS -ne $null){Copy-Item -path $fi -Destination "$fd" | Write-Host "$FI" | Format-List}
if ($FCS -ne $null){Copy-Item -Path $fc -destination "$fd" | Write-Host "$FC" | Format-List}
}
folder
search;
An example of the error being received is: (obviously an issue with it treating the multiple files in the string as one)
Get-Content : Cannot find path 'C:\test\Test\1c.config C:\test\Test\2c.config C:\test\Test\3c.config' because it does not exist.

right off the bat I see the folder function will not work property as $FD will never be null since you assign a string to it, if you need to check if the folder exists use Test-Path. but in relation to your actual script the problem is your use of get-content which is trying to read all of your files contents into an array of strings. from the looks of it you should just be working with the arrays returned by Get-ChildItem and use Test-Path to check your paths rather than that weird Get-Content method you are using(since the content of the files doesn't matter, just whether they exist or not). You also need to incorporate a loop to act on each array element individually rather than trying to work on them in groups like you are.

(This Script is to mass search application files to find values like server id's or passwords hardcoded etc)
Fixed code:
$QQ = Read-Host -Prompt "String your searching for:"
$QL = Read-Host -Prompt "Enter the file location you wish to search:"
$FT = Get-ChildItem -Path "$QL" -recurse | where {$_.extension -eq ".txt"} | % {$_.fullname}
$FI = Get-ChildItem -Path "$QL" -recurse | where {$_.extension -eq ".ini"} | % {$_.fullname}
$FC = Get-ChildItem -Path "$QL" -recurse | where {$_.extension -eq ".config"} | % {$_.fullname}
$FTS = Get-Content -Path $FT -Filter "$QQ"
$FIS = Get-Content -Path $FI -Filter "$QQ"
$FCS = Get-Content -Path $FC -Filter "$QQ"
$FD = "C:\Support\Search-$QQ"
$FD1 = Test-Path $FD
function folder {
if ($FD1 -eq $false) {New-Item "$FD" -ItemType directory}
}
function search{
if ($FTS -ne $null){Copy-Item -Path $ft -Destination "$fd" | Write-Host "$FT" | Format-List}
if ($FIS -ne $null){Copy-Item -path $fi -Destination "$fd" | Write-Host "$FI" | Format-List}
if ($FCS -ne $null){Copy-Item -Path $fc -destination "$fd" | Write-Host "$FC" | Format-List}
}
folder
search;

try this
$QL = Read-Host -Prompt "Enter the file location you wish to search:"
if (-not (Test-Path $QL))
{
write-host "Specified path ($QL) doesnt exists "
return;
}
$QQ = Read-Host -Prompt "String your searching for:"
$FD = "C:\Search-$QQ"
New-Item "C:\Search-$QQ" -ItemType directory -Force | out-null
Get-ChildItem -Path "$QL" -recurse -include "*.txt", "*.ini", "*.config" |
select-string -Pattern "$QQ" -SimpleMatch |
%{ Copy-Item -Path $_.Path -Destination "$fd" -Force ; $_.Path }

Related

How to write all the files names from a folder inside a txt file

With this code I get the data but is not reflected on the txt file. I just get a bunch of Microsoft.PowerShell.Commands.Internal.Format.FormatStartData.
Microsoft.PowerShell.Commands.Internal.Format.GroupStartData
Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData
Instead the names of each file.
Here is the code:
param(
[string]$foldername = 'unknown'
)
if (Test-Path $foldername){
$location = Join-Path -Path $HOME -ChildPath "files.txt"
$files = Get-ChildItem $foldername | Where-Object {$_.PsIsContainer -ne $True} | Format-Table
Name
$amount = Get-ChildItem $foldername | Where-Object {$_.PsIsContainer -ne $True} | Measure-
Object
Add-Content -Path $location -Value $files
Write-Host $amount.count "filenames were written to file" $location
}
else {Write-Host "Sorry,", $foldername, "does not exist."
break
}
First get-childitem supports the switch File, no need to pipe and filter. The Format-Table is used to format the output displayed on the screen, so as you want to write to a file you do not need it.
Also only use break within a loop, if you want to stop the processing use return instead.
param(
[string]$foldername = 'unknown'
)
if (Test-Path $foldername){
$location = Join-Path -Path $HOME -ChildPath "files.txt"
#gets all files in the specified path
$files = Get-ChildItem $foldername -File
#counts the number of files
$amount = $files.count
#If you want the fullpath in the logfile use $files.fullname if you only want the name use $files.name
$files.FullName | Add-Content -Path $location
Write-Host "$amount filenames were written to file $location"
}
else {
Write-Host "Sorry, $foldername, does not exist."
return
}

powershell script not interpreting file path correctly

I have an issue where a path to a file is generated by an application. So the path looks like this….
Unfortunately, this output is generated from an application…so I cannot manipulate the output.
Now…when I run my powershell script to copy the file …I get the following errors
It seems that the problem is that my powershell script is not getting the path correctly….
$folders = Get-Content -Path '\\TFA-APP-01\CUI\WS\FOUNDFILES\results.txt'
$dest = '\\TFA-APP-01\CUI\WS\FOUNDFILES\found\'
$excludes = "WS","FOUNDFILES"
foreach ($folder in $folders) {
# Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Desktop'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Documents'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Downloads'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Outlook'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'INetCache'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Attachments'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
}
How can I either parse the results.txt file and extract just the file paths to another text file?
Or how can I modify my CopyResults.ps1 script to interpret the file path correctly?
Your issue is that Get-Content converts every line of a file into an element of an array, and you don't want to look at every line. You want to look at a specific part of a specific line that repeats in a specific pattern.
Because of all of these constants, we can make a pretty simple script to get the information you want.
$paths = Get-Content C:\temp\paths.txt
for ($i = 1; $i -lt $paths.Length; $i += 3) {
$path = "$($paths[$i].Split('.txt')[0]).txt"
$path # \\SERVER\PATH\FILE.TXT
}
Your file has a pattern of [empty line, path line, company line]. If we think about the .txt file as an array with many subarrays of that pattern, we can see that we want to get the 1st index ($i = 1) for every set of 3 ($i += 3) in the file.
Since I split by .txt, I have to string interpolate the .txt extension back on.
Edit:
Here's the script modified for your issues
$paths = Get-Content C:\temp\paths.txt
for ($i = 1; $i -lt $paths.Length; $i += 3) {
$pathSplit = $paths[$i].Split('.')
$extension = $pathSplit[1].split(' ')[0]
$path = "${$pathSplit[0]).$extension"
$path # \\SERVER\PATH\FILE.TXT
}
$pathSplit is split at the extension into 2 parts. One is the majority of the path and the other is the rest of the line.
$extension looks at the 1st index and splits by the space in order to isolate the file extension.
Finally, $path combines $pathSplit[0] and $extension to give you the full file path.

Powershell Unzip One Specific Folder in a File with Dynamic Name

I found a piece of code here that almost does what I need, which is extract just one folder from an archived file.
The only issue I have is that the archive name changes month on month, therefore I wanted to use a wildcard. Once a wildcard is specified (* in $zipfile), the script does not work for me.
I would be grateful for any suggestions.
[Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') | Out-Null
$zipfile = 'C:\ALL\Debtor*.zip'
$folder = 'tmp\st\sd'
$dst = 'C:\ALL\ZipOutput'
[IO.Compression.ZipFile]::OpenRead($zipfile).Entries | ? {
$_.FullName -like "$($folder -replace '\\','/')/*.*"
} | % {
$file = Join-Path $dst $_.FullName
$parent = Split-Path -Parent $file
if (-not (Test-Path -LiteralPath $parent)) {
New-Item -Path $parent -Type Directory | Out-Null
}
[IO.Compression.ZipFileExtensions]::ExtractToFile($_, $file, $true)
Try this out for size. Just use Get-ChildItem to locate the zip file in your ALL directory.
[Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') | Out-Null
$zipfile = Get-ChildItem -Path C:\ALL\ -Filter *.zip | Where-Object {$_.Name -like "Debtor*"} | Select-Object -ExpandProperty FullName
$folder = 'tmp\st\sd\'
$dst = 'C:\ALL\ZipOutput'
[IO.Compression.ZipFile]::OpenRead($zipfile).Entries | Where-Object {
$_.FullName -like "$($folder -replace '\\','/')/*.*"
} | ForEach-Object {
$file = Join-Path $dst $_.FullName
$parent = Split-Path -Parent $file
if(-not (Test-Path -LiteralPath $parent)) {
New-Item -Path $parent -Type Directory | Out-Null
}
[IO.Compression.ZipFileExtensions]::ExtractToFile($_, $file, $true)
}
I am also assuming that the archive name changes but there are not multiple archives with that name. If there are you will need to wrap everything in a Foreach($zip in $zipfile){ ... }

Copy everything except files on the list

I am trying to copy all files recursively from a:\ to b:\, except those whose metadata is present in a:\list.txt. The list.txt pattern is LastWriteTimeYYYY-MM-DD HH:MM:SS,size,.fileextension, for example:
2001-01-31 23:59:59,12345,.doc
2001-01-31 23:59:59,12345,.txt
2001-01-31 23:59:00,456,.csv
...so any and all files, anywhere in the a:\ dir tree, matching these metadata should not be copied.
I seem to be having trouble with the Where-Object in order to exclude the items on the list.txt, but copy everything else:
$Source = "C:\a"
$Target = "C:\b"
$List = Import-Csv list.txt -Header LastWriteTime,Size,Name
$Hash = #{}
ForEach ($Row in $List){
$Key = ("{0},{1},.{2}" -F $Row.LastWriteTime,$Row.Size,$Row.Name.Split('.')[-1].ToLower())
IF (!($Hash[$Key])) {$Hash.Add($Key,$Row.Name)}
}
$Hash | Format-Table -Auto
Get-Childitem -Path $Source -Recurse -File | Where-Object {$Hash -eq $Hash[$Key]}| ForEach-Object {$Key = ("{0},{1},{2}" -F ($_.LastWriteTime).ToString('yyyy-MM-dd HH:mm:ss'),$_.Length,$_.Extension.ToLower())
#$Key
If ($Hash[$Key]){
$Destination = $_.FullName -Replace "^$([RegEx]::Escape($Source))","$Target"
If (!(Test-Path (Split-Path $Destination))){MD (Split-Path $Destination)|Out-Null}
$_ | Copy-Item -Destination $Destination
}
}
I propose you a simplification of your code :
$Source = "C:\a\"
$Target = "C:\b\"
New-Item -ItemType Directory $Target -Force | Out-Null
$List = Import-Csv list.txt -Header LastWriteTime,Length,Extension
Get-Childitem $Source -Recurse -File | %{
$File=$_
$exist=$List | where {$_.LastWriteTime -eq $File.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss') -and $_.Length -eq $File.Length -and $_.Extension -eq $File.Extension} | select -first 1
if ($exist -ne $null) {continue}
New-Item -ItemType Directory $File.DirectoryName.Replace($Source, $Target) -Force | Out-Null
Copy-Item $File.FullName $File.FullName.Replace($Source, $Target) -Force
}

Deleting a created file at every iteration

$getFiles = Get-ChildItem -Path $readDir -File -Include "*.doc","*.docx","*.xlsx"-Recurse | %{
if(($_ -match "\.doc$") -or ($_ -match "\.docx$")){
$Doc = $word.Documents.Open($_.fullname)
$nameDoc = $fileSaveLoc + $_.Name.Replace(".docx",".txt").replace(".doc",".txt")
$Doc.saveas([ref] $nameDoc, [ref] 5)
$Doc.close()
if((Get-ChildItem "I:\temp\").length -ne 0){
$locations = (Get-Item "I:\temp\"), (Get-ChildItem "I:\temp\" -Directory -recurse) | % {
Get-ChildItem -File $_.FullName | Select-String -List -Pattern '^\d{3}-?\d{2}-?\d{4}$' |
% Path
}
if($locations -ne $null){
$locations | out-file "I:\temp\SSN_FILES.txt"
#Get-ChildItem "I:\temp\" -exclude "fullpath.txt","SSN_FILES.txt" | remove-item
}else{
Get-ChildItem "I:\temp\" -exclude "fullpath.txt","SSN_FILES.txt" | remove-item
}
}
}
elseif($_ -match "\.xlsx$"){
$workbook = $excel.Workbooks.Open($_.FullName)
$csvFilePath = "I:\temp\" + $_.Name.Replace(".xlsx",".csv")
#$csvFilePath = $_.FullName -replace "\.xlsx$", ".csv"
$workbook.SaveAs($csvFilePath, [Microsoft.Office.Interop.Excel.XlFileFormat]::xlCSV)
$workbook.Close()
if((Get-ChildItem "I:\temp\").length -ne 0){
$locations = (Get-Item "I:\temp\"), (Get-ChildItem "I:\temp\" -Directory -recurse) | % {
Get-ChildItem -File $_.FullName | Select-String -List -Pattern '^\d{3}-?\d{2}-?\d{4}$' |
% Path
}
if($locations -ne $null){
$locations | out-file "I:\temp\SSN_FILES.txt"
#Get-ChildItem "I:\temp\" -exclude "fullpath.txt","SSN_FILES.txt" | remove-item
}else{
Get-ChildItem "I:\temp\" -exclude "fullpath.txt","SSN_FILES.txt" | remove-item
}
}
}
}
So this basically says:
check for a file matching doc/docx/xlsx
convert them into a file that can be parsed through
parse through each file at every iteration and compare it to a regex
if the regex is not null, then output it to a file with the file path
otherwise, delete it and anything else that was created except for two files
restart the process at the next file
Now the problem I am encountering is that the files aren't being deleted. I can't get them to be removed when they are created, when I know they don't match the regex. Setting ($locations -eq $true) doesn't solve that issue because it never goes into the first conditional statement.
The folder should contain only the two files that were created and possibly the ones that match the regex.