Link to home
Start Free TrialLog in
Avatar of Pra007 V
Pra007 V

asked on

Power shell script runs successfully but defined function will not effect

Hi,

I am trying below script for removal of files from our local setup basing on the retention policy.
I am able to run the script manually as well as using task manager return code is 0. But actual deletion of the files is not happening.
I am using SYSTEM user with full control to run the script . I bypassed the policies still it is not giving me the wanted result.

Script ::
======
$ErrorActionPreference = "stop"
stop-transcript
start-transcript -path C:\Users\scrptlog.txt
$BaseDirectory = "C:\Users\test"
$Global:RetentionDays = 15
#$Global:OldFiles = @()
#$Global:OldDirectories = @()
$Global:Exceptions = @()
#$Global:NerfMode = $true
$Global:CurrentDate = (get-date)

function EvaluateDirectory
{
      Param
      (
            [parameter(Mandatory=$false, Position=0)][string] $DirectoryPath
      )
      
      #write-host ("Evaluating " + $DirectoryPath)
      
      try
      {
            if (!(Test-Path $DirectoryPath))
            {
                  throw "Directory ($DirectoryPath) does not exist or is inaccessible"
            }
            
            $Children = Get-ChildItem $DirectoryPath -Force
            
            if ($Children -ne $null)
            {
                  foreach ($c in $Children)
                  {
                        $age = $null      #Safety first!
                        $age = $Global:CurrentDate - $c.LastWriteTime
                        if ($c.LastAccessTime -gt $c.LastWriteTime)
                        {
                              $age = $Global:CurrentDate - $c.LastAccessTime
                        }
                        
                        [bool] $isOld = $false
                        if (($age -ne $null) -and ($age.TotalDays -gt $Global:RetentionDays))
                        {
                              $isOld = $true
                        }
                        
                        if ($c.PSIsContainer -eq $true)
                        {
                              $Global:TotalFolders += 1
                              #I am skipping the below two folders removal
                              if (($c.Name -ne "Documentation") -and ($c.Name -ne "X_*"))
                              {
                              #From the below directories files should be removed basing on my retention
                                    EvaluateDirectory $c.FullName
                                    if (($c.Name -ne "From-Customer") -and ($c.Name -ne "To-Customer")) # -and ($isOld -eq $true))
                                          {
                                          $subChildren = Get-ChildItem $c.FullName -Force
                                          if ($subChildren -eq $null)
                                          {
                                                $Global:RemovedFolders += 1
                                                Remove-Item $c.FullName -Force -Confirm:$false
                                          }
                                    }
                              }
                        }
                        else
                        {
                              $Global:TotalFiles += 1
                        
                              if ($isOld -eq $true)
                              {
                                    $Global:RemovedFiles += 1
                                    Remove-Item $c.FullName -Force -Confirm:$false
                              }
                        }
                  }
            }
      }
      catch [Exception]
      {
            $Global:Exceptions += $_
            Write-Host "EXCEPTION:  $($_.Exception.Message)`r`n`tDirectory Path: $DirectoryPath"
      }

      

$Children = Get-ChildItem $BaseDirectory
foreach ($c in $Children | sort-object Name)
{
      if (($c.Name -ne "Documentation") -and ($c.Name -ne "X_*"))
      {
            $Global:TotalFiles = 0
            $Global:RemovedFiles = 0
            $Global:TotalFolders = 0
            $Global:RemovedFolders = 0
            
            EvaluateDirectory $c.FullName
            
            write-host $c.Name
            write-host "`tFiles:  $($Global:TotalFiles) total, $($Global:RemovedFiles) removed"
            write-host "`tFolders:  $($Global:TotalFolders) total, $($Global:RemovedFolders) removed"
      }
}

}
Avatar of Chris Dent
Chris Dent
Flag of United Kingdom of Great Britain and Northern Ireland image

I recommend you use Start-Transcript (with a known path). It's likely something in the script is breaking. An exception thrown within a PS script doesn't translate to a non-zero exit code for a scheduled task. PowerShell.exe worked, even if the script you ran didn't.

Using "exit <number>" in the script as a terminal exit will let you pass error codes back up to the task scheduler.
Start-Transcript is already part of the script ;-).

I don't see you calling the defined function outside of itself. The script does not do anything no matter how you run it, I suppose?
hah missed that huh... good call :)
Avatar of Pra007 V
Pra007 V

ASKER

Hi Experts,

Thank you for the reply, I am new to powershell, Do you want me to include any extra code inside the given script?
Or can I call it from the command prompt or set up it in batch file or windows task manager? Please provide me your suggestions.

Thanks,
Prathibha
Qlemo pointed it out, but it really just looks like the bottom of your script is in the wrong place (within the function).
$ErrorActionPreference = "stop"
stop-transcript
start-transcript -path C:\Users\scrptlog.txt
$BaseDirectory = "C:\Users\test"
$Global:RetentionDays = 15
#$Global:OldFiles = @()
#$Global:OldDirectories = @()
$Global:Exceptions = @()
#$Global:NerfMode = $true
$Global:CurrentDate = (get-date)

