We help IT Professionals succeed at work.

Power shell script runs successfully but defined function will not effect

Pra007 V
Pra007 V asked
on
161 Views
Last Modified: 2017-09-28
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"
      }
}

}
Comment
Watch Question

Chris DentPowerShell Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
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.
Qlemo"Batchelor", Developer and EE Topic Advisor
CERTIFIED EXPERT
Top Expert 2015

Commented:
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?
Chris DentPowerShell Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
hah missed that huh... good call :)

Author

Commented:
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
Chris DentPowerShell Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
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

Author

Commented:
Hi Chris,

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

Thanks,
Prathibha
Qlemo"Batchelor", Developer and EE Topic Advisor
CERTIFIED EXPERT
Top Expert 2015

Commented:
Just use the code as posted by Chris, it is complete.

Author

Commented:
Thank you Chris,Qlemo for your prompt replies and solution provided is working for me :)

Author

Commented:
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
Qlemo"Batchelor", Developer and EE Topic Advisor
CERTIFIED EXPERT
Top Expert 2015

Commented:
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

Author

Commented:
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.
Chris DentPowerShell Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
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

Author

Commented:
Hi Chris,

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

Thanks,
Prathibha

Author

Commented:
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
Chris DentPowerShell Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
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

Author

Commented:
Sure Chris.
PowerShell Developer
CERTIFIED EXPERT
Top Expert 2010
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Author

Commented:
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

Author

Commented:
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
**********************
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.