PsTimeTracking.psm1
|
#Region './Classes/1.class1.ps1' -1 class Class1 { [string]$Name = 'Class1' Class1() { #default Constructor } [String] ToString() { # Typo "calss" is intentional return ( 'This calss is {0}' -f $this.Name) } } #EndRegion './Classes/1.class1.ps1' 16 #Region './Classes/2.class2.ps1' -1 class Class2 { [string]$Name = 'Class2' Class2() { #default constructor } [String] ToString() { return ( 'This calss is {0}' -f $this.Name) } } #EndRegion './Classes/2.class2.ps1' 15 #Region './Classes/3.class11.ps1' -1 class Class11 : Class1 { [string]$Name = 'Class11' Class11 () { } [String] ToString() { return ( 'This calss is {0}:{1}' -f $this.Name,'class1') } } #EndRegion './Classes/3.class11.ps1' 14 #Region './Classes/4.class12.ps1' -1 class Class12 : Class1 { [string]$Name = 'Class12' Class12 () { } [String] ToString() { return ( 'This calss is {0}:{1}' -f $this.Name,'class1') } } #EndRegion './Classes/4.class12.ps1' 14 #Region './Private/Get-PstConfig.ps1' -1 <# .SYNOPSIS Gets the PsTimeTracking configuration from the JSON file. .DESCRIPTION Internal function that loads the configuration file containing clients and projects. If the file doesn't exist, it creates a default configuration. .EXAMPLE PS> Get-PstConfig Returns the configuration object with all clients and projects. #> function Get-PstConfig { [CmdletBinding()] param() # Cross-platform config folder location if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $folder = Join-Path $env:LOCALAPPDATA 'PstTimeTracker' } else { # Linux/macOS $folder = Join-Path $HOME '.local/share/PstTimeTracker' } $configFile = Join-Path $folder 'config.json' Write-Debug "Config file location: $configFile" if (!(Test-Path $folder)) { New-Item $folder -ItemType Directory | Out-Null } if (!(Test-Path $configFile)) { # Create default configuration $defaultConfig = @{ Clients = @( @{ Name = 'ClientA' Projects = @('Project Alpha', 'Project Beta', 'Support') }, @{ Name = 'ClientB' Projects = @('Website Redesign', 'Database Migration') }, @{ Name = 'MMG - Data' Projects = @('Data Analysis', 'ETL Pipeline', 'Reporting') }, @{ Name = 'MMG - DevOps' Projects = @('CI/CD Setup', 'Infrastructure', 'Monitoring') } ) } $defaultConfig | ConvertTo-Json -Depth 10 | Out-File $configFile -Encoding UTF8 } $config = Get-Content $configFile -Raw | ConvertFrom-Json return $config } #EndRegion './Private/Get-PstConfig.ps1' 64 #Region './Private/Save-PstConfig.ps1' -1 <# .SYNOPSIS Saves the PsTimeTracking configuration to the JSON file. .DESCRIPTION Internal function that saves the configuration object to the JSON file. .PARAMETER Config The configuration object to save. .EXAMPLE PS> Save-PstConfig -Config $config Saves the configuration object to the JSON file. #> function Save-PstConfig { [CmdletBinding()] param( [Parameter(Mandatory)] [PSCustomObject]$Config ) $folder = Join-Path $env:localappdata 'PstTimeTracker' $configFile = Join-Path $folder 'config.json' if (!(Test-Path $folder)) { New-Item $folder -ItemType Directory | Out-Null } $Config | ConvertTo-Json -Depth 10 | Out-File $configFile -Encoding UTF8 } #EndRegion './Private/Save-PstConfig.ps1' 32 #Region './Public/Add-PstClient.ps1' -1 <# .SYNOPSIS Adds a new client to the configuration. .DESCRIPTION Adds a new client with an optional list of projects to the configuration. .PARAMETER Name The name of the client to add. .PARAMETER Projects Optional array of project names for this client. .EXAMPLE PS> Add-PstClient -Name 'ClientC' -Projects @('Project 1', 'Project 2') Adds a new client called ClientC with two projects. .EXAMPLE PS> Add-PstClient -Name 'ClientD' Adds a new client called ClientD with no projects. #> function Add-PstClient { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$Name, [Parameter()] [string[]]$Projects = @() ) $config = Get-PstConfig # Check if client already exists $existingClient = $config.Clients | Where-Object { $_.Name -eq $Name } if ($existingClient) { Write-Warning "Client '$Name' already exists. Use Update-PstClient to modify it." return } # Create new client $newClient = [PSCustomObject]@{ Name = $Name Projects = $Projects } # Convert to ArrayList for easier manipulation $clientsList = [System.Collections.ArrayList]::new() if ($config.Clients) { foreach ($client in $config.Clients) { $null = $clientsList.Add($client) } } $null = $clientsList.Add($newClient) # Recreate config object to avoid mutation issues $newConfig = [PSCustomObject]@{ Clients = $clientsList.ToArray() } Save-PstConfig -Config $newConfig } #EndRegion './Public/Add-PstClient.ps1' 65 #Region './Public/Add-PstProject.ps1' -1 <# .SYNOPSIS Adds a project to a client. .DESCRIPTION Adds a new project to the specified client's project list. .PARAMETER Client The name of the client to add the project to. .PARAMETER Project The name of the project to add. .EXAMPLE PS> Add-PstProject -Client 'ClientA' -Project 'New Project' Adds 'New Project' to ClientA's project list. #> function Add-PstProject { [CmdletBinding()] param( [Parameter(Mandatory)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $configFile = Join-Path $env:LOCALAPPDATA 'PstTimeTracker\config.json' } else { $configFile = Join-Path $HOME '.local/share/PstTimeTracker/config.json' } if (Test-Path $configFile) { $config = Get-Content $configFile -Raw | ConvertFrom-Json $config.Clients.Name | Where-Object { $_ -like "$wordToComplete*" } } })] [string]$Client, [Parameter(Mandatory)] [string]$Project ) $config = Get-PstConfig $clientObj = $config.Clients | Where-Object { $_.Name -eq $Client } if (!$clientObj) { Write-Warning "Client '$Client' not found. Use Add-PstClient to create it first." return } # Check if project already exists if ($clientObj.Projects -contains $Project) { Write-Warning "Project '$Project' already exists for client '$Client'." return } # Convert to ArrayList for easier manipulation $projectsList = [System.Collections.ArrayList]::new() if ($clientObj.Projects) { foreach ($proj in $clientObj.Projects) { $null = $projectsList.Add($proj) } } $null = $projectsList.Add($Project) # Recreate the client list with updated projects $updatedClients = foreach ($client in $config.Clients) { if ($client.Name -eq $Client) { [PSCustomObject]@{ Name = $client.Name Projects = $projectsList.ToArray() } } else { $client } } # Recreate config object $newConfig = [PSCustomObject]@{ Clients = $updatedClients } Save-PstConfig -Config $newConfig Write-Host "Project '$Project' added to client '$Client' successfully." -ForegroundColor Green } #EndRegion './Public/Add-PstProject.ps1' 85 #Region './Public/Add-PstTime.ps1' -1 <# .SYNOPSIS Adds a chunk of time to the day so far. .DESCRIPTION Adds a chunk of time to the day so far. .PARAMETER Client The client to add time to. Must be a client configured in the system. .PARAMETER Project The project to add time to. Must be a project associated with the client. .PARAMETER Minutes The number of minutes to add. .PARAMETER StartTime If provided this will be added to the day summary. .EXAMPLE PS> Add-PstTime -Client ClientA -Project 'Project Alpha' -Minutes 60 Adds 60 mins to the day so far for ClientA - Project Alpha. #> function Add-PstTime { param ( [Parameter(Mandatory)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $configFile = Join-Path $env:LOCALAPPDATA 'PstTimeTracker\config.json' } else { $configFile = Join-Path $HOME '.local/share/PstTimeTracker/config.json' } if (Test-Path $configFile) { $config = Get-Content $configFile -Raw | ConvertFrom-Json $config.Clients.Name | Where-Object { $_ -like "$wordToComplete*" } } })] [string]$Client, [Parameter(Mandatory)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $clientName = $fakeBoundParameters['Client'] if ($clientName) { if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $configFile = Join-Path $env:LOCALAPPDATA 'PstTimeTracker\config.json' } else { $configFile = Join-Path $HOME '.local/share/PstTimeTracker/config.json' } if (Test-Path $configFile) { $config = Get-Content $configFile -Raw | ConvertFrom-Json $client = $config.Clients | Where-Object { $_.Name -eq $clientName } if ($client) { $client.Projects | Where-Object { $_ -like "$wordToComplete*" } } } } })] [string]$Project, [Parameter(Mandatory)] [int]$Minutes, [Parameter()] [datetime]$StartTime ) # Validate client exists $config = Get-PstConfig $clientObj = $config.Clients | Where-Object { $_.Name -eq $Client } if (!$clientObj) { Write-Warning "Client '$Client' not found in configuration. Use Get-PstClient to see available clients." return } # Validate project exists for this client if ($clientObj.Projects -notcontains $Project) { Write-Warning "Project '$Project' not found for client '$Client'. Use Get-PstProject -Client '$Client' to see available projects." return } Clear-Host Write-host ('Adding {0} minutes for {1} - {2}' -f $Minutes, $Client, $Project) [Array]$TodaysWork = Restore-Pstday $Addtime = $Client | Select-Object @{l='Client';e={$Client}},@{l='Project';e={$Project}},@{l='StartTime';e={$StartTime}}, @{l='Elapsed';e={New-TimeSpan -Minutes $Minutes}} $Addtime | Format-Table -AutoSize | Out-String | Write-Host -ForegroundColor White $TodaysWork += $AddTime # backup the day so far just in case Backup-PstDay -TodaysWork $TodaysWork # Output day summary Get-PstDaySummary } #EndRegion './Public/Add-PstTime.ps1' 102 #Region './Public/Backup-PstDay.ps1' -1 <# .SYNOPSIS Backups the day so far to a json file in the local appdata folder. .DESCRIPTION backups the day so far to a json file in the local appdata folder. This is used to restore the day so far if the script is closed. .PARAMETER TodaysWork The day so far to backup. .EXAMPLE PS> Backup-PstDay -TodaysWork $TodaysWork Backups the day so far to a json file in the local appdata folder. #> function Backup-PstDay { param ( [parameter(ValueFromPipeline=$true, Mandatory)] $TodaysWork ) if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $folder = Join-Path $env:LOCALAPPDATA 'PstTimeTracker' } else { $folder = Join-Path $HOME '.local/share/PstTimeTracker' } if (!(Test-Path $folder)) { New-Item $folder -ItemType Directory | Out-Null } if($TodaysWork) { $fileName = Join-Path $folder ('todayswork-{0}.json' -f (Get-Date -Format 'yyyy-MM-dd')) $TodaysWork | Select-Object Client, Project, StartTime, @{l='ElapsedTotalSeconds';e={$_.Elapsed.TotalSeconds}} | ConvertTo-Json | Out-File $fileName } # remove json files older than 10 days Get-ChildItem $folder *.json | where-object lastWriteTime -lt (get-date).AddDays(-10) | Remove-Item } #EndRegion './Public/Backup-PstDay.ps1' 43 #Region './Public/Get-PstClient.ps1' -1 <# .SYNOPSIS Gets all configured clients or a specific client. .DESCRIPTION Returns all clients from the configuration or a specific client by name. .PARAMETER Name Optional. The name of the client to retrieve. If not specified, all clients are returned. .EXAMPLE PS> Get-PstClient Returns all configured clients. .EXAMPLE PS> Get-PstClient -Name 'ClientA' Returns the ClientA configuration including its projects. #> function Get-PstClient { [CmdletBinding()] param( [Parameter()] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $configFile = Join-Path $env:LOCALAPPDATA 'PstTimeTracker\config.json' } else { $configFile = Join-Path $HOME '.local/share/PstTimeTracker/config.json' } if (Test-Path $configFile) { $config = Get-Content $configFile -Raw | ConvertFrom-Json $config.Clients.Name | Where-Object { $_ -like "$wordToComplete*" } } })] [string]$Name ) $config = Get-PstConfig if ($Name) { $client = $config.Clients | Where-Object { $_.Name -eq $Name } if ($client) { return $client } else { Write-Warning "Client '$Name' not found." return $null } } else { return $config.Clients } } #EndRegion './Public/Get-PstClient.ps1' 54 #Region './Public/Get-PstDaySummary.ps1' -1 <# .SYNOPSIS Gets the day summary. .DESCRIPTION Gets the day summary. If a date is provided it will restore the day so far from the json file in the local appdata folder and display the summary. .PARAMETER date If provided this will restore the specified day from the json file in the local appdata folder and display the summary. .EXAMPLE PS> Get-PstDaySummary This will display the day summary for the day so far. .EXAMPLE PS> Get-PstDaySummary -date 2023-01-01 This will restore the json from the local appdata folder for 2023-01-01 and display the summary. #> function Get-PstDaySummary { param ( $date ) if($date) { $RestoredWork = Restore-PstDay -date $date if (-not $RestoredWork) { Write-Host ('No work found for {0}...' -f $date) -ForegroundColor DarkRed -BackgroundColor White return } [Array]$results = $RestoredWork | Group-Object Client, Project | Select-Object Name, @{l='Total';e={New-TimeSpan -Seconds (($_.Group.Elapsed.TotalSeconds | Measure-Object -sum ).sum)}} $results += [PSCustomObject]@{ Name = '===Total' Total = New-TimeSpan -Seconds ($RestoredWork | Select-Object @{l='TotalSecs';e={$_.elapsed.TotalSeconds}} | Measure-object -Property TotalSecs -Sum).Sum } $results | Out-String | Write-Host -ForegroundColor White } else { $TodaysWork = Restore-PstDay if($TodaysWork) { Write-Host '--------------------------' -ForegroundColor DarkGreen -BackgroundColor White Write-Host 'So far today: ' -ForegroundColor DarkGreen -BackgroundColor White Write-Host '--------------------------' -ForegroundColor DarkGreen -BackgroundColor White [Array]$results = $TodaysWork | Group-Object Client, Project | Select-Object Name, @{l='Total';e={New-TimeSpan -Seconds (($_.Group.Elapsed.TotalSeconds | Measure-Object -sum ).sum)}} $results += [PSCustomObject]@{ Name = '===Total' Total = New-TimeSpan -Seconds ($TodaysWork | Select-Object @{l='TotalSecs';e={$_.elapsed.TotalSeconds}} | Measure-object -Property TotalSecs -Sum).Sum } $results | Out-String | Write-Host -ForegroundColor White } else { Write-Host 'Nothing recorded yet...' -ForegroundColor DarkRed -BackgroundColor White } } } #EndRegion './Public/Get-PstDaySummary.ps1' 64 #Region './Public/Get-PstProject.ps1' -1 <# .SYNOPSIS Gets projects for a specific client or all projects. .DESCRIPTION Returns projects for a specified client from the configuration. .PARAMETER Client The name of the client whose projects to retrieve. .EXAMPLE PS> Get-PstProject -Client 'ClientA' Returns all projects for ClientA. #> function Get-PstProject { [CmdletBinding()] param( [Parameter(Mandatory)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $configFile = Join-Path $env:LOCALAPPDATA 'PstTimeTracker\config.json' } else { $configFile = Join-Path $HOME '.local/share/PstTimeTracker/config.json' } if (Test-Path $configFile) { $config = Get-Content $configFile -Raw | ConvertFrom-Json $config.Clients.Name | Where-Object { $_ -like "$wordToComplete*" } } })] [string]$Client ) $config = Get-PstConfig $clientObj = $config.Clients | Where-Object { $_.Name -eq $Client } if (!$clientObj) { Write-Warning "Client '$Client' not found." return $null } return $clientObj.Projects } #EndRegion './Public/Get-PstProject.ps1' 45 #Region './Public/Remove-PstClient.ps1' -1 <# .SYNOPSIS Removes a client from the configuration. .DESCRIPTION Removes the specified client and all its projects from the configuration. .PARAMETER Name The name of the client to remove. .PARAMETER Force If specified, removes the client without confirmation. .EXAMPLE PS> Remove-PstClient -Name 'ClientC' Prompts for confirmation, then removes ClientC from the configuration. .EXAMPLE PS> Remove-PstClient -Name 'ClientC' -Force Removes ClientC without confirmation. #> function Remove-PstClient { [CmdletBinding(SupportsShouldProcess, ConfirmImpact='High')] param( [Parameter(Mandatory)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $configFile = Join-Path $env:LOCALAPPDATA 'PstTimeTracker\config.json' } else { $configFile = Join-Path $HOME '.local/share/PstTimeTracker/config.json' } if (Test-Path $configFile) { $config = Get-Content $configFile -Raw | ConvertFrom-Json $config.Clients.Name | Where-Object { $_ -like "$wordToComplete*" } } })] [string]$Name, [Parameter()] [switch]$Force ) $config = Get-PstConfig $existingClient = $config.Clients | Where-Object { $_.Name -eq $Name } if (!$existingClient) { Write-Warning "Client '$Name' not found." return } if ($Force -or $PSCmdlet.ShouldProcess($Name, "Remove client")) { $updatedClients = $config.Clients | Where-Object { $_.Name -ne $Name } # Recreate config object to avoid mutation issues $newConfig = [PSCustomObject]@{ Clients = $updatedClients } Save-PstConfig -Config $newConfig Write-Host "Client '$Name' removed successfully." -ForegroundColor Green } } #EndRegion './Public/Remove-PstClient.ps1' 66 #Region './Public/Remove-PstProject.ps1' -1 <# .SYNOPSIS Removes a project from a client. .DESCRIPTION Removes the specified project from a client's project list. .PARAMETER Client The name of the client to remove the project from. .PARAMETER Project The name of the project to remove. .PARAMETER Force If specified, removes the project without confirmation. .EXAMPLE PS> Remove-PstProject -Client 'ClientA' -Project 'Old Project' Prompts for confirmation, then removes 'Old Project' from ClientA. .EXAMPLE PS> Remove-PstProject -Client 'ClientA' -Project 'Old Project' -Force Removes 'Old Project' from ClientA without confirmation. #> function Remove-PstProject { [CmdletBinding(SupportsShouldProcess, ConfirmImpact='High')] param( [Parameter(Mandatory)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $configFile = Join-Path $env:LOCALAPPDATA 'PstTimeTracker\config.json' } else { $configFile = Join-Path $HOME '.local/share/PstTimeTracker/config.json' } if (Test-Path $configFile) { $config = Get-Content $configFile -Raw | ConvertFrom-Json $config.Clients.Name | Where-Object { $_ -like "$wordToComplete*" } } })] [string]$Client, [Parameter(Mandatory)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $clientName = $fakeBoundParameters['Client'] if ($clientName) { if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $configFile = Join-Path $env:LOCALAPPDATA 'PstTimeTracker\config.json' } else { $configFile = Join-Path $HOME '.local/share/PstTimeTracker/config.json' } if (Test-Path $configFile) { $config = Get-Content $configFile -Raw | ConvertFrom-Json $client = $config.Clients | Where-Object { $_.Name -eq $clientName } if ($client) { $client.Projects | Where-Object { $_ -like "$wordToComplete*" } } } } })] [string]$Project, [Parameter()] [switch]$Force ) $config = Get-PstConfig $clientObj = $config.Clients | Where-Object { $_.Name -eq $Client } if (!$clientObj) { Write-Warning "Client '$Client' not found." return } if ($clientObj.Projects -notcontains $Project) { Write-Warning "Project '$Project' not found for client '$Client'." return } if ($Force -or $PSCmdlet.ShouldProcess("$Client - $Project", "Remove project")) { $updatedProjects = $clientObj.Projects | Where-Object { $_ -ne $Project } # Recreate the client list with updated projects $updatedClients = foreach ($client in $config.Clients) { if ($client.Name -eq $Client) { [PSCustomObject]@{ Name = $client.Name Projects = $updatedProjects } } else { $client } } # Recreate config object $newConfig = [PSCustomObject]@{ Clients = $updatedClients } Save-PstConfig -Config $newConfig Write-Host "Project '$Project' removed from client '$Client' successfully." -ForegroundColor Green } } #EndRegion './Public/Remove-PstProject.ps1' 107 #Region './Public/Restore-PstDay.ps1' -1 <# .SYNOPSIS Restores the day so far from the json file in the local appdata folder. .DESCRIPTION Restores the day so far from the json file in the local appdata folder. This is used to restore the day so far if the script is closed. .PARAMETER date If provided this will restore the specified day from the json file in the local appdata folder. .EXAMPLE PS> Restore-PstDay This will restore the day so far from the json file in the local appdata folder. .EXAMPLE PS> Restore-PstDay -date 2023-01-01 This will restore the json from the local appdata folder for 2023-01-01. #> function Restore-PstDay { param ( $date = (Get-Date).Date ) if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $folder = Join-Path $env:LOCALAPPDATA 'PstTimeTracker' } else { $folder = Join-Path $HOME '.local/share/PstTimeTracker' } $fileName = Join-Path $folder ('todayswork-{0}.json' -f (Get-Date($date) -Format 'yyyy-MM-dd')) Write-Verbose "Restoring day from file: $fileName" if (Test-Path $fileName) { Get-Content $fileName | ConvertFrom-Json | Select-Object Client, Project, StartTime, @{l='Elapsed';e={New-TimeSpan -Seconds $_.ElapsedTotalSeconds}} } } #EndRegion './Public/Restore-PstDay.ps1' 44 #Region './Public/Start-PstDay.ps1' -1 <# .SYNOPSIS Starts the day. .DESCRIPTION Starts the day. Restore the day so far from the json file in the local appdata folder if it exists. .EXAMPLE PS> Start-PstDay This will start the day and restore the day so far from the json file in the local appdata folder if it exists. #> function Start-PstDay { [Array]$TodaysWork = Restore-PstDay } #EndRegion './Public/Start-PstDay.ps1' 21 #Region './Public/Start-PstTimer.ps1' -1 <# .SYNOPSIS Starts a timer for a client and project. .DESCRIPTION Starts a timer for a client and project. The client and project must be configured in the system. .PARAMETER Client Client to track time against. Must be a client configured in the system. .PARAMETER Project Project to track time against. Must be a project associated with the client. .EXAMPLE PS> Start-PstTimer -Client ClientA -Project 'Project Alpha' This will start a timer for ClientA - Project Alpha. #> function Start-PstTimer { param ( [Parameter(Mandatory)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $configFile = Join-Path $env:LOCALAPPDATA 'PstTimeTracker\config.json' } else { $configFile = Join-Path $HOME '.local/share/PstTimeTracker/config.json' } if (Test-Path $configFile) { $config = Get-Content $configFile -Raw | ConvertFrom-Json $config.Clients.Name | Where-Object { $_ -like "$wordToComplete*" } } })] [string]$Client, [Parameter(Mandatory)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $clientName = $fakeBoundParameters['Client'] if ($clientName) { if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $configFile = Join-Path $env:LOCALAPPDATA 'PstTimeTracker\config.json' } else { $configFile = Join-Path $HOME '.local/share/PstTimeTracker/config.json' } if (Test-Path $configFile) { $config = Get-Content $configFile -Raw | ConvertFrom-Json $client = $config.Clients | Where-Object { $_.Name -eq $clientName } if ($client) { $client.Projects | Where-Object { $_ -like "$wordToComplete*" } } } } })] [string]$Project ) # Validate client exists $config = Get-PstConfig $clientObj = $config.Clients | Where-Object { $_.Name -eq $Client } if (!$clientObj) { Write-Warning "Client '$Client' not found in configuration. Use Get-PstClient to see available clients." return } # Validate project exists for this client if ($clientObj.Projects -notcontains $Project) { Write-Warning "Project '$Project' not found for client '$Client'. Use Get-PstProject -Client '$Client' to see available projects." return } Clear-Host $startTime = (Get-Date) $timer = New-Object System.Diagnostics.Stopwatch $timer.Start() [Array]$TodaysWork = Restore-PstDay if($TodaysWork) { # Output day summary Get-PstDaySummary } $null = Read-host ('Working on {0} - {1}, since {2} - Press any key to stop?' -f $Client, $Project, $startTime) $timer.Stop() Write-Host '--------------------------' -ForegroundColor DarkMagenta -BackgroundColor White Write-Host 'Just worked on: ' -ForegroundColor DarkMagenta -BackgroundColor White Write-Host '--------------------------' -ForegroundColor DarkMagenta -BackgroundColor White $Addtime = $timer | Select-Object @{l='Client';e={$Client}},@{l='Project';e={$Project}},@{l='StartTime';e={$startTime}}, Elapsed $Addtime | Format-Table -AutoSize | Out-String | Write-Host -ForegroundColor White $TodaysWork += $AddTime # backup the day so far just in case Backup-PstDay -TodaysWork $TodaysWork # Output day summary Get-PstDaySummary } #EndRegion './Public/Start-PstTimer.ps1' 105 #Region './Public/Update-PstClient.ps1' -1 <# .SYNOPSIS Updates an existing client's name. .DESCRIPTION Updates the name of an existing client in the configuration. .PARAMETER Name The current name of the client. .PARAMETER NewName The new name for the client. .EXAMPLE PS> Update-PstClient -Name 'ClientA' -NewName 'Client Alpha' Renames ClientA to 'Client Alpha'. #> function Update-PstClient { [CmdletBinding()] param( [Parameter(Mandatory)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $configFile = Join-Path $env:LOCALAPPDATA 'PstTimeTracker\config.json' } else { $configFile = Join-Path $HOME '.local/share/PstTimeTracker/config.json' } if (Test-Path $configFile) { $config = Get-Content $configFile -Raw | ConvertFrom-Json $config.Clients.Name | Where-Object { $_ -like "$wordToComplete*" } } })] [string]$Name, [Parameter(Mandatory)] [string]$NewName ) $config = Get-PstConfig $existingClient = $config.Clients | Where-Object { $_.Name -eq $Name } if (!$existingClient) { Write-Warning "Client '$Name' not found." return } # Check if new name already exists $conflictClient = $config.Clients | Where-Object { $_.Name -eq $NewName } if ($conflictClient) { Write-Warning "A client with name '$NewName' already exists." return } # Recreate the client list with updated name $updatedClients = foreach ($client in $config.Clients) { if ($client.Name -eq $Name) { [PSCustomObject]@{ Name = $NewName Projects = $client.Projects } } else { $client } } # Recreate config object $newConfig = [PSCustomObject]@{ Clients = $updatedClients } Save-PstConfig -Config $newConfig Write-Host "Client renamed from '$Name' to '$NewName' successfully." -ForegroundColor Green } #EndRegion './Public/Update-PstClient.ps1' 77 #Region './Public/Update-PstProject.ps1' -1 <# .SYNOPSIS Updates a project name for a client. .DESCRIPTION Renames an existing project for the specified client. .PARAMETER Client The name of the client whose project to update. .PARAMETER Project The current name of the project. .PARAMETER NewName The new name for the project. .EXAMPLE PS> Update-PstProject -Client 'ClientA' -Project 'Project Alpha' -NewName 'Alpha Project v2' Renames the project from 'Project Alpha' to 'Alpha Project v2' for ClientA. #> function Update-PstProject { [CmdletBinding()] param( [Parameter(Mandatory)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $configFile = Join-Path $env:LOCALAPPDATA 'PstTimeTracker\config.json' } else { $configFile = Join-Path $HOME '.local/share/PstTimeTracker/config.json' } if (Test-Path $configFile) { $config = Get-Content $configFile -Raw | ConvertFrom-Json $config.Clients.Name | Where-Object { $_ -like "$wordToComplete*" } } })] [string]$Client, [Parameter(Mandatory)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $clientName = $fakeBoundParameters['Client'] if ($clientName) { if ($IsWindows -or $PSVersionTable.PSVersion.Major -le 5) { $configFile = Join-Path $env:LOCALAPPDATA 'PstTimeTracker\config.json' } else { $configFile = Join-Path $HOME '.local/share/PstTimeTracker/config.json' } if (Test-Path $configFile) { $config = Get-Content $configFile -Raw | ConvertFrom-Json $client = $config.Clients | Where-Object { $_.Name -eq $clientName } if ($client) { $client.Projects | Where-Object { $_ -like "$wordToComplete*" } } } } })] [string]$Project, [Parameter(Mandatory)] [string]$NewName ) $config = Get-PstConfig $clientObj = $config.Clients | Where-Object { $_.Name -eq $Client } if (!$clientObj) { Write-Warning "Client '$Client' not found." return } if ($clientObj.Projects -notcontains $Project) { Write-Warning "Project '$Project' not found for client '$Client'." return } # Check if new name already exists if ($clientObj.Projects -contains $NewName) { Write-Warning "A project with name '$NewName' already exists for client '$Client'." return } # Create updated project list $updatedProjects = $clientObj.Projects | ForEach-Object { if ($_ -eq $Project) { $NewName } else { $_ } } # Recreate the client list with updated projects $updatedClients = foreach ($client in $config.Clients) { if ($client.Name -eq $Client) { [PSCustomObject]@{ Name = $client.Name Projects = $updatedProjects } } else { $client } } # Recreate config object $newConfig = [PSCustomObject]@{ Clients = $updatedClients } Save-PstConfig -Config $newConfig Write-Host "Project renamed from '$Project' to '$NewName' for client '$Client' successfully." -ForegroundColor Green } #EndRegion './Public/Update-PstProject.ps1' 110 |