function EvaluateDirectory
{
      Param
      (
            [parameter(Mandatory=$false, Position=0)][string] $DirectoryPath
      )
      
      #write-host ("Evaluating " + $DirectoryPath)
      
      try
      {
            if (!(Test-Path $DirectoryPath))
            {
                  throw "Directory ($DirectoryPath) does not exist or is inaccessible"
            }
            
            $Children = Get-ChildItem $DirectoryPath -Force
            
            if ($Children -ne $null)
            {
                  foreach ($c in $Children)
                  {
                        $age = $null      #Safety first!
                        $age = $Global:CurrentDate - $c.LastWriteTime
                        if ($c.LastAccessTime -gt $c.LastWriteTime)
                        {
                              $age = $Global:CurrentDate - $c.LastAccessTime
                        }
                        
                        [bool] $isOld = $false
                        if (($age -ne $null) -and ($age.TotalDays -gt $Global:RetentionDays))
                        {
                              $isOld = $true
                        }
                        
                        if ($c.PSIsContainer -eq $true)
                        {
                              $Global:TotalFolders += 1
                              #I am skipping the below two folders removal
                              if (($c.Name -ne "Documentation") -and ($c.Name -ne "X_*"))
                              {
                              #From the below directories files should be removed basing on my retention
                                    EvaluateDirectory $c.FullName
                                    if (($c.Name -ne "From-Customer") -and ($c.Name -ne "To-Customer")) # -and ($isOld -eq $true))
                                          {
                                          $subChildren = Get-ChildItem $c.FullName -Force
                                          if ($subChildren -eq $null)
                                          {
                                                $Global:RemovedFolders += 1
                                                Remove-Item $c.FullName -Force -Confirm:$false
                                          }
                                    }
                              }
                        }
                        else
                        {
                              $Global:TotalFiles += 1
                        
                              if ($isOld -eq $true)
                              {
                                    $Global:RemovedFiles += 1
                                    Remove-Item $c.FullName -Force -Confirm:$false
                              }
                        }
                  }
            }
      }
      catch [Exception]
      {
            $Global:Exceptions += $_
            Write-Host "EXCEPTION:  $($_.Exception.Message)`r`n`tDirectory Path: $DirectoryPath"
      }
}

$Children = Get-ChildItem $BaseDirectory
foreach ($c in $Children | sort-object Name)
{
      if (($c.Name -ne "Documentation") -and ($c.Name -ne "X_*"))
      {
            $Global:TotalFiles = 0
            $Global:RemovedFiles = 0
            $Global:TotalFolders = 0
            $Global:RemovedFolders = 0
            
            EvaluateDirectory $c.FullName
            
            write-host $c.Name
            write-host "`tFiles:  $($Global:TotalFiles) total, $($Global:RemovedFiles) removed"
            write-host "`tFolders:  $($Global:TotalFolders) total, $($Global:RemovedFolders) removed"
      }
}

Open in new window

Hi Chris,

Do you want me to move the child code before exceptional handling?

Thanks,
Prathibha
Just use the code as posted by Chris, it is complete.
Thank you Chris,Qlemo for your prompt replies and solution provided is working for me :)
Hi Experts,

Could you please let me know if we want to get an email for the completion of the activity to get the log file? and overwrite the existing log file an proceed for next run? How we can take it up?

Thanks,
Prathibha
Please confirm that how I read it is correct:
You want to have the log file overwritten each time, and sent after the job is finished?
If that is correct:
Start-Transcript already overwrites the log file, so nothing to do here.
For emailing the log file, you just add this as last line, with correct addresses of course:
Send-MailMessage -SmtpServer mail.company.com -From me@company.com -To you@company.com -Subject "EvaluateDirectory Report" -Attachments C:\Users\scrptlog.txt

Open in new window

Hi Qlemo,

Thank you for the reply, when I stopped script intermittently and try to re-run it, I am getting below . So I need to manually comment the stop transcript and once task initiates I will be removing the comment.

If my script failed with some reason once I scheduled how to resolve this with out manual intervention?

Stop-Transcript : An error occurred stopping transcription: The console host is not currently transcribing.
At C:\Scripts\cleanup.ps1:2 char:16
+ stop-transcript <<<<
    + CategoryInfo          : InvalidOperation: (:) [Stop-Transcript], PSInvalidOperationException
    + FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.StopTranscriptCommand


Also when I use the given sent mail option, getting below, Do we need to specify any unlocking for the transcript file after cleanup?

