StaffCalendar.psm1
#Region '.\Public\Get-ExcelColorIndexValue.ps1' -1 function Get-ExcelColorIndexValue { <# .SYNOPSIS Converts RGB or Hex color values to an Excel color index value. .DESCRIPTION The Get-ExcelColorIndexValue function calculates the Excel color index value from either RGB or Hex color values. This value can be used to set the color of cells in Excel. .PARAMETER red The red component of the RGB color value (0-255). Mandatory in the RGB parameter set. .PARAMETER green The green component of the RGB color value (0-255). Mandatory in the RGB parameter set. .PARAMETER blue The blue component of the RGB color value (0-255). Mandatory in the RGB parameter set. .PARAMETER hexColor The hex color value (e.g., "#FF0000"). Mandatory in the Hex parameter set. .EXAMPLE PS C:\> Get-ExcelColorIndexValue -red 255 -green 0 -blue 0 255 This example converts the RGB color values (255, 0, 0) to an Excel color index value. .EXAMPLE PS C:\> Get-ExcelColorIndexValue 231 230 230 15132391 This example converts the RGB color values (231, 230, 230) to an Excel color index value. .EXAMPLE PS C:\> Get-ExcelColorIndexValue -hexColor "#00FF00" 65280 This example converts the hex color value ("#00FF00") to an Excel color index value. .NOTES This function uses the Excel color index formula, which combines RGB values into a single integer. .LINK https://github.com/bordwalk2000/StaffCalendar #> [CmdletBinding( DefaultParameterSetName = "RGB" )] param ( [Parameter( ParameterSetName = "RGB", Mandatory, Position = 0 )] [int] $red, [Parameter( ParameterSetName = "RGB", Mandatory, Position = 1 )] [int] $green, [Parameter( ParameterSetName = "RGB", Mandatory, Position = 2 )] [int] $blue, [Parameter( ParameterSetName = "Hex", Mandatory )] [string] $hexColor ) if ($PSCmdlet.ParameterSetName -eq "Hex") { # Remove '#' from hexColor string $hexColor = $hexColor -replace '#', '' # Convert hex to RGB values $red = [Convert]::ToInt32($hexColor.Substring(0, 2), 16) $green = [Convert]::ToInt32($hexColor.Substring(2, 2), 16) $blue = [Convert]::ToInt32($hexColor.Substring(4, 2), 16) } # Calculate the color index for the RGB values return $blue * 65536 + $green * 256 + $red } #EndRegion '.\Public\Get-ExcelColorIndexValue.ps1' 97 #Region '.\Public\New-StaffCalendar.ps1' -1 <# .SYNOPSIS Creates a staff calendar for a specified year, either from a list of users with the same work hours or from a CSV file. .DESCRIPTION This function generates a staff calendar in Excel format for a given year. It can accept a list of users with default work hours or import users from a CSV file. The resulting calendar includes workdays, user names, and their respective work hours. Various parameters allow customization of the Excel file, including the file name, worksheet title, and zoom level. .PARAMETER year Specifies the calendar year to create. .PARAMETER users Specifies the list of users to be added to the calendar. This parameter is mandatory when using the "users" parameter set. .PARAMETER defaultUserHours Specifies the work hours to be used for all manually specified users. The default value is "8-5". This parameter is in the "users" parameter set. .PARAMETER csvPath Specifies the CSV file path to import user data. The CSV requires a header row of "Name" and "WorkHours". This parameter is mandatory when using the "csv" parameter set. .PARAMETER excelFileName Specifies the filename of the created Excel file. The default value is "$year Staff Schedule". .PARAMETER worksheetTitleRow Specifies the worksheet title string that will be followed by the month name. The default value is "Staff Calendar". .PARAMETER firstColumnWidth Specifies the width of the "A" column. The default value is 13. .PARAMETER worksheetZoomLevel Specifies the zoom level for each sheet. The default value is 100. .EXAMPLE PS C:\> New-StaffCalendar -year 1997 -users "Jack O", "Sam C", "Daniel J" -defaultUserHours "9-5" Creates a staff calendar for the year 1997 with specified users and default work hours from 9 to 5. .EXAMPLE PS C:\> New-StaffCalendar -year 2266 -csvPath .\csv_example\staff.csv Creates a staff calendar for the year 2266 using user data imported from the specified CSV file. .NOTES This function requires Excel to be installed on the system as it interacts with the Excel COM object to generate the calendar. .LINK https://github.com/bordwalk2000/StaffCalendar #> Function New-StaffCalendar { [CmdletBinding( DefaultParameterSetName = "users" )] param ( # Calendar year to create [Parameter( Mandatory, HelpMessage = "Year you want calendar created for." )] [int] $year, # List of users to be added [Parameter( Mandatory, HelpMessage = "List of users to be added.", ParameterSetName = "users" )] [string[]] $users, # The work houses to be used for the users specified. [Parameter( HelpMessage = "The work hours to be used for all the manually specified users.", ParameterSetName = "users" )] [string] $defaultUserHours = "8:00-5:00", # List of users to be added [Parameter( Mandatory, HelpMessage = "CSV Path to get data.", ParameterSetName = "csv" )] [ValidateScript( { Test-Path -Path $_ } )] [System.IO.FileInfo] $csvPath, # Excel file name [Parameter( HelpMessage = "Filename of created excel file." )] [string] $excelFileName = "$year Staff Schedule", # Worksheet title row [Parameter( HelpMessage = "Worksheet title string that will be followed by the month name." )] [string] $worksheetTitleRow = "Staff Calendar", # Column "A" Width [Parameter( HelpMessage = "The width of the of the 'A' column." )] [int] $firstColumnWidth = 13, # Worksheet Zoom Level [Parameter( HelpMessage = "Set the zoom level you would like for each sheet." )] [int] $worksheetZoomLevel = 100, # Specify location where the excel file is going to be saved [Parameter( HelpMessage = "Path Excel file will be saved to." )] [ValidateScript( { Test-Path -Path $_ } )] [string] $saveLocation = $PWD ) # Create userList object if ($PSCmdlet.ParameterSetName -eq "csv") { $userList = Import-Csv $csvPath } elseif ($PSCmdlet.ParameterSetName -eq "users") { # Define userList object $userList = [PSCustomObject]@() # Populate to userList from list of users foreach ($user in $users) { $userList += [PSCustomObject]@{ Name = $user; WorkHours = $defaultUserHours } } } try { # Creates new Excel application $excel = New-Object -ComObject Excel.Application $excel.Visible = $false # Set to true for testing $workbook = $excel.Workbooks.Add() } catch { $Message = "Unable to Create Excel Object. Make sure Excel is installed on current computer. $_" Write-Error -Message $Message -ErrorAction Stop } # Get the list of month names and abbreviated month names $monthNameList = (Get-Culture).DateTimeFormat.MonthNames $abbreviatedMonthNameList = (Get-Culture).DateTimeFormat.AbbreviatedMonthNames # Initialize an array to hold the custom objects $months = @() # Loop through the month names and create a custom object for each month for ($i = 0; $i -lt $monthNameList.Length; $i++) { if ($monthNameList[$i] -ne "") { $month = [PSCustomObject]@{ MonthNumber = $i + 1 # Month number (1-based index) MonthName = $monthNameList[$i] AbbreviatedName = $AbbreviatedMonthNameList[$i] } $months += $month } } foreach ($month in $months) { # Define progress bar params $progressParams = @{ Activity = "Creating Calendar" Status = "Processing $($month.MonthName)" PercentComplete = ((100 / 12) * $month.MonthNumber) } # Create progress bar Write-Progress @progressParams # Add new sheet $worksheet = $workbook.Worksheets.Add( [System.Reflection.Missing]::Value, $workbook.Worksheets.Item($workbook.Worksheets.Count) ) # Rename new sheet to month abbreviated name $worksheet.Name = $month.AbbreviatedName # Set zoom level if ($worksheetZoomLevel -ne 100) { $excel.ActiveWindow.Zoom = $worksheetZoomLevel } # Set column widths $worksheet.Columns.Item("A").ColumnWidth = $firstColumnWidth $worksheet.Columns.Item("B").ColumnWidth = 11.5 $worksheet.Columns.Item("C").ColumnWidth = 11.5 $worksheet.Columns.Item("D").ColumnWidth = 11.5 $worksheet.Columns.Item("E").ColumnWidth = 11.5 $worksheet.Columns.Item("F").ColumnWidth = 11.5 $worksheet.Columns.Item("G").ColumnWidth = 2 # Calculate the first and last day of the month $firstDayOfMonth = Get-Date -Year $year -Month $month.MonthNumber -Day 1 $lastDayOfMonth = $firstDayOfMonth.AddMonths(1).AddDays(-1) # Initialize an array to hold the workdays $workdays = @() # Loop through each day of the month $currentDay = $firstDayOfMonth while ($currentDay -le $lastDayOfMonth) { # Check if the current day is a weekday (Monday to Friday) if ($currentDay.DayOfWeek -ne 'Saturday' -and $currentDay.DayOfWeek -ne 'Sunday') { $workdays += $currentDay } # Move to the next day $currentDay = $currentDay.AddDays(1) } # Group the workdays by week $weeks = @() $currentWeek = @() $lastWeekNumber = $null foreach ($day in $workdays) { $weekNumber = [System.Globalization.CultureInfo]::CurrentCulture.Calendar.GetWeekOfYear( $day, [System.Globalization.CalendarWeekRule]::FirstDay, [System.DayOfWeek]::Monday ) if ($weekNumber -ne $lastWeekNumber) { if ($currentWeek.Count -gt 0) { $weeks += , @($currentWeek) $currentWeek = @() } $lastWeekNumber = $weekNumber } $currentWeek += $day } if ($currentWeek.Count -gt 0) { $weeks += , @($currentWeek) } # Define title cell settings $worksheet.Cells.Item(1, 2).Value2 = "$worksheetTitleRow - $($month.MonthName)" $worksheet.Cells.Item(1, 2).Font.Size = 22 $worksheet.Cells.Item(1, 2).Font.Bold = $true # Merge and center title cells (B through F) $range = $worksheet.Range("B1:F1") $range.Merge() $range.HorizontalAlignment = -4108 # Center horizontally (xlCenter) $range.VerticalAlignment = -4108 # Center vertically (xlCenter) # Write the weeks to the Excel worksheet starting at row 4 $row = 4 foreach ($week in $weeks) { # Define week name and date range $dateCellRange = $worksheet.Range("B$($row-1):F$($row)") # Set background color to RGB (231,230,230) or #E7E6E6 $dateCellRange.Interior.Color = 15132391 # Add borders to the range with xlContinuous $dateCellRange.Borders.LineStyle = 1 # Insert users rows $userRowCount = $row + 1 foreach ($user in $userList) { $worksheet.Cells.Item(($userRowCount), (1)) = $user.Name # Set borders around all users data cells $worksheet.Range( $worksheet.Cells.Item($userRowCount, 1), $worksheet.Cells.Item($userRowCount, 6) ).Borders.LineStyle = 1 $worksheet.Cells.Item(($userRowCount++), (1)).Font.Bold = $true } # Date data starts at cell B $col = 2 # Insert Day Data foreach ($day in $week) { # Move start of month cell to the correct location if ( # Check if it's the first week of the month [bool]( Compare-Object -ReferenceObject $weeks[0] -DifferenceObject $week -ExcludeDifferent -IncludeEqual ) -and ( #Check if it's the first workday of the month $day -eq $week[0] ) ) { # If both checks are true then move the starting cell over the day of the week -1. $col = $col + $day.DayOfWeek.value__ - 1 } # Set work day cell $weekDayCell = $worksheet.Cells.Item(($row - 1), $col) $weekDayCell.Value2 = $day.DayOfWeek.ToString() $weekDayCell.Font.Bold = $true $weekDayCell.HorizontalAlignment = -4108 # -4108 corresponds to center alignment # Set date cell $dateCell = $worksheet.Cells.Item($row, $col) $dateCell.Value2 = $day.ToString("yyyy-MM-dd") $dateCell.Font.Bold = $true $dateCell.HorizontalAlignment = -4108 # -4108 corresponds to center alignment # Add work hours for each user $hourRowCount = $row + 1 foreach ($user in $userList) { # Set hour cell $hoursCell = $worksheet.Cells.Item($hourRowCount, $col) $hoursCell.NumberFormat = "@" # "@" symbol is the cell format code for text $hoursCell.Value2 = $user.WorkHours # Increase hour row count $hourRowCount++ } # Increase column count $col++ } $row = $row + $userList.Count + 3 } # Set Font for the Sheet $worksheet.UsedRange.Font.Name = "Calibri" } # Complete the progress bar Write-Progress -Completed -Activity "Creating Calendar" # Delete worksheet named Sheet1 $workbook.Worksheets.Item("Sheet1").Delete() # Set Jan cell to tbe the active one $workbook.Worksheets.Item("Jan").Activate() # Define where the file wil be saved $excelFile = "$saveLocation\$excelFileName.xlsx" # Remove existing file Remove-Item -Path $excelFile -ErrorAction SilentlyContinue # Save the Excel file $workbook.SaveAs($excelFile) # Excel clean up $workbook.Close($false) $excel.Quit() [System.Runtime.Interopservices.Marshal]::ReleaseComObject($worksheet) | Out-Null [System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook) | Out-Null [System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null [GC]::Collect() [GC]::WaitForPendingFinalizers() Write-Output "Excel file created: $excelFile" } #EndRegion '.\Public\New-StaffCalendar.ps1' 375 |