Powershell script suddenly failing - powershell

We have a script running daily on two separate servers, there have been no changes made to either copy of the script all year. Last weekend, there was a server outage that interrupted the script running on one of the servers, and ever since the script on that server partially fails each day.
Here is the code which continues to fail, I have broken it out and ran it locally without issue.
$rawlineCountFile ="C:\temp\files\test\linecount"
$rawlineCountFile = $rawlineCountFile +'RawlineCount' + 'test' + '.csv'
$filePath = "C:\temp\files\test"
# do line count in files
$bak = Get-ChildItem $filePath | Where-Object { $_.Extension -eq ".dat" }
Try
{
Write-Output "line_count , file_name"
foreach ($file in $bak) {
$name = $file.name
$measure =(Get-Content $filePath\$file | Measure-Object)
$lines = $measure.Count
Write-Output "$lines , $name"
Write-Output "$lines , $name" >> $rawlineCountFile
}
} catch [Exception] {
Write-Output $_.Exception.GetType().FullName
Write-Output $_.Exception.Message
}
This script above looks at a folder with .dat files and FOR EACH one, it writes the $lines within each file ($measure.count) and the $file.name into a rawlinecountfile.csv.
i.e.
123 , file1.dat
234 , file2.dat
987 , file3.dat
567 , file4.dat
etc. etc.
Each day there are 7 files moved into this folder, then this script runs, so there should be 7 rows added to the rawlinecountfile each day also, then later, after the rest of the process finishes, all the files are cleared out to prepare for the next day.
However, since the outage last week, it only writes 0-2 out of 7 rows onto the csv file each day, not FOR EACH file (still 7).
We are stumped as to why the For Each doesn't seem to be working anymore, while the script has not been changed and the same exact script still runs as expected on the sister server, and on my local machine.
Any thoughts?

When you were calling Get-Content, I believe you are trying to get the file from C:\Temp\Files\Test\C:\Temp\Files\Test\Filename.dat. You can use $file.FullName to get the full path. I suspect it was probably throwing an error and not adding the content to the file. This worked in PS 5.1.
$rawlineCountFile ="C:\temp\files\test\linecount"
$rawlineCountFile = $rawlineCountFile +'RawlineCount' + 'test' + '.csv'
$filePath = "C:\temp\files\test"
# do line count in files
$bak = Get-ChildItem $filePath | Where-Object { $_.Extension -eq ".dat" }
Try
{
Write-Output "line_count , file_name"
foreach ($file in $bak)
{
$name = $file.name
$lines = #(Get-Content -Path $File.FullName).Count
Write-Output "$lines , $name"
"$lines , $name" | Add-Content $rawlineCountFile
}
}
catch [Exception]
{
Write-Output $_.Exception.GetType().FullName
Write-Output $_.Exception.Message
}
Replacing just the single line I mentioned that could be an issue:
$rawlineCountFile ="C:\temp\files\test\linecount"
$rawlineCountFile = $rawlineCountFile +'RawlineCount' + 'test' + '.csv'
$filePath = "C:\temp\files\test"
# do line count in files
$bak = Get-ChildItem $filePath | Where-Object { $_.Extension -eq ".dat" }
Try
{
Write-Output "line_count , file_name"
foreach ($file in $bak) {
$name = $file.name
$measure =(Get-Content $file.FullName | Measure-Object)
$lines = $measure.Count
Write-Output "$lines , $name"
Write-Output "$lines , $name" >> $rawlineCountFile
}
} catch [Exception] {
Write-Output $_.Exception.GetType().FullName
Write-Output $_.Exception.Message
}

Related

Powershell Throw Causing Variables to Clear?

