A couple more useful functions

In addition to the couple of functions from yesterday (creating log files and capturing code execution errors for audit purposes), today I have two more functions that I use to track progress for long running blocks of code where some activity is being performed against a list of items (say gathering mailbox statistics against a captured list of mailboxes) and prompting a user to open a CSV or other text file to use that file within the script.

So the first is the code that will be enabling a progress bar within the code so that it shows on the screen. PowerShell sometimes doesn’t show the progress bar, so there are two items that should be checked to make sure that this is enabled:

  • $ProgressPreference should be set to Continue; and
  • $psStyle.Progress.View should be set to Classic

So the first part of the code sets up the counter that will be used for the progress bar, followed by the code that displays the progress bar based on moving through the loop in the code (this sample is based on the Folder permissions script that was mentioned yesterday). And finally, we increment the counter variable as we complete a run through the loop.

#----- Starting counter for Progress Bar -----#
$i=1

#----- Do the work ---#
ForEach ($Perm in $PermList) {

  #----- Progress Bar Calculations -----#
  $PercentCalc = ($i / ($Permlist | Measure-Object).Count*100)
  $PercentComplete = "{0:N2}" -f $PercentCalc
	
	#----- Generate desired variables as required -----#
	$Mailbox = $userHash.item($Perm.Mailbox)
	$Delegate = $userHash.item($Perm.Accessee)
	$AccesseePartner = $Perm.AccesseePartner
	$Access = $Perm.Rights.Split("{;}")
	$MailboxFolder = $Perm.MailboxFolder
	
	
	#----- Progress Bar Updates -----#
  Write-Progress -Activity "Applying Mailbox Folder Permissions " -status "Granting folder permissions on mailbox $Mailbox" -percentComplete $PercentComplete -CurrentOperation "$PercentComplete% Complete"

  #Do the work here
  
  #----- Adding to counter for each item processed -----#
	$i++
}

This will then show the progress bar as it goes through the loop as shown below:

This also works with multiple progress bars by adding in additional counters in subloops. Here’s the text from the Microsoft page (https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/write-progress?view=powershell-7.4):

for($I = 0; $I -lt 10; $I++ ) {
    $OuterLoopProgressParameters = @{
        Activity         = 'Updating'
        Status           = 'Progress->'
        PercentComplete  = $I * 10
        CurrentOperation = 'OuterLoop'
    }
    Write-Progress @OuterLoopProgressParameters
    for($j = 1; $j -lt 101; $j++ ) {
        $InnerLoopProgressParameters = @{
            ID               = 1
            Activity         = 'Updating'
            Status           = 'Progress'
            PercentComplete  = $j
            CurrentOperation = 'InnerLoop'
        }
        Write-Progress @InnerLoopProgressParameters
        Start-Sleep -Milliseconds 25
    }
}

And this looks like:

And finally, a function that prompts the user for an input file (like a CSV). This is pretty straightforward. The first part of the following code is the function, and the second is how to use it within the script itself along with a check for certain header names if the file is a CSV:

#----- Function - Popup to select CSV Input File -----#
Function Get-FileName($initialDirectory)
{   
	 [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") |
	 Out-Null

	 $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
	 $OpenFileDialog.initialDirectory = $initialDirectory
	 $OpenFileDialog.filter = "All CSV files (*.csv*)| *.csv*"
	 $OpenFileDialog.ShowDialog() | Out-Null
	 $OpenFileDialog.filename

} #end function Get-FileName

#----- This section prompts for the USer List CSV file -----#
#----- Get the current directory -----#
$FilePathCurrent=(Get-Item -Path ".\" -Verbose).FullName #Determine current directory

Write-Host -ForegroundColor yellow "ACTION: Select the User List CSV Input file"
$UserFileName = (Get-FileName -initialDirectory "$FilePathCurrent") #Selects the Userlist file name

$UserList = Import-Csv -Path $UserFileName

$HeaderCheck = $UserList | Get-Member -MemberType NoteProperty
IF ($HeaderCheck.Name -notcontains "DestinationEmail") # Check to make sure the Input File has the correct header
    {
    Write-Host "Input File requires a header column with the name of DestinationEmail" -ForegroundColor Red
    Write-Host "Stopping Script" -ForegroundColor Red
    Break
}
	

That’s it for today, hopefully that helps someone out. I think that’s it for the basic functions that I tend to use within my scripts.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.