Get missing file name in a sequence of files - powershell

In a folder i have many files, they are sequential, type ABC001.csv,ABC002.csv,ABC003.csv and so on. Sometimes this sequence breaks, then there are missing files and I need to identify which of the sequence are missing in the folder manually, we have more than 700files.
Does anyone here know a power shell script to help me with this task?

If all files to be counted always have a naming format ABC<3-digit number>.csv, then you could do this:
# get an array of integer sequence numbers from the files
$sequence = (Get-ChildItem -Path 'D:\Test' -Filter 'ABC*.csv' -File).BaseName |
Where-Object { $_ -match '(\d{3})$' } | ForEach-Object { [int]$matches[1] } |
Sort-Object -Unique
# get the missing numbers (if any) and output filenames to be collected in $missingFiles
$missingFiles = Compare-Object $sequence (1..($sequence[-1])) -PassThru | ForEach-Object {
'ABC{0:D3}.csv' -f $_ # reconstruct the filename with the missing number
}
# output on screen
if (#($missingFiles).Count) {
Write-Host "Files missing:" -ForegroundColor Yellow
$missingFiles
}
else {
Write-Host "All files are in sequence" -ForegroundColor Green
}
Of course, change the rootpath of the files (here 'D:\Test') to your own

In this example,
The script is located in the same location as a folder named "Temp".
The "Temp" folder had files ABC001.csv through ABC717.csv.
Files ABC123.csv and ABC555.csv were deleted from "Temp" folder.
for ($i = 1; $i -lt 718; $i++) {
$FileName = $PSScriptRoot + '\Temp\ABC{0:d3}.csv' -f $i
if(-not (Test-Path -Path $FileName -PathType Leaf)) {
Write-Host "Missing $FileName"
}
}
Output when ran:
Missing 123
Missing 555

Related

Powershell - Copy files only from the current day and if they don't exist in the target directory

I'm trying to develop a script that copy .txt files from two source folders to one destination folder.
I would like as well to add 2 additional conditions:
If a file already exists in the target directory, skip it
The copied files must not be older than the current day
This is what I made, but it doesn't work as expected:
$SourceDirItemsMITEMAvail = "\\wipfs02\Data\webshop\test\ecomcloud_import\carhartt\product\*"
$SourceDirCaproBPRIC = "\\wipfs02\Data\webshop\test\hybris_import\carhartt\product\*"
$TargetDirB2B = "\\wipfs02\Data\webshop\test\ecomcloud_import\carhartt\b2b\product\"
$ExcludeSubDir = "archive", "IDISC Test", "save", "archive_B2B", "archive_tmp", "Errors"
# Copy only the specific files
$SpecificTypesEcomCloudImport = "avail*", "items*", "MITEM*"
$SpecificTypesHybrisImport = "BPRIC*", "CAPRO*"
# Get the current date
$CurrentDateFiles = (Get-Date).Date
# Copy items from source directories and transfer them to the B2B Folder
For ($i=0; $i -lt $SourceDirItemsMITEMAvail.Count -and $SourceDirCaproBPRIC.Count; $i++) {
# If the copied files don't already exist into the target directory, then copy them
if (-not(Test-Path -Path $SourceDirItemsMITEMAvail, $SourceDirCaproBPRIC)) {
try {
# The copied files must not be older that the current day
$CopyFilesEcomCloudImportDir = Copy-Item $SourceDirItemsMITEMAvail -Exclude $ExcludeSubDir -Destination $TargetDirB2B -PassThru -Verbose -Include $SpecificTypesEcomCloudImport | Where-Object { $_.LastWriteTime -eq $CurrentDateFiles}
Write-Host ""$CopyFilesEcomCloudImportDir.Count" file(s) have been copied from $SourceDirItemsMITEMAvail to $TargetDirB2B."
# The copied files must not be older that the current day
$CopyFilesHybrisImportDir = Copy-Item $SourceDirCaproBPRIC -Exclude $ExcludeSubDir -Destination $TargetDirB2B -PassThru -Verbose -Include $SpecificTypesHybrisImport | Where-Object { $_.LastWriteTime -eq $CurrentDateFiles}
Write-Host ""$CopyFilesHybrisImportDir.Count" file(s) have been copied from $SourceDirCaproBPRIC to $TargetDirB2B."
}
catch {
"Error: $($_.Exception.Message)"
}
}else {
Write-Host "Cannot copy $CopyFilesEcomCloudImportDir because a file with that name already exists in the destination folder."
Write-Host "Cannot copy $CopyFilesHybrisImportDir because a file with that name already exists in the destination folder."
}
}
Either it copies all the files from the sources directories, or it goes immediately to the else condition.
If I remove the if (Test-Path) condition, it copies all the files from the sources, even those who are older than the current day.
If I let the if (Test-Path) condition, it goes immediately to the else statement.
Could you help me to resolve this? Thanks!
Using just PowerShell, you could do this:
$SourceDirItemsMITEMAvail = "\\wipfs02\Data\webshop\test\ecomcloud_import\carhartt\product"
$SourceDirCaproBPRIC = "\\wipfs02\Data\webshop\test\hybris_import\carhartt\product"
$TargetDirB2B = "\\wipfs02\Data\webshop\test\ecomcloud_import\carhartt\b2b\product"
$ExcludeSubDir = "archive", "IDISC Test", "save", "archive_B2B", "archive_tmp", "Errors"
# create a regex of the folders to exclude
# each folder will be Regex Escaped and joined together with the OR symbol '|'
$notThese = ($ExcludeSubDir | ForEach-Object { [Regex]::Escape($_) }) -join '|'
# Copy only the specific files
##############################
# if all files are .txt files, change the patterns below to include that:
# like "avail*.txt", "items*.txt", "MITEM*.txt","BPRIC*.txt", "CAPRO*.txt"
##############################
$FileNamePattern = "avail*", "items*", "MITEM*","BPRIC*", "CAPRO*"
# Get the current date
$today = (Get-Date).Date
Get-ChildItem -Path $SourceDirItemsMITEMAvail, $SourceDirCaproBPRIC -Include $FileNamePattern -File -Recurse |
Where-Object { $_.DirectoryName -notmatch $notThese -and $_.LastWriteTime.Date -eq $today } |
ForEach-Object {
$targetFile = Join-Path -Path $TargetDirB2B -ChildPath $_.Name
if (Test-Path -Path $targetFile -PathType Leaf) {
Write-Host "File '$targetFile' already exists. Skipping"
}
else {
$_ | Copy-Item -Destination $TargetDirB2B -Force
}
}