My PowerShell script just checks multiple servers to make sure the input* and output* directories are clear of any files.
I'm simply trying to output to console the results of a GCI call prior to throwing an error message. However, when I uncomment the "throw" line, the $inputFiles and $outputFiles no longer output to the console. Below is the code:
$allServers = #(
"server1.com",
"server2.com")
foreach ($server in $allServers) {
$inputFiles = Get-ChildItem -Path "\\$server\C$\jobs\statements\input*\" -Recurse | Where-Object {! $_.PSIsContainer } | Select FullName
$outputFiles = Get-ChildItem -Path "\\$server\C$\jobs\statements\output*\" -Recurse | Where-Object {! $_.PSIsContainer } | Select FullName
if ($inputFiles -eq $NULL -and $outputFiles -eq $NULL) {
Write-Host "Environment is ready for statement processing."
}
else {
Write-Host "Environment is NOT ready for statement processing."
Write-Host "The following files exist in input/output: `n"
$inputFiles
$outputFiles
#Throw "Files exist in input/output. See above for details."
}
}
Below is the console output:
Environment is NOT ready for statement processing.
The following files exist in input/output:
Environment is NOT ready for statement processing.
The following files exist in input/output:
FullName
--------
\\server1.com\C$\jobs\statements\input\asdasd.txt
\\server1.com\C$\jobs\statements\input_254\asdasd.txt
\\server1.com\C$\jobs\statements\input_test\asdasd.txt
\\server2.com\C$\jobs\statements\input\CUSSTAT10302021.245
\\server2.com\C$\jobs\statements\input\CUSSTAT11312021
\\server2.com\C$\jobs\statements\input\CUSSTAT11312021.zip
And below is the console output when I uncomment the "throw" line:
Environment is NOT ready for statement processing.
The following files exist in input/output:
Files exist in input/output. See above for details.
At C:\jobs\statements\bin\Statements-EnvironmentCheck.ps1:47 char:9
+ Throw "Files exist in input/output. See above for details."
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Files exist in ...ve for details.:String) [], RuntimeException
+ FullyQualifiedErrorId : Files exist in input/output. See above for details.
I know I have some error output cleanup to perform in order to include all the servers that might have files present, but please ignore that for now.
What you're experiencing is explained in this answer and this answer, basically you need to implement Out-Host \ Out-Default:
$inputFiles, $outputFiles | Out-Host # Should fix the problem
# possibly `throw` might require this too
throw "Files exist in input/output. See above for details." | Out-Host
However, I feel is worth showing you a better way to approach your code, returning a unified array of objects which you can filter, sort and export.
$allServers = #(
"server1.com"
"server2.com"
)
$result = foreach ($server in $allServers) {
# use `-File` instead of `! $_.PSIsContainer`
$out = #{
in = Get-ChildItem "\\$server\C$\jobs\statements\input*\" -Recurse -File
out = Get-ChildItem "\\$server\C$\jobs\statements\output*\" -Recurse -File
}
# if $out['in'] and $out['out'] are `$null`, Ready is `$true`
[pscustomobject]#{
Ready = -not($out['in'] -or $out['out'])
Server = $server
Files = $out
}
}
Now, if you want to see which servers are Ready (no files in input and output):
$result.where{ $_.Ready }
And if you want to see which servers are not Ready, and have a list of the files:
$result.where{ -not $_.Ready }.foreach{
foreach($file in $_.Files.PSBase.Values.FullName) {
[pscustomobject]#{
Server = $_.Server
Files = $file
}
}
}

Powershell output formatting?