Send-MailMessage : The process cannot access the file 'C:\Users\scrptlog.txt' because it is being
used by another process.
Start and stop are in very strange places. Fixed here.
$ErrorActionPreference = "stop"
Start-Transcript -path C:\Users\scrptlog.txt
$BaseDirectory = "C:\Users\test"
$Global:RetentionDays = 15
#$Global:OldFiles = @()
#$Global:OldDirectories = @()
$Global:Exceptions = @()
#$Global:NerfMode = $true
$Global:CurrentDate = (get-date)

function EvaluateDirectory
{
      Param
      (
            [parameter(Mandatory=$false, Position=0)][string] $DirectoryPath
      )
      
      #write-host ("Evaluating " + $DirectoryPath)
      
      try
      {
            if (!(Test-Path $DirectoryPath))
            {
                  throw "Directory ($DirectoryPath) does not exist or is inaccessible"
            }
            
            $Children = Get-ChildItem $DirectoryPath -Force
            
            if ($Children -ne $null)
            {
                  foreach ($c in $Children)
                  {
                        $age = $null      #Safety first!
                        $age = $Global:CurrentDate - $c.LastWriteTime
                        if ($c.LastAccessTime -gt $c.LastWriteTime)
                        {
                              $age = $Global:CurrentDate - $c.LastAccessTime
                        }
                        
                        [bool] $isOld = $false
                        if (($age -ne $null) -and ($age.TotalDays -gt $Global:RetentionDays))
                        {
                              $isOld = $true
                        }
                        
                        if ($c.PSIsContainer -eq $true)
                        {
                              $Global:TotalFolders += 1
                              #I am skipping the below two folders removal
                              if (($c.Name -ne "Documentation") -and ($c.Name -ne "X_*"))
                              {
                              #From the below directories files should be removed basing on my retention
                                    EvaluateDirectory $c.FullName
                                    if (($c.Name -ne "From-Customer") -and ($c.Name -ne "To-Customer")) # -and ($isOld -eq $true))
                                          {
                                          $subChildren = Get-ChildItem $c.FullName -Force
                                          if ($subChildren -eq $null)
                                          {
                                                $Global:RemovedFolders += 1
                                                Remove-Item $c.FullName -Force -Confirm:$false
                                          }
                                    }
                              }
                        }
                        else
                        {
                              $Global:TotalFiles += 1
                        
                              if ($isOld -eq $true)
                              {
                                    $Global:RemovedFiles += 1
                                    Remove-Item $c.FullName -Force -Confirm:$false
                              }
                        }
                  }
            }
      }
      catch [Exception]
      {
            $Global:Exceptions += $_
            Write-Host "EXCEPTION:  $($_.Exception.Message)`r`n`tDirectory Path: $DirectoryPath"
      }
}

$Children = Get-ChildItem $BaseDirectory
foreach ($c in $Children | sort-object Name)
{
      if (($c.Name -ne "Documentation") -and ($c.Name -ne "X_*"))
      {
            $Global:TotalFiles = 0
            $Global:RemovedFiles = 0
            $Global:TotalFolders = 0
            $Global:RemovedFolders = 0
            
            EvaluateDirectory $c.FullName
            
            write-host $c.Name
            write-host "`tFiles:  $($Global:TotalFiles) total, $($Global:RemovedFiles) removed"
            write-host "`tFolders:  $($Global:TotalFolders) total, $($Global:RemovedFolders) removed"
      }
}

Stop-Transcript
Send-MailMessage -SmtpServer mail.company.com -From me@company.com -To you@company.com -Subject "EvaluateDirectory Report" -Attachments C:\Users\scrptlog.txt

Open in new window

Hi Chris,

Really appreciate your efforts, I am very thankful.
Yes script is working with out any issues :)

Thanks,
Prathibha
Hi Chris,

once script executed, I found below result from the log.

Ideally script should skip below two directories.

Don't find any name for directory Documentation in the log but I can see the directory X_test in the output.

if (($c.Name -ne "Documentation") -and ($c.Name -ne "X_*"))

Could you please explain me on this?

Thanks,
Pra
You're using a literal comparison (ne) with a wildcard, it will only skip it if the directory is exactly "X_*". Use the "notlike" operator instead.
$c.Name -notlike "X_*

Open in new window

Sure Chris.
ASKER CERTIFIED SOLUTION
Avatar of Chris Dent
Chris Dent
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you Chris, I am facing some syntactic issues for new script. Old one is working for me in my local.
But I am facing issue while executing it from the Unix based shared folder. SA confirmed me that it has all the 777 permissions.
But I am facing access denied issues for the folders on UNIX based netapp shared folder. Any clue how make it run for the mentioned netapp folder?

Thanks,
Pra
Error while running : Nothing was removed it is just showing the count in log.

EXCEPTION:  Access to the path is denied.
      Directory Path: \\testpath\xxx\      
EXCEPTION:  Access to the path is denied.
      Directory Path: \\testpath\xxx\      Files:  2 total, 2 removed
      Folders:  1 total, 0 removed
**********************