I have hourly log files from the past couple of months and i would like to export the data to MS Charts.
I've managed to get the data out, but having problems with getting the date on the x axis of the Chart.
The file name of the log file contains the date and i've tried using the creatation date or last write time. The closest i've got is to count the number of logs then divide by 24, but the dates it generates does not match up with the data.
Any ideas please?
Everything works as expected, but i cant get the X Axis to display the correct dates. in theory, it should calculate the 11 June as the start date, and the end date is yesterday's date.
the format of the file it reads from is
HealthCheck Wed 10 Sep 2014 - 05.00 AM.log
Ideally, I would like to get the date from the file name. I dont want to rely on calculations on when the file was written as this is prone to errors.
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms.DataVisualization")
$Farm = "XAccess"
#gets files from yesterday
$Date = Get-Date #-Uformat %x
$Date = ($Date).adddays(-1)
$Date = $Date.ToString("M/d/yyyy")
$files = get-childitem "c:\$Farm*.log" | Where{$_.LastWriteTime -lt $date}
$ActiveSessions = Select-String -path $files '(?<=^"*Total Active Sessions: )\d+(?=)'|
ForEach-Object {$_.Matches[0].Value}
#Calculates numbers of days
$datapoints = $ActiveSessions.count/24
#== Creates Chart ==#
# create chart object
$Chart = New-object System.Windows.Forms.DataVisualization.Charting.Chart
$Chart.Width = 1600
$Chart.Height = 800
# create a chartarea to draw on and add to chart
$ChartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
$Chart.ChartAreas.Add($ChartArea)
[void]$Chart.Series.Add("Data")
$Chart.ChartAreas["ChartArea1"].AxisX.Interval = 24
$Chart.ChartAreas["ChartArea1"].AxisX.LabelStyle.Angle = -40
$Chart.ChartAreas["ChartArea1"].AxisY.Interval = 5
$Chart.ChartAreas["ChartArea1"].AxisY.title = "Active Sessions"
$chart.Series.Add('ChartArea1')
# add a data point for each server
foreach ($session in $ActiveSessions)
{
$dp1 = new-object System.Windows.Forms.DataVisualization.Charting.DataPoint(0, $session)
$dp1.AxisLabel = (get-date).adddays(-"$datapoints").tostring("ddd dd MMM")
$datapoints = $datapoints - 0.0416666666666667
$Chart.Series["Data"].Points.Add($dp1)
}
# set the title to the date and time
$title = new-object System.Windows.Forms.DataVisualization.Charting.Title
$Chart.Titles.Add( $title )
$Chart.Titles[0].Font = "Arial,13pt"
$Chart.Titles[0].Text = "Year to Date sessions for $Farm"
# save the chart to a file
$Chart.SaveImage("C:\$Farm Farm.png","png")
Ok, so you want the date from the file. No problem, we can do that. Let's start with how best to do it... We have options (as usual) to choose from. Wait, I'm getting ahead of myself. Where do we want to define it? Well, simplest place I can think of is anyplace that you are looping through the files in question and getting other data, so we can keep everything properly associated. So, it looks like the lines that you assign $ActiveSessions is going to be our best bet.
Now, back to how to get the date. We could use the SubString method, but that just seems messy to me when we have a defined format for the text. Personally I'd rather do a regex match. So what I see in the file name is a three letter day abbreviation, then a 1-2 digit day, a three letter month, and a four digit year. After that there's a hyphen, and two digit hour, period, two digit minute, and the AM/PM designator.
So, as far as [datetime] formats go that's ddd d MMM yyyy - hh.mm tt. We'll get back to that. How to extract the date? Oh right, a regex. Here's how I'd get that:
([regex]"\w{3} \d{1,2} \w{3} \d{4} - \d{2}\.\d{2} (?:AM|PM)").matches($_.Filename).value
That declares the pattern as a regex object, and then uses it's Matches() method, and get the value of the match. So we have the date, now to actually make it usable. Here's where we get back to that DateTime format. We can use the [DateTime]::ParseExact() method to get the date time, even with the strange formatting. Now we are going to be getting it in the ForEach loop, and are extracting the date from the FileName property of the object that Select-String is feeding the loop. Here's what it will look like:
[datetime]::ParseExact(([regex]"\w{3} \d{1,2} \w{3} \d{4} - \d{2}\.\d{2} (?:AM|PM)").matches($_.Filename).value,"ddd d MMM yyyy - hh.mm tt",$null)
Ok, that actually gives us a nice usable datetime object. So that ForEach loop is already spitting back the active sessions, and $ActiveSessions is an array of strings. Let's change that a little and make it an array of objects, and each object will have two properties now, Sessions and Date. So the inside of the ForEach loop has to make an object with those properties. Easiest way (with PowerShell v3 or higher, I'll show you the hard way if you are running an old version of PowerShell and need me to) is:
[PSCustomObject][Ordered]#{
'Sessions'=$_.Matches[0].Value
'Date'=[datetime]::ParseExact(([regex]"\w{3} \d{1,2} \w{3} \d{4} - \d{2}\.\d{2} (?:AM|PM)").matches($_.Filename).value,"ddd d MMM yyyy - hh.mm tt",$null)
}
That makes the whole $ActiveSessions = line look like:
$ActiveSessions = Select-String -path $files '(?<=^"*Total Active Sessions: )\d+(?=)'|
ForEach-Object {[PSCustomObject][Ordered]#{
'Sessions'=$_.Matches[0].Value
'Date'=[datetime]::ParseExact(([regex]"\w{3} \d{1,2} \w{3} \d{4} - \d{2}\.\d{2} (?:AM|PM)").matches($_.Filename).value,"ddd d MMM yyyy - hh.mm tt",$null)
}
}
Only thing that leaves is to change where that variable is referenced:
foreach ($session in $ActiveSessions)
{
$dp1 = new-object System.Windows.Forms.DataVisualization.Charting.DataPoint(0, $session.session)
$dp1.AxisLabel = $Session.Date.tostring("ddd dd MMM")
$Chart.Series["Data"].Points.Add($dp1)
}
That should do it for you.
I tried using regex but could not get pass the error i mentioned.
so after a bit more research, i decided exporting the creation date of the file and the data i needed into a CSV file, then creating the chart from that. So this is the code i used to get the data in to csv:
$files = get-childitem "c:\$farm*.log" | sort CreationTime
Foreach ($file in $files)
{
$FileCreation = $file.CreationTime.Date.ToString('ddd dd MMM yyyy')
$ActiveSessions = Select-String -path $file '(?<=^"*Total Active Sessions: )\d+(?=)' | ForEach-Object {$_.Matches[0].Value}
Add-Content d:\licInUse.csv "$FileCreation,$ActiveSessions"
}
# processing the Data
$Processes = Import-Csv -path d:\licInUse.csv -Delimiter ',' -Header "Date","Count"
$DateNames = #(foreach($Date in $Processes){$Date.Date})
$SessionCount = #(foreach($Date in $Processes){$Date.Count})
then used the following to plot the data
$Chart.Series["Data"].Points.DataBindXY($DateNames, $SessionCount)
Related
I have written a PowerShell script to extract the date from filenames and delete based on that.
Sample file name: TBTT_UAT_01012021_000019.csv
Code to extract date :
$fileDateText = ($filename -split '_')[4]
$fileDate = [System.DateTime]::ParseExact($fileDateText, "dd/MM/yyyy", [System.Globalization.CultureInfo]::InvariantCulture)
But I am getting the following error when I run the script, as it recognizes the date before CSV:
String '000019.csv' was not recognized as a valid DateTime.: FormatException
Can someone advise, please?
Thanks,
I think you may be looking at the wrong array element returning from your split. Also the string you are giving in the overloads for .ParseExact() may be off. This seemed to work in my tests:
$fileDate = ("TBTT_UAT_01012021_000019.csv" -split '_')[2]
[DateTime]::ParseExact($fileDate, "ddMMyyyy", [System.Globalization.CultureInfo]::InvariantCulture)
Returned: Friday, January 1, 2021 12:00:00 AM
If you want to get more granular about the time we'll have to cut up the string file name differently.
Issue has been fixed by changing from:
[System.DateTime]::ParseExact($fileDateText, "dd/MM/yyyy", [System.Globalization.CultureInfo]::InvariantCulture)
to
$fileDate = [DateTime]::ParseExact("$fileDateText", 'ddMMyyyy',[CultureInfo]::InvariantCulture)
if ($filename -match '(?<Timestamp>\d{8})') {
[DateTime]::ParseExact($Matches.Timestamp, 'ddMMyyyy', [CultureInfo]::InvariantCulture)
}
I gravitate toward regexes with named extraction groups rather than doing string manipulation. The syntax is a bit more fiddly, but the resulting script ends up being more resilient.
My data($messages) looks like this
Source: sourceA
Message : {#{messagetext = abc;publishedtime = 10/5/2020}, #{messagetext = def;publishedtime = 10/12/2020}
I am trying to filter the message by displaying only messages that happened from last week until now then combining it with the source property. It is possible that a source may have multiple lines if several publishedtime happened last week.
$filterDate = (Get-Date).AddDays(-7)
$messages | select source, #{n='messagetext' ; e={???}} , #{n='publishedtime' ; e={???}}
I am lost on how to add the calculated property with the condition. I was also thinking if this could be done with a loop.
I also tried the following but having some errors
$Messages | Where-Object {([DateTime]($_.messages).publishedtime).ToUniversalTime() -ge $filterDate} but having some error
There is no need to use a calculated property. First filter the $messages collection by date. Like so,
$filterDate = (Get-Date).AddDays(-7)
$lastWeek = $messages | ? { $_.PublishedTime -ge $filterDate }
Now the $lastWeek collection contains only messages that were published within a week. Depending on the exact format of PublishedTime and your locale settings, it might need to be parsed as a date. If that's the case, please edit the question and show a few examples of actual data. Sanitize the messages if needed.
I think you should always compare dates to dates, and not compare a datetime object to a string, especially since in your question it is unclear what exact format the date is in.
Probably the format used is 'M/d/yyyy', but it could just aswell be 'd/M/yyyy' or even 'MM/d/yyyy'
$dateFormat = 'M/d/yyyy' # <-- this is unclear in the question, could also be 'd/M/yyyy' or 'MM/d/yyyy'
# you can set the Time part to all zero, as the dates in the $Messages objects also do not have that
$filterDate = (Get-Date).AddDays(-7).Date
$Messages | Where-Object {[DateTime]::ParseExact($_.Message.publishedtime, $dateFormat, $null) -ge $filterDate}
It is my first time that I am reaching back to you as I am stuck on something and been scratching my head for over a week now. It is worth saying that I just started with PowerShell a few months ago and I love using it for my scripts, but apparently my skills still need improving. I am unable to find a simple and elegant solution that would extract a log from clearly defined start line until the first empty line CF\LF or time stamp that follows.
I am attaching the log I am trying to extract the data from. To specify the problem and give some more details about the log lines - they can vary in number, the end line of each log can also vary and the time stamp is different for each log depending on the time the test was executed.
cls
# Grab the profile system path
$userProfilePath = $env:LOCALAPPDATA
# Define log path
$logPath = "$userProfilePath\DWIO\logs\IOClient.txt"
# Define the START log line matching string
# This includes the the tests that PASS and FAIL
$logStartLine = " TEST "
# Find all START log lines matching the string and grab their line number
$StartLine = (Get-Content $logPath | select-string $logStartLine)
#Get content from file
foreach ($start in $StartLine) {
# Extract the date time stamp from every starting line
$dateStamp = ($start -split ' ')[0]
#Regex pattern to compare two strings
$pattern = "(.*)$dateStamp"
#Perform the opperation
$result = [regex]::Match($file,$pattern).Groups[1].Value
Write-Host $result
}
The log format is like:
08-31 16:32:20 INFO - [IOBridgeThread - mPerformAndComputeIntegrityCheck] - BridgeAsyncCall - mPerformAndComputeIntegrityCheck Result = TEST PASSED
Average Camera Temperature :40.11911°C
Module 0
Nb Points: 50673 pts (>32500)
Noise:
AMD: 0.00449238 mm (<0.027)
STD DEV: 0.006961088 mm
Dead camera: false
Module 1
Nb Points: 53809 pts (>40000)
Noise:
AMD: 0.0055302843 mm (<0.027)
STD DEV: 0.00869096 mm
Dead camera: false
Module consistency
Weak module: false
M0 to M1
Distance: 0.007857603 mm (<0.015)
Angle: 0.022567615 degrees (<0.07)
Target
Position: 0.009392071 mm (<5.0)
Angle: 0.54686683 degrees (<5.0)
Intensity: 120.35959
08-31 16:32:20 INFO - [cIOScannerService RUNNING] - Scanner State is now Scan-Ready
The issue is that the line at the end of every log would be different as well as the log lines would differ so it is the only logical way to achieve the correct extraction is to match the first line which would always contain: " TEST " and then grab the log to the first timestamp appearance after or the empty line which also shows every time at the end of the log.
Just not sure how to achieve that and the code I have is returning no/empty matches, however if I echo $StartLine - it shows correctly the log starting lines.
You can match the first line that starts with a date time like format and contains TEST in the line. Then capture in group 1 all the content that does not start with a date time like format.
(?m)^\d{2}-\d{2} \d{2}:\d{2}:\d{2}.*\bTEST\b.*\r?\n((?:(?!\d{2}-\d{2} \d{2}:\d{2}:\d{2}).*(?:\r?\n|$))*)
Explanation
(?m) Inline modifier for multiline
^ Start of line
\d{2}-\d{2} \d{2}:\d{2}:\d{2}.*\bTEST\b.* Match a date time like pattern followed by TEST in the line
\r?\n Match a newline
( Capture group 1
(?: Non capture group
(?!\d{2}-\d{2} \d{2}:\d{2}:\d{2}).*(?:\r?\n|$) If the line does not start with a date time like pattern, match the whole line followed by either a newline or the end of the line
)* Close non capture group and repeat 0+ times
) Close group 1
See a regex101 demo and a .NET regex demo (click on the Table tab) and a powershell demo
You can use Get-Content -Raw to get the contents of a file as one string.
$textIOClient = Get-Content -Raw "$userProfilePath\DWIO\logs\IOClient.txt"
$pattern = "(?m)^\d{2}-\d{2} \d{2}:\d{2}:\d{2}.*\bTEST\b.*\r?\n((?:(?!\d{2}-\d{2} \d{2}:\d{2}:\d{2}).*(?:\r?\n|$))*)"
Select-String $pattern -input $textIOClient -AllMatches | Foreach-Object {$_.Matches} | Foreach-Object {$_.Groups[1].Value}
I found an approach I really loved in this answer elsewhere on the site:
PowerShell - Search String in text file and display until the next delimeter
Using that, I wrote a little code around it in the following to show you how to use the results:
$itemCount = 1
$Server = ""
$Data = #()
$Collection = #()
Switch(GC C:\temp\stackTestlog.txt){
{[String]::IsNullOrEmpty($Server) -and !([String]::IsNullOrWhiteSpace($_))}{$Server = $_;Continue}
{!([String]::IsNullOrEmpty($Server)) -and !([String]::IsNullOrEmpty($_))}{$Data+="`n$_";Continue}
{[String]::IsNullOrEmpty($_)}{$Collection+=[PSCustomObject]#{Server=$Server;Data=$Data};Remove-Variable Server; $Data=#()}
}
If(!([String]::IsNullOrEmpty($Server))){$Collection+=[PSCustomObject]#{Server=$Server;Data=$Data};Remove-Variable Server; $Data=#()}
if(($null -eq $collection) -or ($Collection.Count -eq 0)){
Write-Warning "Could not parse file"
}
else{
Write-Output "Found $($collection.Count) members"
ForEach($item in $Collection){
#add additional code here if you need to do something with each parsed log entry
Write-Output "Item # $itemCount $($item.Server) records"
Write-Host $item.Data -ForegroundColor Cyan
$itemCount++
}
}
You can extend this in the line with a comment, and then remove the Write-output and Write-Host lines too.
Here's what it looks like in action.
Found 2 members
Item #1 08-31 16:32:20 INFO - [IOBridgeThread - mPerformAndComputeIntegrityCheck] - BridgeAsyncCall - mPerformAndCompu
teIntegrityCheck Result = TEST PASSED records
Average Camera Temperature :40.11911°C
#abridged...
Item #2 blahblahblah
I've tried a lot of different ways and I can't seem to get it right.
Here is the code of what I have tried so far...
[String]$dateValue = '20161212'
[String]$dateStamp = $dateValue -f (Get-Date)
[String]$dateStamp2 = ([datetime]::parseexact($dateValue, "yyyyMMdd", [System.Globalization.CultureInfo]::InvariantCulture)).Date
[String]$dateStamp3 = ([datetime]::FromFileTime($dateValue)).ToString('g')
Write-Host '$dateStamp = ' $dateStamp
Write-Host '$dateStamp2 = ' $dateStamp2
Write-Host '$dateStamp3 = ' $dateStamp3
Current Code Output
$dateStamp = 20161212
$dateStamp2 = 12/12/2016 00:00:00
$dateStamp3 = 12/31/1600 5:00 PM
Desired Code Output
$dateStamp = 12/12/2016
Any Ideas?
Once you have a datetime object it's easy to convert it to whatever string format you need. You are so close with your second attempt. Adding ToString allows you to specify a string format.
([datetime]::parseexact($dateValue, "yyyyMMdd", [System.Globalization.CultureInfo]::InvariantCulture)).ToString("dd/MM/yyyy")
Given that you have a culture-invariant string as your input and that you want a fixed output format, you may as well perform string parsing, without the need to convert to an intermediate [datetime] instance:
> '20161213' -replace '\d{2}(\d{2})(\d{2})(\d{2})', '$2/$3/$1'
12/13/16
Note that I've changed the day to be different from the month to better highlight the reformatting that takes place.
Generally, though, the [datetime]-based method demonstrated in Nick's helpful answer gives you the most flexibility.
Full disclosure, I'm fairly new to using Powershell and I'm working on a solution that tests if 38 excel reports are in a certain location and formatted with a specific date at the end of it (e.g. Excel-Advanzia-Outages 18 Sep 2015), copies them to another folder as backups, runs a macro in another excel workbook (that sorts the reports into subfolders based on the date), and lastly deletes the 38 reports from the original folder.
I changed/removed the date from one of the reports so that it would come back false to test what would happen, but it is still is trying to execute the code in the IF statement. Everything seems to work if all the reports are correctly formatted though.
I'd love to hear some feedback on how to fix the error or if there might be a better, more dynamic way to code this. Thanks!
Here is my code so far:
# Declares variable $a as today's date and will add 2 days in "dd MMM yyyy" formatting (Adding 2 days because this will be set up to run on Wednesday and checks for files that have Friday's date)
$a = "{0:dd MMM yyyy}" -f (get-date).AddDays(2)
# Verifies each Excel file is correctly formatted with upcoming Friday's date formatted as "dd MMM yyyy" at end of file. If true, code inside if statement is executed.
If ((test-path "C:\Users\mathill\Desktop\Outages\Excel-Advanzia-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-AIB-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-American-Express-Corp-Srvcs-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Amex-Central-Europe-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Arcot-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-B+S-Card-Service $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Bank-of-America-Asia-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Bank-of-America-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Barclays-Commercial-Card-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-BOI-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-C-Card-S-p-A-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-CCUK Finance-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-CMC-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-COBE-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Degussa-Bank-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Deutsche-Bank-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Elavon-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Home-Retail-Group-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-IE-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-ING-CPS-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-JPMC-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-KBC-Bank-Ireland-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Lloyds-TSB-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Metro-Bank-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-NBS-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-PayPal-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Prime-Carrefour-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-PTSB-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Rabo-Bank-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-RBSG-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-RSA-Cyota-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Swisscard-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Telrock-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Tesco-Bank-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-TSYS-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Virgin-Money-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Wells-Fargo-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-WEX-Outages $a.xls") -eq $true)
{
# Deletes all files in "C:\Users\mathill\Desktop\Outages\Current (Pre-Wrap)"
Remove-Item "C:\Users\mathill\Desktop\Outages\Current (Pre-Wrap)\*.*"
# Copies all Excel files from Outages folder into Current (Pre-Wrap) folder as backups
Copy-Item C:\Users\mathill\Desktop\Outages\*.xls "C:\Users\mathill\Desktop\Outages\Current (Pre-Wrap)"
# Create new Excel Object
$objExcel = new-object -comobject excel.application
# Open Workbook from specific location
$objWorkbook = $objExcel.Workbooks.Open("C:\Users\mathill\Desktop\Outage Protection Macro - Class.xls")
# Open workbook to first worksheet
$worksheet = $Objworkbook.worksheets.item(1)
# Run outageprotect macro
$objExcel.Run("outageprotect")
# Close workbook without saving
$objWorkbook.close($false)
# Exit Excel
$objExcel.quit()
# Remove all Excel files from Outages folder
Remove-Item "C:\Users\mathill\Desktop\Outages\*.xls"
}
It is because some values are returning true. What you should consider doing instead is store all the paths in a single array variable and then test and manipulate each path as needed one at a time via a foreach loop. So it would look more like this:
$Paths = "C:\Users\mathill\Desktop\Outages\Excel-Advanzia-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-AIB-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-American-Express-Corp-Srvcs-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Amex-Central-Europe-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Arcot-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-B+S-Card-Service $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Bank-of-America-Asia-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Bank-of-America-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Barclays-Commercial-Card-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-BOI-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-C-Card-S-p-A-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-CCUK Finance-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-CMC-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-COBE-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Degussa-Bank-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Deutsche-Bank-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Elavon-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Home-Retail-Group-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-IE-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-ING-CPS-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-JPMC-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-KBC-Bank-Ireland-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Lloyds-TSB-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Metro-Bank-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-NBS-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-PayPal-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Prime-Carrefour-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-PTSB-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Rabo-Bank-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-RBSG-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-RSA-Cyota-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Swisscard-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Telrock-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Tesco-Bank-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-TSYS-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Virgin-Money-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-Wells-Fargo-Outages $a.xls","C:\Users\mathill\Desktop\Outages\Excel-WEX-Outages $a.xls") -eq $true)
Foreach ($Path in $Paths)
{
#skips to next item in array if path not found (continue)
If (! (Test-path $Path))
{Continue}
#rest of code goes here
}
Alternatively if a requirement here is that all 38 paths exist before continuing you could confirm that like this:
$Tests = test-path 'c:','c:\windows','c:\dontexist'
If ($Tests -contains $False)
{'path missing';return}