I have a script that scans for a specific folder in users AppData folder. If it finds the folder, it then returns the path to a txt file. So we can see the computer name and username where it was found.
I would like to be able to format the what is actually written to the text file, so it removes everything from the path except the Computer and User names.
Script:
foreach($computer in $computers){
$BetterNet = "\\$computer\c$\users\*\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm"
Get-ChildItem $BetterNet | ForEach-Object {
$count++
$betternetCount++
write-host BetterNet found on: $computer
Add-Content "\\SERVERNAME\PowershellScans\$date\$time\BetterNet.txt" $_`n
write-host
}
}
The text files contain information like this
\\computer-11-1004S10\c$\users\turtle\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm
\\computer-1004-24S\c$\users\camel\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm
\\computer-1004-23S\c$\users\rabbit\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm
If you have each line in a form of the string $string_containing_path then it is easy to split using split method and then add index(1) and (4) that you need:
$afterSplit = $string_containing_path.Split('\')
$stringThatYouNeed = $afterSplit[1] + " " + $afterSplit[4]
You can also use simple script that will fix your current logs:
$path_in = "C:\temp\list.txt"
$path_out= "C:\temp\output.txt"
$reader = [System.IO.File]::OpenText($path_in)
try {
while($true){
$line = $reader.ReadLine()
if ($line -eq $null) { break }
$line_after_split_method = $line.Split('\')
$stringToOutput = $line_after_split_method[1] + " " + $line_after_split_method[4] + "`r`n"
add-content $path_out $stringToOutput
}
add-content $path_out "End"
}
finally {
$reader.Close()
}
If you split your loop into two foreach loops, one for computer and user directory it would be easier to output the name of the user directory.
$output = foreach($computer in $computers){
$UserDirectories = Get-ChildItem "\\$computer\c$\users\" -Directory
foreach ($Directory in $UserDirectories) {
$BetterNet = Get-ChildItem (Join-Path $Directory.fullname "\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm")
Add-Content "\\SERVERNAME\PowershellScans\$date\$time\BetterNet.txt" "$computer $($Directory.name)`r`n"
write-host BetterNet found on: $computer
$BetterNet
}
}
$output.count

How to parse and delete archived event logs in Powershell

I'm trying to parse archived Security logs to track down an issue with changing permissions. This script greps through .evtx files that are +10 days old. It currently outputs what I want, but when it goes to clean up the old logs (About 50GB/daily, uncompressed, each of which are archived into their own daily folder via another script that runs at midnight) it begins complaining that the logs are in use and cannot be deleted. The process that seems to be in use when I try to delete the files through Explorer is alternately DHCP Client or Event Viewer, stopping both of these services works, but clearly I can't run without eventvwr. DHCP client is used for networking niceness but is not needed.
The only thing that touches the .evtx files is this script, they're not backed up, they're not monitored by anything else, they're not automatically parsed by the Event Log service, they're just stored on disk waiting.
The script originally deleted things as it went, but then since that failed all the deletions were moved to the end, then to the KillLogWithFire() function. Even the timer doesn't seem to help. I've also tried moving the files to a Processed subfolder, but that does't work for the same reason.
I assume that there's some way to release any handles that this script opens on any files, but attempting to .close() or .dispose() of the EventLog variable in the loop doesn't work.
$XPath = #'
*[System[Provider/#Name='Microsoft-Windows-Security-Auditing']]
and
*[System/EventID=4670]
'#
$DeletableLogs = #()
$logfile = "L:\PermChanges.txt"
$AdminUsers = ("List","of","Admin","Users")
$today = Get-Date
$marker = "
-------------
$today
-------------
"
write-output $marker >> $logfile
Function KillLogWithFire($log){
Try {
remove-item $log
}
Catch [writeerror]{
$Timer += 1
sleep $timer
write-output "Killing log $log in $timer seconds"
KillLogWithFire($log)
}
}
Function LogPermissionChange($PermChanges){
ForEach($PermChange in $PermChanges){
$Change = #{}
$Change.ChangedBy = $PermChange.properties[1].value.tostring()
#Filter out normal non-admin users
if ($AdminUsers -notcontains $Change.ChangedBy){continue}
$Change.FileChanged = $PermChange.properties[6].value.tostring()
#Ignore temporary files
if ($Change.FileChanged.EndsWith(".tmp")){continue}
elseif ($Change.FileChanged.EndsWith(".partial")){continue}
$Change.MadeOn = $PermChange.TimeCreated.tostring()
$Change.OriginalPermissions = $PermChange.properties[8].value.tostring()
$Change.NewPermissions = $PermChange.properties[9].value.tostring()
write-output "{" >> $logfile
write-output ("Changed By : "+ $Change.ChangedBy) >> $logfile
write-output ("File Changed : "+ $Change.FileChanged) >> $logfile
write-output ("Change Made : "+ $Change.MadeOn) >> $logfile
write-output ("Original Permissions :
"+ $Change.OriginalPermissions) >> $logfile
write-output ("New Permissions :
"+ $Change.NewPermissions) >> $logfile
"}
" >> $logfile
}
}
GCI -include Archive-Security*.evtx -path L:\Security\$Today.AddDays(-10) -recurse | ForEach-Object{
Try{
$PermChanges = Get-WinEvent -Path $_ -FilterXPath $XPath -ErrorAction Stop
}
Catch [Exception]{
if ($_.Exception -match "No events were found that match the specified selection criteria."){
}
else {
Throw $_
}
}
LogPermissionChange($PermChanges)
$PermChanges = $Null
$DeletableLogs += $_
}
foreach ($log in $DeletableLogs){
$Timer = 0
Try{
remove-item $log
}
Catch [IOException]{
KillLogWithFire($log)
}
}
UPDATE
Rather than editing the original code as I've been told not to do, I wanted to post the full code that's now in use as a separate answer. The Initial part, which parses the logs and is run every 30 minutes is mostly the same as above:
$XPath = #'
*[System[Provider/#Name='Microsoft-Windows-Security-Auditing']]
and
*[System/EventID=4670]
'#
$DeletableLogs = #()
$logfile = "L:\PermChanges.txt"
$DeleteList = "L:\DeletableLogs.txt"
$AdminUsers = ("List","Of","Admins")
$today = Get-Date
$marker = "
-------------
$today
-------------
"
write-output $marker >> $logfile
Function LogPermissionChange($PermChanges){
ForEach($PermChange in $PermChanges){
$Change = #{}
$Change.ChangedBy = $PermChange.properties[1].value.tostring()
#Filter out normal non-admin users
if ($AdminUsers -notcontains $Change.ChangedBy){continue}
$Change.FileChanged = $PermChange.properties[6].value.tostring()
#Ignore temporary files
if ($Change.FileChanged.EndsWith(".tmp")){continue}
elseif ($Change.FileChanged.EndsWith(".partial")){continue}
$Change.MadeOn = $PermChange.TimeCreated.tostring()
$Change.OriginalPermissions = $PermChange.properties[8].value.tostring()
$Change.NewPermissions = $PermChange.properties[9].value.tostring()
write-output "{" >> $logfile
write-output ("Changed By : "+ $Change.ChangedBy) >> $logfile
write-output ("File Changed : "+ $Change.FileChanged) >> $logfile
write-output ("Change Made : "+ $Change.MadeOn) >> $logfile
write-output ("Original Permissions :
"+ $Change.OriginalPermissions) >> $logfile
write-output ("New Permissions :
"+ $Change.NewPermissions) >> $logfile
"}
" >> $logfile
}
}
GCI -include Archive-Security*.evtx -path L:\Security\ -recurse | ForEach-Object{
Try{
$PermChanges = Get-WinEvent -Path $_ -FilterXPath $XPath -ErrorAction Stop
}
Catch [Exception]{
if ($_.Exception -match "No events were found that match the specified selection criteria."){
}
else {
Throw $_
}
}
LogPermissionChange($PermChanges)
$PermChanges = $Null
$DeletableLogs += $_
}
foreach ($log in $DeletableLogs){
write-output $log.FullName >> $DeleteList
}
The second portion does the deletion, including the helper function above graciously provided by TheMadTechnician. The code still loops as the straight delete is faster than the function, but not always successful even ages after the files have not been touched.:
# Log Cleanup script. Works around open log issues caused by PS parsing of
# saved logs in EventLogParser.ps1
$DeleteList = "L:\DeletableLogs.txt"
$DeletableLogs = get-content $DeleteList
Function Close-LockedFile{
Param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)][String[]]$Filename
)
Begin{
$HandleApp = 'C:\sysinternals\Handle.exe'
If(!(Test-Path $HandleApp)){Write-Host "Handle.exe not found at $HandleApp`nPlease download it from www.sysinternals.com and save it in the afore mentioned location.";break}
}
Process{
$HandleOut = Invoke-Expression ($HandleApp+' '+$Filename)
$Locks = $HandleOut |?{$_ -match "(.+?)\s+pid: (\d+?)\s+type: File\s+(\w+?): (.+)\s*$"}|%{
[PSCustomObject]#{
'AppName' = $Matches[1]
'PID' = $Matches[2]
'FileHandle' = $Matches[3]
'FilePath' = $Matches[4]
}
}
ForEach($Lock in $Locks){
Invoke-Expression ($HandleApp + " -p " + $Lock.PID + " -c " + $Lock.FileHandle + " -y") | Out-Null
If ( ! $LastexitCode ) { "Successfully closed " + $Lock.AppName + "'s lock on " + $Lock.FilePath}
}
}
}
Function KillLogWithFire($log){
Try {
Close-LockedFile $Log -
}
Catch [System.IO.IOException]{
$Timer += 1
sleep $timer
write-host "Killing $Log in $Timer seconds with fire."
KillLogWithFire($Log)
}
}
foreach ($log in $DeletableLogs){
Try {
remove-item $log -ErrorAction Stop
}
Catch [System.IO.IOException]{
$Timer = 0
KillLogWithFire($Log)
}
}
remove-item $DeleteList
One solution would be to get HANDLE.EXE and use it to close any open handles. Here's a function that I use roughly based off of this script. It uses handle.exe, finds what has a file locked, and then closes handles locking that file open.
Function Close-LockedFile{
Param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)][String[]]$Filename
)
Begin{
$HandleApp = 'C:\sysinternals\Handle.exe'
If(!(Test-Path $HandleApp)){Write-Host "Handle.exe not found at $HandleApp`nPlease download it from www.sysinternals.com and save it in the afore mentioned location.";break}
}
Process{
$HandleOut = Invoke-Expression ($HandleApp+' '+$Filename)
$Locks = $HandleOut |?{$_ -match "(.+?)\s+pid: (\d+?)\s+type: File\s+(\w+?): (.+)\s*$"}|%{
[PSCustomObject]#{
'AppName' = $Matches[1]
'PID' = $Matches[2]
'FileHandle' = $Matches[3]
'FilePath' = $Matches[4]
}
}
ForEach($Lock in $Locks){
Invoke-Expression ($HandleApp + " -p " + $Lock.PID + " -c " + $Lock.FileHandle + " -y") | Out-Null
If ( ! $LastexitCode ) { "Successfully closed " + $Lock.AppName + "'s lock on " + $Lock.FilePath}
}
}
}
I have handle.exe saved in C:\Sysinternals, you may want to adjust the path in the function, or save the executable there.
I was having a very similar problem and after lots of searching found this article. Whilst handle.exe worked when I first tried I did note the -c carries a warning "Closing handles can cause application or system instability"
I am also using get-winevent and it seems to (sometimes) lock the .evtx file being processed. I have written a loop to wait 5 secs an retry. Sometimes it takes up to 2 minutes or the file to be released, I have had one run overnight and it had hundreds of retries.
When I used handle the first time it worked perfectly. I then implemented it into the script and later found it to be looping an "unexplained error". I ended up having to reboot the server to get things working again so removed the handle.exe from the script and back to waiting for the file to be closed.
I can reliably release the file by stopping the script and closing down the powershell ise. As soon as the ISE is closed the file can be deleted without a problem.
Unfortunately I need this script to keep running and not be held up by the file remaining open. I am surprised that have to resort to sysinternals to release the file and that powershell does not offer an easy way to close the file.
I had the same issue as GTEM where closing the handles would cause corruption when processing hundreds of event log files. Eventually Get-WinEvent would not work properly. It would either freeze or give me the same "unexplained error".
So I opened a premier case with MS. They lead me to the actual variable I was storing the Get-WinEvent events in was what was locking the file. I guess it doesn't actually unlock the file if you are still using that variable. So to resolve this I added some code to my script after I transferred the variable to a new variable. You can see the code I added in the 3rd region listed below.
#***************************************************************************
#region *** Get the log entries.
# clear the log entry for each pass
$LogEntry = #()
# Get the vent from the log file and export it to the logentry variable and output to the screen
Get-WinEvent -Path $NewPath -FilterXPath $XPathFilter -ErrorAction SilentlyContinue | Tee-Object -Variable LogEntry
#endregion *** End get the log entries
#***************************************************************************
#***************************************************************************
#region *** This is where I copy it to the new variable for later output.
# if there are any log entries
if ($LogEntry.Count -gt 0) {
# Add the log entries to the log file
$LogEntries += $LogEntry
} # if there are any log entries
#endregion *** End were I copy to the new variable.
#***************************************************************************
#***************************************************************************
#region *** This is where I added code to allow me to remove the file lock.
# Remove the variable to release the evtx file lock
Remove-Variable -Name LogEntry
# Garbage collect to remove any additional memory tied to the file lock.
[GC]::Collect()
# sleep for 1 seconds
Sleep -Seconds 1
#endregion **** Code to remove the file lock.
#***************************************************************************
After this was done, I no longer have to use Handle.exe to close the file anymore.