powershell check for existence of multiple inputs

I need to check if files from input exists.
I split multiple inputs for example BWMDL.VML BWMDL.STA etc and write out files that are already in folder
I check if files from input are present in folder or not.
But I'm getting True, even if the file doesnt exists, also the output from test-path is printed twice, with different result.
Set-Variable -Name Files -Value (Read-Host "instert file name")
Set-Variable -Name FromPath -Value ("C:\Users\Desktop\AP\AP\parser\*.VML" , "C:\Users\Desktop\AP\AP\parser\*.STA")
Set-Variable -Name NameOfFiles (Get-ChildItem -Path $FromPath "-Include *.VML, *.STA" -Name)
Write-Host "FILES IN FOLDER:"
$NameOfFiles
Write-host "---------------------"
Write-host "FILES FROM INPUT: "
Splitted
Write-host "---------------------"
Write-host "FILE EXISTS: "
ForEach ($i in Splitted) {
FileToCheck
}
function Splitted {
$Files -Split " "
}
function FileToCheck {
Test-Path $FromPath -Filter $Files -PathType Leaf
}
For example I'm getting like this result
You are over complicating this.
Once you get the names of all files with extension .VML or .STA in an array, you do not have to use Test-Path anymore, since you know the files in array $NameOfFiles actually do exist, otherwise Get-ChildItem would not have listed them.
This means you can get rid of the helper functions you have defined, which BTW should have been written on top of your code, so before calling on them.
Try
$Files = (Read-Host "instert file name(s) separated by space characters" ) -split '\s+'
$FromPath = 'C:\Users\Desktop\AP\AP\parser'
# if you need to recurse through possible subfolders
$NameOfFiles = (Get-ChildItem -Path $FromPath -Include '*.VML', '*.STA' -File -Recurse).Name
# without recursion (so if files are directly in the FromPath):
# $NameOfFiles = (Get-ChildItem -Path $FromPath -File | Where-Object {$_.Extension -match '\.(VML|STA)'}).Name
Write-Host "FILES IN FOLDER:"
$NameOfFiles
Write-host "---------------------"
Write-host "FILES FROM INPUT: "
$Files
Write-host "---------------------"
Write-host "FILE EXISTS: "
foreach ($file in $Files) { ($NameOfFiles -contains $file) }
Output should look like
instert file name(s) separated by space characters: BWMDL.VML BWMDL.STA
FILES IN FOLDER:
BWMDL.STA
BWMDL.VML
---------------------
FILES FROM INPUT:
BWMDL.VML
BWMDL.STA
---------------------
FILE EXISTS:
True
True

Get creation date with format

