I have many file paths stored in a DB. I need to check if the files actually exist. I've done this before but lost the script for it and need some help.
I put all the paths in a text file and want to loop over them, and check if they exist. if they don't exist, I want to put the nonexistent path in a log file.
Something like this:
# ! equals -not
$log = "e:\pshell\notExists.log"
$log | out-file $log
$list = Get-Content "e:\pshell\files.txt"
Foreach ($file in $list)
{
CHECK IF FILE EXISTS
IF IT DOESNT then Write-Output $file
}
little help?
test-path?
$log = "e:\pshell\notExists.log" $log | out-file $log
$list = Get-Content "e:\pshell\files.txt"
Foreach ($file in $list)
{
If (!(test-path $file))
{
Write-Output $file
}
}
If you inputfile is one filepath per line, try:
$log = "e:\pshell\notExists.log"
Get-Content "e:\pshell\files.txt" | Where-Object {
#Keep only paths that does not exists
!(Test-Path $_)
} | Set-Content $log
$log = "e:\pshell\notExists.log"
Get-Content "e:\pshell\files.txt" |
where {!(test-path $_)} |
add-content $log
Related
I am trying to construct a script that moves through specific folders and the log files in it, and filters the error codes. After that it passes them into a new file.
I'm not really sure how to do that with for loops so I'll leave my code bellow.
If someone could tell me what I'm doing wrong, that would be greatly appreciated.
$file_name = Read-Host -Prompt 'Name of the new file: '
$path = 'C:\Users\user\Power\log_script\logs'
Add-Type -AssemblyName System.IO.Compression.FileSystem
function Unzip
{
param([string]$zipfile, [string]$outpath)
[System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath)
}
if ([System.IO.File]::Exists($path)) {
Remove-Item $path
Unzip 'C:\Users\user\Power\log_script\logs.zip' 'C:\Users\user\Power\log_script'
} else {
Unzip 'C:\Users\user\Power\log_script\logs.zip' 'C:\Users\user\Power\log_script'
}
$folder = Get-ChildItem -Path 'C:\Users\user\Power\log_script\logs\LogFiles'
$files = foreach($logfolder in $folder) {
$content = foreach($line in $files) {
if ($line -match '([ ][4-5][0-5][0-9][ ])') {
echo $line
}
}
}
$content | Out-File $file_name -Force -Encoding ascii
Inside the LogFiles folder are three more folders each containing log files.
Thanks
Expanding on a comment above about recursing the folder structure, and then actually retrieving the content of the files, you could try something line this:
$allFiles = Get-ChildItem -Path 'C:\Users\user\Power\log_script\logs\LogFiles' -Recurse
# iterate the files
$allFiles | ForEach-Object {
# iterate the content of each file, line by line
Get-Content $_ | ForEach-Object {
if ($_ -match '([ ][4-5][0-5][0-9][ ])') {
echo $_
}
}
}
It looks like your inner loop is of a collection ($files) that doesn't yet exist. You assign $files to the output of a ForEach(...) loop then try to nest another loop of $files inside it. Of course at this point $files isn't available to be looped.
Regardless, the issue is you are never reading the content of your log files. Even if you managed to loop through the output of Get-ChildItem, you need to look at each line to perform the match.
Obviously I cannot completely test this, but I see a few issues and have rewritten as below:
$file_name = Read-Host -Prompt 'Name of the new file'
$path = 'C:\Users\user\Power\log_script\logs'
$Pattern = '([ ][4-5][0-5][0-9][ ])'
if ( [System.IO.File]::Exists( $path ) ) { Remove-Item $path }
Expand-Archive 'C:\Users\user\Power\log_script\logs.zip' 'C:\Users\user\Power\log_script'
Select-String -Path 'C:\Users\user\Power\log_script\logs\LogFiles\*' -Pattern $Pattern |
Select-Object -ExpandProperty line |
Out-File $file_name -Force -Encoding ascii
Note: Select-String cannot recurse on its own.
I'm not sure you need to write your own UnZip function. PowerShell has the Expand-Archive cmdlet which can at least match the functionality thus far:
Expand-Archive -Path <SourceZipPath> -DestinationPath <DestinationFolder>
Note: The -Force parameter allows it to over write the destination files if they are already present. which may be a substitute for testing if the file exists and deleting if it does.
If you are going to test for the file that section of code can be simplified as:
if ( [System.IO.File]::Exists( $path ) ) { Remove-Item $path }
Unzip 'C:\Users\user\Power\log_script\logs.zip' 'C:\Users\user\Power\log_script'
This is because you were going to run the UnZip command regardless...
Note: You could also use Test-Path for this.
Also there are enumerable ways to get the matching lines, here are a couple of extra samples:
Get-ChildItem -Path 'C:\Users\user\Power\log_script\logs\LogFiles' |
ForEach-Object{
( Get-Content $_.FullName ) -match $Pattern
# Using match in this way will echo the lines that matched from each run of
# Get-Content. If nothing matched nothing will output on that iteration.
} |
Out-File $file_name -Force -Encoding ascii
This approach will read the entire file into an array before running the match on it. For large files it may pose a memory issue, however it enabled the clever use of -match.
OR:
Get-ChildItem -Path 'C:\Users\user\Power\log_script\logs\LogFiles' |
Get-Content |
ForEach-Object{ If( $_ -match $Pattern ) { $_ } } |
Out-File $file_name -Force -Encoding ascii
Note: You don't need the alias echo or its real cmdlet Write-Output
UPDATE: After fuzzing around a bit and trying different things I finally got it to work.
I'll include the code below just for demonstration purposes.
Thanks everyone
$start = Get-Date
"`n$start`n"
$file_name = Read-Host -Prompt 'Name of the new file: '
Out-File $file_name -Force -Encoding ascii
Expand-Archive -Path 'C:\Users\User\Power\log_script\logs.zip' -Force
$i = 1
$folders = Get-ChildItem -Path 'C:\Users\User\Power\log_script\logs\logs\LogFiles' -Name -Recurse -Include *.log
foreach($item in $folders) {
$files = 'C:\Users\User\Power\log_script\logs\logs\LogFiles\' + $item
foreach($file in $files){
$content = Get-Content $file
Write-Progress -Activity "Filtering..." -Status "File $i of $($folders.Count)" -PercentComplete (($i / $folders.Count) * 100)
$i++
$output = foreach($line in $content) {
if ($line -match '([ ][4-5][0-5][0-9][ ])') {
Add-Content -Path $file_name -Value $line
}
}
}
}
$end = Get-Date
$time = [int]($end - $start).TotalSeconds
Write-Output ("Runtime: " + $time + " Seconds" -join ' ')
Lets say i have 8 files in a folder, and I have a file.csv with 5 lines.
The 8 files start with the same like in the file.csv 0022***_something.csv. So I want to check if filename exist in file.csv
file.csv lines look like:
0022150;something;something;something
0022151;something;something;something
0022152;something;something;something
0022153;something;something;something
0022154;something;something;something
$FileCsv = Get-Content "\\sharedFolder\file.csv" | foreach {($_ -split ";")[0..0]} | Where {($_ -like "00*")}
$FolderPath = "\\SharedFolder\Path\"
Foreach ($file in $folderPath)
{
$file = $file.Substring(0,7)
if ($file exist in $FileCsv) #Not sure how I get this line right.
{
$file + "Exist"
}
else
{
$file + "Does not exist"
}
}
I would do something like this:
$FolderPath = "\\SharedFolder\Path\" #"# This is where the files are found
# read the CSV file, using a header 'Name' for the first column and get this column as an array of strings.
$NamesInCsv = (Import-Csv -Path "\\SharedFolder\file.csv" -Header Name -Delimiter ';').Name
# get a list if files with names that start with '022'
Get-ChildItem -Path $FolderPath -Filter '022*' -File | ForEach-Object {
# if the first 7 characters of the name are in the names from the CSV
if ($_.Name.Length -ge 7 -and $NamesInCsv -contains $_.Name.Substring(0,7)) {
Write-Host "File $($_.Name) exists in the Csv"
}
else {
Write-Host "File $($_.Name) does not exist in the Csv"
}
}
Hope that helps
I am trying to write a script that will read a windows media playlist file and extract the path and filename of all the songs in the playlist and copy the files to a single folder. I am not sure how to strip out the text between the
$wpl = Get-Content "C:\Temp\test.wpl"
foreach ($line in $wpl) {
If ($line -match "<media src=*") {
$file = $line.split("`n")|%{
$_.split('"')[1]}
Copy-Item $file "C:\Temp"
}
}
Tested on Win7 and MediaPlayer 12
For .m3u Files you can do the job with this code:
$list = Get-Content "C:\Temp\test.m3u" | ? { $_ -notmatch "^$|^\s+$" }
foreach ($line in $list) {
If ($line -notmatch '#' ) {
Copy-Item $line "C:\Temp"
}
}
I finally got it to work for m3u files.
$PlaylistName = Read-Host 'Playlist filename (Include drive and path):'
$Directory = Read-Host 'Target Directory (Include drive and path):'
Write-Host "Searching "$PlaylistName" for media files and copying to "$Directory"`n"
(Get-Content $PlaylistName) | where {$+.trim() -ne "" } | Out-File Temp.txt
(Get-Content Temp.txt) | Select-String -pattern "#EXTINF:0" -notmatch | Out-File first.txt
(Get-Content first.txt) | Select-String -pattern "#EXTM3U" -notmatch | Out-File final.txt
Copy-Item (Get-Content final.txt $Directory
Still needs alot of cleanup and much improvement and possibly a gui interface but I am working on that stuff.
I would like to replace a string in a file, and then know if something was actually replaced.
I have many files to parse, and I know only very few will have to be corrected.
So I would like to write the file out only if a changed occurs. Also I would like to be able to trace the changes in a log...
For example, I've been trying this :
(Get-Content $item.Fullname) | Foreach-Object {$_ -replace $old, $new} |
Out-File $item.Fullname
But using I can't tell if any changes were done or not...
Do you have any solution?
Do it in multiple steps:
$content = [System.IO.File]::ReadAllText($item.FullName)
$changedContent = $content -replace $old,$new
if ($content -ne $changedContent) {
# A change was made
# log here
$changedContent | Set-Content $item.FullName
} else {
# No change
}
Use select-string like grep to detect the string and log a message, then use get- and set-content to replace the string:
$item = 'myfile.txt'
$searchstr = "searchstring"
$replacestr = "replacestring"
if (select-string -path $item -pattern $searchstr) {
write-output "found a match for: $searchstr in file: $item"
$oldtext = get-content $item
$newtext = $oldtext.replace($searchstr, $replacestr)
set-content -path $item -value $newtext
}
Hello I have this code I've been working on to loop through a folder add file name to command line parameter of an executeable then output the results to a text file..
The code works for one interation but does not seem to loop through all the files and append to the text file.
Can you take a look at my structure and see why it is not looping through all the files and appending.
Regards.
$Path = "C:\rawfiles"
$files = Get-ChildItem C:\rawfiles\*.001
ForEach ($file in $files) {
c:\outputfiles\ldump.exe $file.fullName > c:\outputfiles\test9.txt -Append
"=======End of Batch========" | Out-File c:\outputfiles\test9.txt -Append
}
You can't mix > with -Append. Try this instead:
$Path = "C:\rawfiles"
$files = Get-ChildItem C:\rawfiles\*.001
ForEach ($file in $files) {
c:\outputfiles\ldump.exe $file.fullName | Out-File c:\outputfiles\test9.txt -Append
"=======End of Batch========" | Out-File c:\outputfiles\test9.txt -Append
}
Or:
$Path = "C:\rawfiles"
$files = Get-ChildItem C:\rawfiles\*.001
ForEach ($file in $files) {
c:\outputfiles\ldump.exe $file.fullName >> c:\outputfiles\test9.txt
"=======End of Batch========" >> c:\outputfiles\test9.txt
}
You may want to add a line at the very beginning to delete or empty test9.txt.