Get-Content - Get all Content, starting from a specific linenumber

My first question here, and just want to say thanks for all the input I've gotten over the years from this site.
I'm also new to powershell so the answar might be very simple.
I'm working on a Script that ment check a log file every 5 mins. (schedulded from ActiveBatch).
At the moment the script is searching for ERROR in a logfile. And it works fine.
But my problem is that the script searches the entire file throgh every time. So when an ERROR do occur, the check "fails" every 5 minutes the rest of the day. Untill a new logfile is generated.
My script:
Write-Host Opretter variabler...
$file = "${file}"
$errorString = "${errorString}"
Write-Host file variable is: $file
Write-Host errorString variable is: $errorString
Write-Host
Write-Host Select String Results:
$ssResult = Get-Content $file | Select-String $errorString -SimpleMatch
Write-Host
Write-Host There was $ssResult.Count `"$errorString`" statements found...
Write-Host
IF ($ssResult.Count -gt 0) {Exit $ssResult.Count}
So what i would like, is to Find the ERROR, and then Remeber the Linenumber (Perhaps in a file). Then in the next run (5minutes later) i want to start the search from that line.
for example. And error is found on line 142, the Script exits with error code 142. five minutes later the script is run again, and it should start from line 143, and go through the rest of the file.
You can remember number of error strings found in file:
$ssResult.Count > C:\path\to\file.txt
Then number of new erros is:
$errorCount = $ssResult.Count - (Get-Content C:\path\to\file.txt)
Remember to set the value in file to zero on first run of script and every time a new logfile is generated.
You basically gave a pretty good description of how it will work:
Read the last line number
$if (Test-Path $Env:TEMP\last-line-number.txt) {
[int]$LastLineNumber = #(Get-Content $Env:TEMP\last-line-number.txt)[0]
} else {
$LastLineNumber = 0
}
Read the file
$contents = Get-Content $file
Find the first error starting at $LastLineNumber (one of the rare cases where for is appropriate in PowerShell, lest we want to create nicer objects)
for ($i = $LastLineNumber; $i -lt $contents.Count; $i++) {
if ($contents[$i] -like "*$errorString*") {
$i + 1 > $Env:TEMP\last-line-number.txt
exit ($i + 1)
}
}
Select-String returns matchinfo objects, which have the line number, so you can should be able to do something like this:
$lasterror = Get-Content $lasterrorfile
$newerrors = select-string -Path $file -Pattern $errorstring -SimpleMatch |
where $_.LineNumber -gt $lasterror
Write-Host "$($newerrors.count) found."
if ($newerrors.count)
{$newerrors[-1].LineNumber | Set-Content $lasterrorfile}
So this is my final Script, Thanks Dano. I'm sure the Day-Reset thing can be done smarter, but this seems to work :)
#logic for Day-Reset
Write-Host checking if its a new day...
$today = Get-Date -format dddd
$yesterday = Get-Content $ENV:TEMP\${adapterName}_yesterday.txt
Write-Host today variable is: $today
Write-Host yesterday variable is: $yesterday
Write-Host
IF ($today.CompareTo($yesterday))
{
Get-Date -format dddd > $ENV:TEMP\${adapterName}_yesterday.txt
0 > $ENV:TEMP\${adapterName}_numberofErrors.txt
}
Write-Host Setting variables...
$file = "${file}"
$errorString = "${errorString}"
Write-Host file variable is: $file
Write-Host errorString variable is: $errorString
Write-Host
Write-Host Select String Results:
$ssResult = Get-Content $file | Select-String $errorString -SimpleMatch
Write-Host There was $ssResult.Count `"$errorString`" statements found...
$errorCount = $ssResult.Count - (Get-Content $ENV:TEMP\${adapterName}_numberofErrors.txt)
Write-Host There was $errorCount new `"$errorString`" statements found...
Write-Host
$ssResult.Count > $Env:TEMP\FXAll_numberofErrors.txt
Exit $errorCount