I want to loop over images and move each into a folder of the creation date, but I seem to fail to see the point about how to format the resulting datetime string and maybe also how ChildItem works...
I intend to create a variable containing the correct formatted string of the creation date "2017-03-06", so that I can create a directory with that name and move the file there. This shall happen within a loop (for, foreach, ...).
$files = Get-ChildItem "P:\photos\"
for ($i=0; $i -lt $files.Count; $i++) {
$outfile = $files[$i].FullName
Write-Host "file: " $outfile
$CreationDateStr = Get-ChildItem $files[$i].CreationTime |
Get-Date -f "yyyy-MM-dd"
Write-Host "file creation time: " $CreationDateStr
}
Read-Host -Prompt "Press Enter to exit"
This does not work, and the code is not correct:
Get-ChildItem : The disc was not found. Not disc with name "03/06/2017 07"
This works, but it needs to be formatted:
$files[$i].CreationTime
file creation time: 06.03.2017 07:53:21
We don't recommend Write-Host because you can't redirect it.
Here's what I think you are looking for:
Get-ChildItem "P:\Photos" | ForEach-Object {
$dirName = "{0:yyyy-MM-dd}" -f $_.CreationTime
if ( -not (Test-Path $dirName -PathType Container) ) {
[Void] (New-Item $dirName -ItemType Directory)
}
Move-Item $_ $dirName -WhatIf
}
So in the loop, we check if the specified directory doesn't exist (create it if it doesn't), then move the file to the new directory. Remove -WhatIf if the code does what you want.

Identify Empty Folders

I would like to identify a specific empty folder in our user profiles.
I have a text file containing all of our user names that I want the script to refer to. The script will loop each user directory and either output to file or screen and say if the directory is empty. Hidden files do not have to count!
Something similar
FOR /F %U IN (C:\UserList\UserList.TXT) DO *Find and List Empty Folder* \\Server\Share\%U\Target_Folder
Powershell solutions welcome!
This article on Technet provides the following Powershell code snippet to identify all empty folders:
$a = Get-ChildItem C:\Scripts -recurse | Where-Object {$_.PSIsContainer -eq $True}
$a | Where-Object {$_.GetFiles().Count -eq 0} | Select-Object FullName
Replace "C:\Scripts" with the root folder you want to search.
Update:
The following script will get you in the ballpark.
$content = Get-Content C:\Temp\FolderList.txt
foreach ($line in $content)
{
Write-Host $line -NoNewline
$testObject = Test-Path -Path $line
if ($testObject)
{
$folder = Get-Item -Path $line
$filesCount = $folder.GetFiles().Count
if ($filesCount.Equals(0))
{
Write-Host " - Empty folder"
}
else
{
Write-Host " - Contains files"
}
}
else
{
Write-Host " - Invalid path"
}
}

using a global variable in multiple functions powershell

I have this code :
$Count=0
Function DryRun-UploadFile($DestinationFolder, $File, $FileSource, $Count)
{
if($FileSource -eq $null){
$FileSource = $Folder
}
$path= [String]$FileSource+'\'+$File
$Size = get-item $Path
$Size = $Size.length
if($Size -lt 160000){
Write-Host "Passed"
}else{
$Count=$Count+1
}
}
function DryRun-PopulateFolder($ListRootFolder, $FolderRelativePath, $Count)
{
Write-Host "Uploading file " $file.Name "to" $WorkingFolder.name -ForegroundColor Cyan
if(!($File -like '*.txt')){
#Upload the file
DryRun-UploadFile $WorkingFolder $File $FileSource $Count
}else{
$Count=$Count+1
}
}
}
Function DryRun-Copy-Files{
$AllFolders = Get-ChildItem -Recurse -Path $Folder |? {$_.psIsContainer -eq $True}
#Get a list of all files that exist directly at the root of the folder supplied by the operator
$FilesInRoot = Get-ChildItem -Path $Folder | ? {$_.psIsContainer -eq $False}
#Upload all files in the root of the folder supplied by the operator
Foreach ($File in ($FilesInRoot))
{
#Notify the operator that the file is being uploaded to a specific location
Write-Host "Uploading file " $File.Name "to" $DocLibName -ForegroundColor Cyan
if(!($File -like '*.txt')){
#Upload the file
DryRun-UploadFile($list.RootFolder) $File $null $Count
}else{
$Count=$Count+1
}
}
#Loop through all folders (recursive) that exist within the folder supplied by the operator
foreach($CurrentFolder in $AllFolders)
{
DryRun-PopulateFolder ($list.RootFolder) $FolderRelativePath $Count
}
Write-output "Number of files excluded is: "$Count | Out-file DryRun.txt -append
}
I have removed some of my code for simplicity sake as it has nothing to do with my problem. My code goes through a file structure and counts up if the file is above 160000 bytes or is a txt file. run calling DryRun-Copy-Files.
And I have a variable called $count which I want to use in all the functions and then output what the count is to a file.
The problem is it only counts in the first function DryRun-Copy-Files not in the others
define the variable with global:
$global:count=0
and use it in the functions (don't explicit pass it)