In powershell $x.FullName not returning full path

I have a powershell script below which takes a config file and deletes files older than x days matching a regular expression.
Config File:
path,pattern,days,testrun
C:\logs\,^data_access_listener.log,7,false
However here is what is output:
Would have deleted 000a19f6-a982-4f77-88be-ca9cc51a2bcbuu_data_access_listener.log
Would have deleted 00189746-2d46-4cdd-a5bb-6fed4bee25a7uu_data_access_listener.log
I'm expecting the output to include the full file path since I'm using the .FullName attribute so I'd expect output as such:
Would have deleted C:\logs\000a19f6-a982-4f77-88be-ca9cc51a2bcbuu_data_access_listener.log
Would have deleted C:\logs\00189746-2d46-4cdd-a5bb-6fed4bee25a7uu_data_access_listener.log
If I am using $x.FullName why am I not getting the full name with path (C:\logs)?
Thanks
Brad
$LogFile = "C:\deletefiles.log"
$Config = import-csv -path C:\config.txt
function DeleteFiles ([string]$path, [string]$pattern, [int]$days, [string]$testrun){
$a = Get-ChildItem $path -recurse | where-object {$_.Name -notmatch $pattern}
foreach($x in $a) {
$y = ((Get-Date) - $x.LastWriteTime).Days
if ($y -gt $days -and $x.PsISContainer -ne $True) {
if ($testrun -eq "false") {
write-output “Deleted" $x.FullName >>$LogFile
} else {
write-output “Would have deleted $x” >>$LogFile
}
}
}
}
foreach ($line in $Config) {
$path = $line.path
$pattern = $line.pattern
$days = $line.days
$testrun = $line.testrun
DeleteFiles $path $pattern $days
}
Looks like a typo. You are not using FullName in the condition that leads to "Would have Deleted". Change:
write-output “Would have deleted $x” >>$LogFile
to:
write-output “Would have deleted " $x.FullName >>$LogFile
To answer your comment, if you want to call a property on a variable that is expanded in the string, you have to surround it in $(), so that the parser knows to invoke the whole expression. Like this:
write-output “Would have deleted $($x.FullName)" >>$LogFile