├── .github └── ISSUE_TEMPLATE │ ├── bug-report.yml │ ├── config.yml │ ├── feature-request.yml │ └── other-request.yml ├── Changelog.md ├── Design.md ├── LICENSE.txt ├── PSClock.psd1 ├── PSClock.psm1 ├── README.md ├── docs ├── Get-PSClock.md ├── Get-PrimaryDisplaySize.md ├── Save-PSClock.md ├── Set-PSClock.md ├── Show-FontPreview.md ├── Show-PSClockSettingPreview.md ├── Start-PSClock.md ├── Stop-PSClock.md └── about_psclock.md ├── en-US ├── PSClock-help.xml ├── PSClock.psd1 └── about_psclock.help.txt ├── formats └── psclock.format.ps1xml ├── functions ├── ClockSettingsPreview.ps1 ├── Get-PSClock.ps1 ├── Get-ScreenWidth.ps1 ├── Save-PSClock.ps1 ├── Set-PSClock.ps1 ├── Start-PSClock.ps1 ├── Stop-PSClock.ps1 ├── WPFFontPreview.ps1 ├── fonts.ico └── private.ps1 ├── images ├── custom-verbose.png ├── get-psclock.png ├── psclock-preview.png ├── psclock.png ├── pstoolmaking-thumbnail.png ├── sample-1.png ├── sample-2.png ├── sample-3.png ├── set-psclock-color.png ├── show-fontpreview.png └── tab-complete-example.png └── tests └── PSClock.tests.ps1 /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | name: 🪲 Bug Report 2 | description: Report a bug or problem. 3 | title: "[Bug]: " 4 | labels: ["bug","triage"] 5 | assignees: 6 | - jdhitsolutions 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: "## Thank you for bringing this to our attention." 11 | - type: textarea 12 | id: description 13 | attributes: 14 | label: Describe the problem 15 | description: Please describe the bug or problem including the exact syntax you are using and any error or warning messages. 16 | validations: 17 | required: true 18 | - type: textarea 19 | id: expected-behavior 20 | attributes: 21 | label: Expectation 22 | description: What did you expect to happen? 23 | - type: textarea 24 | id: additional-info 25 | attributes: 26 | label: Additional Information 27 | description: Do you have any additional information or context that you think will be helpful in resolving this issue? 28 | - type: dropdown 29 | id: psversion 30 | attributes: 31 | label: PowerShell version 32 | description: What version of PowerShell are you running? 33 | options: 34 | - '4.0' 35 | - '5.1' 36 | - 6.x 37 | - '7.0' 38 | - '7.1' 39 | - '7.2' 40 | - Other 41 | validations: 42 | required: true 43 | - type: dropdown 44 | id: platform 45 | attributes: 46 | label: Platform 47 | description: What operating system are you running? 48 | options: 49 | - Windows 10 Home 50 | - Windows 11 Home 51 | - Windows 10 Pro or Enterprise 52 | - Windows 11 Pro or Enterprise 53 | - MacOS 54 | - Linux 55 | - Other 56 | - type: checkboxes 57 | id: checks 58 | attributes: 59 | label: Additional Checks 60 | description: Have you verified the following? 61 | options: 62 | - label: You are using the latest version of this module. 63 | required: true 64 | - label: You have read this repository's README file. 65 | - label: You have read full help and examples for the command you are having problems with. 66 | - label: You are running PowerShell in an elevated session. 67 | - label: You are running in a traditional PowerShell console or Windows Terminal 68 | 69 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: README 4 | url: https://github.com/jdhitsolutions/PSClock/blob/main/README.md 5 | about: Open this module's README.md file. 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: 💡Feature Request 2 | description: Request a new feature or enhancement 3 | title: "[Request]: " 4 | labels: ["enhancement","triage"] 5 | assignees: 6 | - jdhitsolutions 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: "## Thank you for bringing this to our attention." 11 | - type: textarea 12 | id: description 13 | attributes: 14 | label: Describe the request 15 | description: Please describe your feature request or enhancement in detail. What deficiency does it address in the module? What use cases support your request? 16 | validations: 17 | required: true 18 | - type: dropdown 19 | id: psversion 20 | attributes: 21 | label: PowerShell version 22 | description: What version of PowerShell are you running? 23 | options: 24 | - '4.0' 25 | - '5.1' 26 | - 6.x 27 | - '7.0' 28 | - '7.1' 29 | - '7.2' 30 | - Other 31 | validations: 32 | required: false 33 | - type: dropdown 34 | id: platform 35 | attributes: 36 | label: Platform 37 | description: What operating system are you running? 38 | options: 39 | - Windows 10 Home 40 | - Windows 11 Home 41 | - Windows 10 Pro or Enterprise 42 | - Windows 11 Pro or Enterprise 43 | - MacOS 44 | - Linux 45 | - Other 46 | 47 | 48 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/other-request.yml: -------------------------------------------------------------------------------- 1 | name: 🤔Other Request or Question 2 | description: Open a request for all other issues 3 | title: "[Question]: " 4 | labels: ["question","triage"] 5 | assignees: 6 | - jdhitsolutions 7 | body: 8 | - type: textarea 9 | id: description 10 | attributes: 11 | label: Describe the question or issue 12 | description: What is on your mind? 13 | validations: 14 | required: true 15 | - type: dropdown 16 | id: psversion 17 | attributes: 18 | label: PowerShell version 19 | description: What version of PowerShell are you running? 20 | options: 21 | - '4.0' 22 | - '5.1' 23 | - 6.x 24 | - '7.0' 25 | - '7.1' 26 | - '7.2' 27 | - Other 28 | validations: 29 | required: false 30 | - type: dropdown 31 | id: platform 32 | attributes: 33 | label: Platform 34 | description: What operating system are you running? 35 | options: 36 | - Windows 10 Home 37 | - Windows 11 Home 38 | - Windows 10 Pro or Enterprise 39 | - Windows 11 Pro or Enterprise 40 | - MacOS 41 | - Linux 42 | - Other 43 | 44 | 45 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog for PSClock 2 | 3 | ## [Unreleased] 4 | 5 | ## [1.5.0] - 2025-03-31 6 | 7 | ### Added 8 | 9 | - Added a private, custom function for verbose messages. 10 | - Moved verbose messages and warnings to localized string data. 11 | - Modified commands to write additional data for debugging and troubleshooting to the Information stream. 12 | - Added parameter `-Passthru` to `Save-PSClock`. 13 | 14 | ### Changed 15 | 16 | - Updated `Design.md`. 17 | - Updated auto completers for the `Color` and `FontFamily` parameters to let the user start typing a parameter value.. 18 | - Help updates. 19 | - Updated `README`. 20 | - Changed dependency from `ThreadJob` to the newer `Microsoft.PowerShell.ThreadJob`. 21 | 22 | ### Removed 23 | 24 | - Removed all error handling related to non-Windows systems since this module can't be imported into non-Windows systems. 25 | 26 | ## [1.4.0] - 2024-05-21 27 | 28 | ### Added 29 | 30 | - Added parameter `SampleText` to `Show-FontPreview`. 31 | - Added parameter `CurrentPosition` with an alias of `Position` to `Set-PSClock`. 32 | - Added command `Get-PrimaryDisplaySize`. 33 | - Added verbose output to `Show-FontPreview`. 34 | - Added an about help topic. 35 | - Added the function `Show-PSClockSettingPreview` to configure PSClock settings with a WPF-based GUI. 36 | 37 | ### Changed 38 | 39 | - Modified `Start-PSClock` to temporarily pause the dispatch timer if grabbing and moving the clock. 40 | - Updated `Design.md`. 41 | - Modified `FontWeight` default values to be a more complete set of: 'Normal', 'Bold', 'Light', 'Medium', 'SemiBold'. 42 | - Documentation and help updates. 43 | - Converted ChangeLog format. 44 | 45 | ## [1.3.0] - 2024-05-14 46 | 47 | - Code cleanup. 48 | - Added alias `gpc` for `Get-PSClock`. 49 | Added alias `spc` for `Set-PSClock`. 50 | - Added command `Show-FontPreview` to display a preview of a font in a WPF form. 51 | - Updated Verbose output in the module functions. 52 | - Updated `Design.md`.s 53 | - Updated `README.md`. 54 | 55 | ## [1.2.0] - 2022-08-08 56 | 57 | - Moved the `Color` parameter in `Set-PSColor` to the first position. __This is a minor breaking change__. 58 | 59 | ## [1.1.0] - 2022-02-23 60 | 61 | - Changed form title to "PSClock". 62 | - Updated `Start-PSClock` to allow user to delete the flag file if detected. 63 | - Updated module manifest. 64 | - Updated `Color` parameter auto completer for `Set-PSClock` to display values using the named color. Use `Ctrl-Space` to display the formatted list. 65 | - Updated `README.md`. 66 | - Added private functions `Convert-RGBtoAnsi` and `Get-RGB`. 67 | - Updated help documentation. 68 | 69 | ## [1.0.0] - 2021-11-09 70 | 71 | - Fixed bad formatting in markdown help files. 72 | - Updated `README.md`. 73 | - Added `Design.md`. 74 | - General code cleanup. 75 | - Official release 76 | 77 | ## [0.9.1] - 2021-11-08 78 | 79 | - Added online help links. 80 | - Updated module manifest to reset Verbose preference. [Issue #1](https://github.com/jdhitsolutions/PSClock/issues/1) 81 | - Fixed a bug in `Save-PSClock` that wasn't exporting all settings. 82 | - Updated `README.md`. 83 | 84 | ## 0.9.0 - 2021-11-08 85 | 86 | - Added a module icon. 87 | - Modified `Start-PSClock` and `Get-PSClock` to include window position information. 88 | - Added `Save-PSClock` to export settings to a CliXML file. 89 | - Updated `Start-PSClock` to use saved values if found. 90 | - Added an argument completer for the `Color` parameter of `Start-PSClock` and `Set-PSClock`. 91 | - Updated help documentation. 92 | - Updated `README.md`. 93 | - Added verbose output for module import. 94 | - Manifest updates. 95 | - Release to PowerShell Gallery 96 | 97 | ## 0.8.0 - 2021-11-06 98 | 99 | - Modified `Start-PSClock` and `Set-PSClock` to take parameter input from the pipeline by property name. 100 | - Added `System.Drawing` as a required assembly so that the font family autocompletion works. 101 | - Updated help files. 102 | - Added external help. 103 | 104 | ## 0.7.0 - 2021-11-06 105 | 106 | - Added markdown help files. 107 | - Changed the default clock color to `White`. 108 | - Added `-Passthru` to `Set-PSColor`. 109 | 110 | ## 0.0.1 - 2021-11-06 111 | 112 | - Initial module setup. 113 | 114 | [Unreleased]: https://github.com/jdhitsolutions/PSClock/compare/v1.5.0..HEAD 115 | [1.5.0]: https://github.com/jdhitsolutions/PSClock/compare/v1.4.0..v1.5.0 116 | [1.4.0]: https://github.com/jdhitsolutions/PSClock/compare/v1.3.0..v1.4.0 117 | [1.3.0]: https://github.com/jdhitsolutions/PSClock/compare/v1.2.0..v1.3.0 118 | [1.2.0]: https://github.com/jdhitsolutions/PSClock/compare/v1.1.0..v1.2.0 119 | [1.1.0]: https://github.com/jdhitsolutions/PSClock/compare/v1.0.0..v1.1.0 120 | [1.0.0]: https://github.com/jdhitsolutions/PSClock/compare/v0.9.1..v1.0.0 121 | [0.9.1]: https://github.com/jdhitsolutions/PSClock/compare/v0.9.0..v0.9.1 -------------------------------------------------------------------------------- /Design.md: -------------------------------------------------------------------------------- 1 | # PSClock Module Design 2 | 3 | This document will provide technical details about how this module is designed. You might use this information to learn how to build your own PowerShell modules. Or you might use this information to troubleshoot a problem with the PSClock module. 4 | 5 | ## WPF Design 6 | 7 | The WPF form is very simple. In the parent form is a Stack Panel which contains a Label control. The clock is nothing more than the text of the label control. Most PowerShell-based WPF scripts import some time of XAML content to define the form. The form in this module is so simple that it can be defined in code. 8 | 9 | ```powershell 10 | $form = New-Object System.Windows.Window 11 | $form.Title = "PSTimer" 12 | $form.Height = 200 13 | $form.Width = 400 14 | $form.SizeToContent = "WidthAndHeight" 15 | $form.AllowsTransparency = $True 16 | $form.Background = "Transparent" 17 | $stack = New-Object System.Windows.Controls.StackPanel 18 | $label = New-Object System.Windows.Controls.label 19 | $label.Content = 20 | $stack.AddChild($label) 21 | $form.AddChild($stack) 22 | ``` 23 | 24 | The values to customize the appearance such as font style and color are passed as function parameters and then on to the form. Note that the code is defining some settings that aren't visible. But they remain for troubleshooting or debug purposes should I need them. 25 | 26 | ### Adding a Timer 27 | 28 | Because this is a clock, I wanted it to update once a second. To make this work in my WPF form, I create a `DispatcherTimer` object and configure the tick interval to be 1 second. 29 | 30 | ```powershell 31 | $timer = New-Object System.Windows.Threading.DispatcherTimer 32 | $timer.Interval = [TimeSpan]"0:0:1.00" 33 | ``` 34 | 35 | Next, I need to create an event to run every time the timer ticks off another second. 36 | 37 | ```powershell 38 | $timer.Add_Tick({ 39 | #update the label contents with the current date and time 40 | }) 41 | ``` 42 | 43 | ### Adding Events 44 | 45 | The WPF form also includes a few other events. Because the form is transparent, there's nothing visible to grab and move the clock. I added an event to move the form when it was clicked and dragged with the left mouse button. 46 | 47 | ```powershell 48 | $form.Add_MouseLeftButtonDown({ $form.DragMove() }) 49 | ``` 50 | 51 | Even though there is a `Stop-PSClock` command to close the form, I also added another event to close the form with a right mouse click. 52 | 53 | ```powershell 54 | $form.Add_MouseRightButtonUp({ _QuitClock }) 55 | ``` 56 | 57 | The action is calling an internal private function that cleans up related files. 58 | 59 | Finally, I added shortcuts to make it easy to re-size the clock using the + and - keys. 60 | 61 | ```powershell 62 | $form.Add_KeyDown({ 63 | switch ($_.key) { 64 | { 'Add', 'OemPlus' -contains $_ } { 65 | If ( $PSClockSettings.fontSize -ge 8) { 66 | $PSClockSettings.fontSize++ 67 | $form.UpdateLayout() 68 | } 69 | } 70 | { 'Subtract', 'OemMinus' -contains $_ } { 71 | If ($PSClockSettings.FontSize -ge 8) { 72 | $PSClockSettings.FontSize-- 73 | $form.UpdateLayout() 74 | } 75 | } 76 | { 'P' -contains $_ } { 77 | #show the preview settings form 78 | Show-PSClockSettingPreview 79 | } 80 | } 81 | }) 82 | ``` 83 | 84 | ## Runspaces 85 | 86 | When you create a WPF form and run it in PowerShell, because PowerShell is single-threaded, your prompt is blocked until the script creating the form completes. In this module the whole point is to keep the clock running on the desktop. The solution is to create a new runspace and run the WPF PowerShell code in it. 87 | 88 | ```powershell 89 | $rs = [RunspaceFactory]::CreateRunspace() 90 | $rs.ApartmentState = "STA" 91 | $rs.ThreadOptions = "ReuseThread" 92 | $rs.Open() 93 | ``` 94 | 95 | All of the code that creates the form is added to the runspace. 96 | 97 | ```powershell 98 | PSCmd = [PowerShell]::Create().AddScript({ 99 | #PowerShell code 100 | }) 101 | #assign the command to the runspace 102 | PSCmd.runspace = $rs 103 | #launch the runspace 104 | [void]PSCmd.BeginInvoke() 105 | ``` 106 | 107 | During development, I ran the WPF code directly in PowerShell. Only after I was satisfied with the results did I move it to the runspace. 108 | 109 | ### Synchronized Hashtable 110 | 111 | Normally, you can't easily interact with anything running in a separate PowerShell runspace. However, you can take advantage of a _synchronized hashtable_. This is a special type of hashtable. In `Start-PSClock` I define a hashtable for the global scope. 112 | 113 | ```powershell 114 | $global:PSClockSettings = [hashtable]::Synchronized(@{ 115 | DateFormat = $DateFormat 116 | FontSize = $FontSize 117 | FontStyle = $FontStyle 118 | FontWeight = $FontWeight 119 | Color = $Color 120 | FontFamily = $FontFamily 121 | OnTop = $OnTop 122 | StartingPosition = $Position 123 | CurrentPosition = $Null 124 | }) 125 | ``` 126 | 127 | The keys and values are the function's parameters. The synchronized part means I can create the same hashtable in the runspace. 128 | 129 | ```powershell 130 | $rs.SessionStateProxy.SetVariable("PSClockSettings", $global:PSClockSettings) 131 | ``` 132 | 133 | The runspace now has a variable called `$PSClockSettings`. If I make a change to the hashtable in either the global scope or the runspace, the other variable will be updated. 134 | 135 | This means that I can use the global hashtable to control the runspace. 136 | 137 | ```powershell 138 | if ($PSClockSettings.StartingPosition) { 139 | $form.left = $PSClockSettings.StartingPosition[0] 140 | $form.top = $PSClockSettings.StartingPosition[1] 141 | } 142 | else { 143 | $form.WindowStartupLocation = "CenterScreen" 144 | } 145 | # ... 146 | $label = New-Object System.Windows.Controls.label 147 | $label.Content = Get-Date -Format $PSClockSettings.DateFormat 148 | 149 | $label.HorizontalContentAlignment = "Center" 150 | $label.Foreground = $PSClockSettings.Color 151 | $label.FontStyle = $PSClockSettings.FontStyle 152 | $label.FontWeight = $PSClockSettings.FontWeight 153 | $label.FontSize = $PSClockSettings.FontSize 154 | $label.FontFamily = $PSClockSettings.FontFamily 155 | ``` 156 | 157 | In the `Tick` event handler, I update the form and hashtable. 158 | 159 | ```powershell 160 | if ($PSClockSettings.Running) { 161 | $label.Foreground = $PSClockSettings.Color 162 | $label.FontStyle = $PSClockSettings.FontStyle 163 | $label.FontWeight = $PSClockSettings.FontWeight 164 | $label.FontSize = $PSClockSettings.FontSize 165 | $label.FontFamily = $PSClockSettings.FontFamily 166 | $label.Content = Get-Date -Format $PSClockSettings.DateFormat 167 | 168 | $form.TopMost = $PSClockSettings.OnTop 169 | $form.UpdateLayout() 170 | 171 | $PSClockSettings.CurrentPosition = $form.left,$form.top 172 | } 173 | ``` 174 | 175 | You can always view the "raw" hashtable from a PowerShell prompt. 176 | 177 | ```dos 178 | PS C:\> $PSClockSettings 179 | 180 | Name Value 181 | ---- ----- 182 | FontSize 65 183 | CommandPath C:\scripts\psclock\functions 184 | DateFormat F 185 | Color Yellow 186 | FontStyle Normal 187 | Started 3/31/2025 10:34:48 AM 188 | OnTop False 189 | Running True 190 | StartingPosition {61, 62} 191 | Runspace System.Management.Automation.Runspaces.LocalRunspace 192 | FontWeight Normal 193 | FontFamily Freestyle Script 194 | CurrentPosition {61, 62} 195 | ``` 196 | 197 | ### Set-PSClock 198 | 199 | Because I didn't want to have to manually update the hashtable if I wanted to modify the clock, I `Set-PSClock` updates the hashtable. Using a function means I can document it and include features like `-WhatIf`. 200 | 201 | ```powershell 202 | $settings = "FontSize", "FontStyle", "FontWeight", "Color", "OnTop", "DateFormat", "FontFamily" 203 | if ($PSClockSettings -And $PSClockSettings.Running) { 204 | Foreach ($setting in $settings) { 205 | if ($PSBoundParameters.ContainsKey($setting)) { 206 | $value = $PSBoundParameters[$setting] 207 | $action = "Setting value to $value" 208 | Write-Verbose "Setting $setting to $value" 209 | if (PSCmdlet.ShouldProcess($setting, $action)) { 210 | $Global:PSClockSettings[$setting] = $Value 211 | } 212 | } 213 | } #foreach setting 214 | ``` 215 | 216 | ### Thread Jobs 217 | 218 | When a new PSClock is created, it also creates a new runspace. You can see this by running `Get-Runspace`. Runspace information is stored in the `$PSClockSettings` synchronized hashtable. 219 | 220 | ```dos 221 | PS C:\> Get-PSClock 222 | 223 | Running Format FontFamily Size Weight Color Style OnTop RunspaceID 224 | ------- ------ ---------- ---- ------ ----- ----- ----- ---------- 225 | True F Freestyle Script 65 Normal Yellow Normal False 11 226 | 227 | PS C:\> Get-Runspace -id 11 228 | 229 | Id Name ComputerName Type State Availability 230 | -- ---- ------------ ---- ----- ------------ 231 | 11 Runspace11 localhost Local Opened Busy 232 | ``` 233 | 234 | When the clock is closed, the runspace will remain. This is not necessarily a bad thing. Once you close your PowerShell session, the runspaces will be removed. But I wanted a cleaner way to clean up when a clock is closed. 235 | 236 | In my event handler connected to quitting, I create a ThreadJob. This is similar to a PowerShell background job excepts it runs in the current thread. It doesn't create a new runspace. I have the runspace ID from the synchronized hashtable so I can start a new ThreadJob like this: 237 | 238 | ```powershell 239 | #define a thread job to clean up the runspace 240 | $cmd = { 241 | Param([int]$ID) 242 | $r = Get-Runspace -Id $id 243 | $r.close() 244 | $r.dispose() 245 | } 246 | Start-ThreadJob -ScriptBlock $cmd -ArgumentList $PSClockSettings.runspace.id 247 | ``` 248 | 249 | When the clock closes, either with `Stop-PSClock` or a right-click, this code will run. 250 | 251 | ## Start-PSClock 252 | 253 | The main function, `Start-PSClock`, generates the runspace, creates the synchronized hashtable and launches the WPF form. Once the clock is running, I can use `Set-PSClock` to modify it. 254 | 255 | I tend to run multiple PowerShell windows and versions at the same time. While I could technically run the module in two different PowerShell sessions, it wouldn't make sense to have duplicate clocks. 256 | 257 | ### Flag File 258 | 259 | When a new clock is created, `Start-PSClock` creates a _flag_ file in the user's TEMP folder. This is nothing more than a text file. The flag file variable is defined in the module file. 260 | 261 | ```powershell 262 | $FlagPath = Join-Path -Path $env:temp -ChildPath psclock-flag.txt 263 | ``` 264 | 265 | The file is created in the `Start-PSClock` function. The file contains a timestamp and the user who started the clock. 266 | 267 | ```powershell 268 | "[{0}] PSClock started by {1} under PowerShell process id $pid" -f (Get-Date), $env:USERNAME | Out-File $FlagPath 269 | ``` 270 | 271 | The `Start-PSClock` command checks for this file, and if it is found, writes a warning message and then quits. 272 | 273 | ```powershell 274 | if (Test-Path $FlagPath) { 275 | Write-Warning ($strings.FlagFound -f (Get-Content -path $FlagPath),$FlagPath) 276 | 277 | $r = Read-Host $strings.RemovePrompt 278 | if ($r -eq 'Y') { 279 | Remove-Item $FlagPath 280 | } 281 | else { 282 | #bail out 283 | Return 284 | } 285 | } 286 | ``` 287 | 288 | In a different PowerShell session you'll get a result like this: 289 | 290 | ```dos 291 | PS C:\> Start-PSClock 292 | 293 | WARNING: A running clock has been detected from another PowerShell session on this desktop: 294 | 295 | [3/31/2025 12:17:52 PM] PSClock started by Jeff under PowerShell process id 54672 296 | 297 | If this is incorrect, delete C:\Users\Jeff\AppData\Local\Temp\psclock-flag.txt and try again. 298 | ``` 299 | 300 | The `_Quit` private function in `Start-PSClock` should delete this file. 301 | 302 | ```powershell 303 | if (Test-Path $FlagPath) { 304 | Remove-Item $FlagPath 305 | } 306 | ``` 307 | 308 | But, if the PowerShell session closes without stopping the clock, this code won't run and the flag file will remain. In this situation, you need to manually delete the file, as the warning instructs. 309 | 310 | If you try to start another clock in the same session, `Start-PSClock` tests to see if one is already running. 311 | 312 | ```powershell 313 | if ($PSClockSettings.Running) { 314 | Write-Warning "You already have a clock running. You can only have one clock running at a time." 315 | Return 316 | } 317 | ``` 318 | 319 | ## Save-PSClock 320 | 321 | One of the design goals was to make it easy to start a clock using the last used settings. Granted, it wouldn't be that difficult to add a `Start-PSClock` command to a PowerShell profile script with all the parameters. But, I'd have to modify the profile script every time I decided to tweak a setting. Instead, `Save-PSClock` will export key properties to an XML file using `Export-Clixml`. 322 | 323 | In the module file, a module-scoped variable is defined for the export path. 324 | 325 | ```powershell 326 | $SavePath = Join-Path -Path $home -ChildPath PSClockSettings.xml 327 | ``` 328 | 329 | The `PSClockSettings.xml` will be stored in `$HOME`. Because I'm going to use the values from the `$PSClockSettings` synchronized hashtable with `Start-PSClock`, I need to "align" the property names. 330 | 331 | ```powershell 332 | $props = @{Name="DateFormat";Expression={$_.Format}},"Color", 333 | @{Name="FontSize";Expression={$_.Size}}, 334 | @{Name="FontWeight";Expression={$_.weight}},"FontFamily", 335 | @{Name="FontStyle";Expression={$_.Style}},"OnTop", 336 | @{Name="Position";Expression = {$_.CurrentPosition}} 337 | ``` 338 | 339 | This array is then used with `Select-Object` to export the custom properties. 340 | 341 | ```powershell 342 | Get-PSClock | Select-Object -property $props | Export-Clixml -Path $SavePath 343 | ``` 344 | 345 | In `Start-PSClock`, there is a test for the xml file. If found, it is imported and the values assigned to the function's parameters. 346 | 347 | ```powershell 348 | if ((Test-Path $SavePath)-AND (-not $Force)) { 349 | Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Using saved settings" 350 | $import = Import-Clixml -Path $SavePath 351 | foreach ($prop in $import.PSObject.properties) { 352 | Write-Verbose "[$((Get-Date).TimeOfDay) PROCESS] Using imported value for $($prop.name)" 353 | Set-Variable -name $prop.name -value $prop.Value 354 | } 355 | } 356 | ``` 357 | 358 | In a function, each parameter becomes an internal variable. I can use `Set-Variable` to assign values to the parameters. 359 | 360 | The initial design concept was that if the user specified any parameter value, then the saved file would be skipped. This proved to be too cumbersome. Instead, I opted for a `-Force` parameter. This allows the user to specify parameter values, or use the defaults and ignore any saved settings. The saved settings file will not be deleted in this situation. If you no longer wish to use the saved settings file, you can manually delete it. 361 | 362 | ## Formatting 363 | 364 | The only true object that this module generates is from `Get-PSClock`. This function makes it easier to interact with the `$PSClockSettings` synchronized hashtable. Instead of writing a hashtable to the pipeline, the command creates a custom object. 365 | 366 | ```powershell 367 | [PSCustomObject]@{ 368 | PSTypeName = "PSClock" 369 | Started = $global:PSClockSettings.Started 370 | Format = $global:PSClockSettings.DateFormat 371 | Output = (Get-Date -Format $global:PSClockSettings.DateFormat) 372 | Running = $global:PSClockSettings.Running 373 | FontFamily = $global:PSClockSettings.FontFamily 374 | Size = $global:PSClockSettings.fontSize 375 | Weight = $global:PSClockSettings.FontWeight 376 | Color = $global:PSClockSettings.Color 377 | Style = $global:PSClockSettings.FontStyle 378 | OnTop = $global:PSClockSettings.OnTop 379 | CurrentPosition = $global:PSClockSettings.CurrentPosition 380 | RunspaceID = $global:PSClockSettings.Runspace.id 381 | } 382 | ``` 383 | 384 | The `PSTypeName` entry defines an object type. 385 | 386 | ```dos 387 | PS C:\> Get-PSClock | Get-Member 388 | 389 | TypeName: PSClock 390 | 391 | Name MemberType Definition 392 | ---- ---------- ---------- 393 | Equals Method bool Equals(System.Object obj) 394 | GetHashCode Method int GetHashCode() 395 | GetType Method type GetType() 396 | ToString Method string ToString() 397 | Color NoteProperty string Color=Yellow 398 | CurrentPosition NoteProperty Object[] CurrentPosition=System.Object[] 399 | FontFamily NoteProperty string FontFamily=Freestyle Script 400 | Format NoteProperty string Format=F 401 | OnTop NoteProperty switch OnTop=False 402 | Output NoteProperty System.String Output=Monday, March 31, 2025 10:42:19 AM 403 | Running NoteProperty bool Running=True 404 | RunspaceID NoteProperty int RunspaceID=46 405 | Size NoteProperty int Size=65 406 | Started NoteProperty System.DateTime Started=3/31/2025 10:34:48 AM 407 | Style NoteProperty string Style=Normal 408 | Weight NoteProperty string Weight=Normal 409 | ``` 410 | 411 | The object is defined with all the properties I might ever want to use. However, I only need to see a subset in most cases. This is no different than a command like `Get-Process`. The process object is very rich, but the command output provide a formatted view. I can do the same thing, but only if the object has a defined name, like `PSClock`. 412 | 413 | I used the [New-PSFormatXML](https://jdhitsolutions.com/yourls/c8dc45) command from the [PSScriptTools](https://github.com/jdhitsolutions/PSScriptTools) module. This generated a format ps1xml file which is exported in the module manifest. 414 | 415 | ```powershell 416 | FormatsToProcess = @('formats\psclock.format.ps1xml') 417 | ``` 418 | 419 | I tweaked the file to get the output I wanted. One change I made was to use ANSI formatting to highlight if a clock was not running. 420 | 421 | ```xml 422 | 423 | 424 | if ($host.name -match "console|code" -AND (-Not $_.Running)) { 425 | "$([char]27)[91m$($_.Running)$([char]27)[0m" 426 | } 427 | else { 428 | $_.Running 429 | } 430 | 431 | 432 | ``` 433 | 434 | ![Get-PSClock](images/get-psclock.png) 435 | 436 | ## AutoCompletion 437 | 438 | The last major design element is the use of auto-completion. I wanted tab completion for the font family and color parameters in `Start-PSClock` and `Set-PSClock`. 439 | 440 | ```powershell 441 | Register-ArgumentCompleter -CommandName 'Start-PSClock', 'Set-PSClock' -ParameterName 'FontFamily' -ScriptBlock { 442 | param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) 443 | 444 | [System.Drawing.Text.InstalledFontCollection]::new().Families.Name | 445 | Where-Object { $_ -like "$($WordToComplete)*" } | 446 | ForEach-Object { 447 | # completion text,listitem text,result type,Tooltip 448 | [System.Management.Automation.CompletionResult]::new("'$($_)'", $_, 'ParameterValue', $_) 449 | } 450 | } 451 | 452 | Register-ArgumentCompleter -CommandName 'Start-PSClock', 'Set-PSClock' -ParameterName 'Color' -ScriptBlock { 453 | param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) 454 | 455 | [System.Drawing.Brushes].GetProperties().name | Select-Object -Skip 1 | 456 | Where-Object { $_ -Like "$($WordToComplete)*" } | 457 | ForEach-Object { 458 | # completion text,listitem text,result type,Tooltip 459 | [System.Management.Automation.CompletionResult]::new("'$($_)'", $_, 'ParameterValue', $_) 460 | } 461 | } 462 | ``` 463 | 464 | The script block gets values from the .NET Framework and pipes to `Where-Object` so that I can use the `$WordToComplete` variable which allows me to start typing part of a value and then press tab. 465 | 466 | For example, I can type `r` as a value for `FontFamily` then press tab to see all the possible values. 467 | 468 | ![tab completion](images/tab-complete-example.png) 469 | 470 | Or, I can press tab and cycle through all of the settings. 471 | 472 | Some of the parameters in `Start-PSClock` have parameter validation using `ValidateSet()` 473 | 474 | ```powershell 475 | [Parameter(HelpMessage = "Specify a font style.", ValueFromPipelineByPropertyName)] 476 | [ValidateSet("Normal", "Italic", "Oblique")] 477 | [alias("style")] 478 | [string]$FontStyle = "Normal", 479 | ``` 480 | 481 | This too, provides an auto-completion experience. 482 | 483 | ## Custom Verbose 484 | 485 | Localized string data and custom verbose messaging was introduced in module version 1.5.0. This centralizes the string data and makes it easier to localize. The strings are stored in a hashtable in `en-us\PSClock.psd1`. 486 | 487 | ```powershell 488 | ConvertFrom-StringData @" 489 | SynchHash = Building a synchronized hashtable 490 | CantFind = Cant find a running PSClock. Do you need to start one? 491 | CreatingFlag = Creating the flag file {0} 492 | DefiningRunspace = Defining the runspace command 493 | DefiningWPF = Defining the WPF form and controls 494 | Detected = Detected PowerShell host: {0} 495 | ... 496 | "@ 497 | 498 | This data is loaded on module import. 499 | 500 | ```powershell 501 | if ((Get-Culture).Name -match '\w+') { 502 | Import-LocalizedData -BindingVariable strings 503 | } 504 | else { 505 | #force using En-US if no culture found, which might happen on non-Windows systems. 506 | Import-LocalizedData -BindingVariable strings -FileName PSClock.psd1 -BaseDirectory $PSScriptRoot\en-us 507 | } 508 | ``` 509 | 510 | The functions use this string data for verbose messages and warning. 511 | 512 | ```powershell 513 | _verbose ($strings.Starting -f $MyInvocation.MyCommand) 514 | _verbose ($strings.Running -f $PSVersionTable.PSVersion) 515 | _verbose ($strings.Detected -f $Host.Name) 516 | ``` 517 | 518 | The module uses a custom and private function called `_verbose` to display the verbose messages. 519 | 520 | ```powershell 521 | function _verbose { 522 | [CmdletBinding()] 523 | Param([string]$Message) 524 | 525 | $m = "[$([char]27)[3m{0}$([char]27)[0m] {1}" -f (Get-Date).TimeOfDay, $Message 526 | Microsoft.PowerShell.Utility\Write-Verbose $m 527 | } 528 | ``` 529 | 530 | ![custom verbose messages](images/custom-verbose.png) 531 | 532 | ## Learn More 533 | 534 | ![PowerShell Scripting and Toolmaking](images/pstoolmaking-thumbnail.png) 535 | 536 | If you feel that your PowerShell scripting skills need a boost, I'm assuming you've first read [_Learn PowerShell Scripting in a Month of Lunches_](https://www.manning.com/books/learn-powershell-scripting-in-a-month-of-lunches?a_aid=jdhit&a_bid=2326a8ab). If so, then I suggest getting a copy of the [PowerShell Scripting and Toolmaking Book](https://leanpub.com/powershell-scripting-toolmaking/). Don Jones and I wrote this book intending it to be the definitive guide on everything you need to know to be a better PowerShell scripter and toolmaker. 537 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021-2025 JDH Information Technology Solutions, Inc. 2 | 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /PSClock.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'PSClock' 3 | 4 | @{ 5 | RootModule = 'PSClock.psm1' 6 | ModuleVersion = '1.5.0' 7 | CompatiblePSEditions = @('Desktop', 'Core') 8 | GUID = '668afa48-5176-4fd0-bd0f-e414155c6da3' 9 | Author = 'Jeff Hicks' 10 | CompanyName = 'JDH Information Technology Solutions, Inc.' 11 | Copyright = '2021-2025 JDH Information Technology Solutions, Inc.' 12 | Description = 'A set of PowerShell commands for creating and managing a WPF-based clock that runs on your Windows desktop.' 13 | PowerShellVersion = '5.1' 14 | RequiredModules = @('Microsoft.PowerShell.ThreadJob') 15 | RequiredAssemblies = @('PresentationFramework', 'PresentationCore', 'System.Drawing') 16 | FormatsToProcess = @('formats\psclock.format.ps1xml') 17 | FunctionsToExport = @( 18 | 'Start-PSClock', 19 | 'Set-PSClock', 20 | 'Get-PSClock', 21 | 'Stop-PSClock', 22 | 'Save-PSClock', 23 | 'Show-FontPreview', 24 | 'Show-PSClockSettingPreview', 25 | 'Get-PrimaryDisplaySize' 26 | ) 27 | VariablesToExport = 'PSClockSettings' 28 | AliasesToExport = @('psclock','gpc','spc') 29 | PrivateData = @{ 30 | PSData = @{ 31 | Tags = @("clock", "wpf", "windows","time") 32 | LicenseUri = 'https://github.com/jdhitsolutions/PSClock/blob/main/LICENSE.txt' 33 | ProjectUri = 'https://github.com/jdhitsolutions/PSClock' 34 | IconUri = 'https://raw.githubusercontent.com/jdhitsolutions/PSClock/master/images/psclock.png' 35 | RequireLicenseAcceptance = $false 36 | } 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /PSClock.psm1: -------------------------------------------------------------------------------- 1 | #Turn on additional verbose messaging when importing the module 2 | if ($MyInvocation.line -match '-verbose') { 3 | $VerbosePreference = 'Continue' 4 | $manifest = Import-PowerShellDataFile $PSScriptRoot\PSClock.psd1 5 | Write-Verbose "Importing module version $($manifest.ModuleVersion)" 6 | } 7 | 8 | Write-Verbose 'Defining string data' 9 | if ((Get-Culture).Name -match '\w+') { 10 | Import-LocalizedData -BindingVariable strings 11 | } 12 | else { 13 | #force using En-US if no culture found, which might happen on non-Windows systems. 14 | Import-LocalizedData -BindingVariable strings -FileName PSClock.psd1 -BaseDirectory $PSScriptRoot\en-us 15 | } 16 | 17 | Write-Verbose 'Sourcing functions: ' 18 | Get-ChildItem -Path $PSScriptRoot\functions\*.ps1 | 19 | ForEach-Object { 20 | Write-Verbose $_.FullName 21 | . $_.FullName 22 | } 23 | 24 | #define module-scoped variables the path for Save-PSClock 25 | $SavePath = Join-Path -Path $home -ChildPath PSClockSettings.xml 26 | $FlagPath = Join-Path -Path $env:temp -ChildPath psclock-flag.txt 27 | 28 | Write-Verbose "Using save path $SavePath" 29 | Write-Verbose "Using flag file path $FlagPath" 30 | 31 | Write-Verbose 'Registering argument completer for FontFamily' 32 | Register-ArgumentCompleter -CommandName 'Start-PSClock', 'Set-PSClock' -ParameterName 'FontFamily' -ScriptBlock { 33 | param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) 34 | 35 | [System.Drawing.Text.InstalledFontCollection]::new().Families.Name | 36 | Where-Object { $_ -like "$($WordToComplete)*" } | 37 | ForEach-Object { 38 | # completion text,listItem text,result type,Tooltip 39 | [System.Management.Automation.CompletionResult]::new("'$($_)'", $_, 'ParameterValue', $_) 40 | } 41 | } 42 | 43 | Write-Verbose 'Registering argument completer for Color' 44 | Register-ArgumentCompleter -CommandName 'Start-PSClock', 'Set-PSClock' -ParameterName 'Color' -ScriptBlock { 45 | param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) 46 | 47 | #skipping Transparent as a font color 48 | [System.Drawing.Brushes].GetProperties().name | 49 | Select-Object -Skip 1 | 50 | Where-Object { $_ -Like "$($WordToComplete)*" } | 51 | ForEach-Object { 52 | #show the color name using the color 53 | $ansi = Get-RGB $_ | Convert-RGBtoAnsi 54 | [String]$show = "$ansi$($_)$([char]27)[0m" 55 | # completion text,listItem text,result type,Tooltip 56 | [System.Management.Automation.CompletionResult]::new("'$($_)'", $show, 'ParameterValue', $_) 57 | } 58 | } 59 | 60 | 61 | if ($VerbosePreference -eq 'Continue') { 62 | $VerbosePreference = 'SilentlyContinue' 63 | } 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PSClock 2 | 3 | ![PSGallery Version](https://img.shields.io/powershellgallery/v/PSClock.png?style=for-the-badge&logo=powershell&label=PowerShell%20Gallery)![PSGallery Downloads](https://img.shields.io/powershellgallery/dt/PSClock.png?style=for-the-badge&label=Downloads) 4 | 5 | ![logo](images/psclock.png) 6 | 7 | This module will create a WPF-based clock, launched from a PowerShell prompt that on your Windows desktop. The clock runs in a background PowerShell runspace so that it doesn't block. The module will automatically clean up the runspace when you close the clock. You can customize the clock's appearance including how you want to format the date and time. The clock's background is transparent so all you see is formatted text. 8 | 9 | ## Installation 10 | 11 | If you are running Windows, you can install the module from the PowerShell Gallery. This module will work in Windows PowerShell and PowerShell 7 on Windows. 12 | 13 | ```powershell 14 | Install-PSResource PSClock [-scope AllUsers] 15 | ``` 16 | 17 | Installing the module will also install the `Microsoft.PowerShell.ThreadJob` module if it isn't already installed. If you attempt to install the module with `Install-Module` and you have the legacy `ThreadJob` module installed, you might get a warning message. If this happens, run `Install-Module PSClock -AllowClobber`. This error doesn't seem to happen when using `Install-PSResource`. 18 | 19 | ## Module Commands 20 | 21 | | Name | Alias | Synopsis | 22 | |-------------------------------|-------------|----------------------------------------------| 23 | | [Get-PrimaryDisplaySize](docs/Get-PrimaryDisplaySize.md) | | Get the primary display size in pixels. | 24 | | [Get-PSClock](docs/Get-PSClock.md) | *gpc* | Get PSClock details. | 25 | | [Save-PSClock](docs/Save-PSClock.md) | | Save current PSClock settings to a file. | 26 | | [Set-PSClock](docs/Set-PSClock.md) | *spc* | Modify a running PSClock. | 27 | | [Show-FontPreview](docs/Show-FontPreview.md) | | Show a font preview in a WPF form. | 28 | | [Show-PSClockSettingPreview](docs/Show-PSClockSettingPreview.md) | | Show a GUI preview of PSClock settings. | 29 | | [Start-PSClock](docs/Start-PSClock.md) | *psclock* | Start a PSClock. | 30 | | [Stop-PSClock](docs/Stop-PSClock.md) | | Stop a running PSClock. | 31 | 32 | ### [Start-PSClock](docs/Start-PSClock.md) 33 | 34 | Use `Start-PSClock` or the `psclock` alias to launch a PSClock. 35 | 36 | ```powershell 37 | Start-PSClock -size 24 -FontFamily 'Bahnschrift Light' 38 | ``` 39 | 40 | The font size must be at least 8. You should have tab completion for the `Color`, `FontFamily`, and other font-related parameters. 41 | 42 | By default, the clock will be displayed on the center of your screen. You can click and drag the clock to reposition using the left mouse button. You might have to try a few times to "grab" the clock. You can close the clock with a right click or the `Stop-PSClock` command. 43 | 44 | The command lets you specify any `DateTime` format string. This is the same value you would use in a command like `Get-Date -format U`. Note that these strings are case-sensitive. See https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings for more information. 45 | 46 | ```powershell 47 | Start-PSClock -size 30 -Color Yellow -format G -FontFamily Verdana 48 | ``` 49 | 50 | ![format G](images/sample-2.png) 51 | 52 | ### [Save-PSClock](docs/Save-PSClock.md) 53 | 54 | You can use `Save-PSClock` to export current clock settings to an XML file. 55 | 56 | ```powershell 57 | Save-PSClock 58 | ``` 59 | 60 | The file, `PSClockSettings.xml`, will be stored in `$HOME`. If the file is detected when you run `Start-PSClock`, the saved settings will be imported. If the file exists and you want to specify new settings, use the `-Force` parameter with `Start-PSClock`. This will not remove the saved settings file, only ignore it. 61 | 62 | You need to manually delete the file if you no longer wish to use it. If you uninstall the module you will also need to manually delete the file. 63 | 64 | ### [Get-PSClock](docs/Get-PSClock.md) 65 | 66 | Use this command to get information about the current clock. 67 | 68 | ```cmd 69 | PS C:\> Get-PSClock 70 | 71 | Running Format FontFamily Size Weight Color Style OnTop RunspaceID 72 | ------- ------ ---------- ---- ------ ----- ----- ----- ---------- 73 | True G Verdana 30 Normal Yellow Normal False 24 74 | ``` 75 | 76 | If the clock is not running, the `Running` value will be displayed in Red and there will be no `RunspaceID`. There are other properties to this object you might want to use. 77 | 78 | ```cmd 79 | Started : 3/30/2025 10:57:30 AM 80 | Format : G 81 | Output : 3/30/2025 10:59:49 AM 82 | Running : True 83 | FontFamily : Verdana 84 | Size : 30 85 | Weight : Normal 86 | Color : Yellow 87 | Style : Normal 88 | OnTop : False 89 | CurrentPosition : {1729, 552} 90 | RunspaceID : 24 91 | ``` 92 | 93 | The `Output` property is a sample using the specified format string. 94 | 95 | ### [Set-PSClock](docs/Set-PSClock.md) 96 | 97 | Use this command to modify the settings of a running PSClock. 98 | 99 | ```powershell 100 | Set-PSClock -size 30 -color white -FontFamily 'Baskerville Old Face' -force 101 | ``` 102 | 103 | ![modify the clock](images/sample-3.png) 104 | 105 | You can also increase the size by selecting the clock and using the + key. Decrease using the - key. Each change takes a second to be applied. You might need to "grab" the clock and move it slightly to ensure you have it selected. 106 | 107 | If you only want to change the color, you can use PSReadLine to display a formatted list of color options. After the `-Color` parameter, press Ctrl+Space and answer `Y`. 108 | 109 | ![PSReadLine completion](images/set-psclock-color.png) 110 | 111 | Move the cursor to your selected choice and press Enter. 112 | 113 | ### Settings Preview Form 114 | 115 | Version 1.4.0 updates the PSClock and allows you to configure the font family, style, and color via a WPF-based GUI. Select the clock and press `p` to display the form. The form elements have tooltips that explain each setting. Hover your mouse over the element to see the tooltip. 116 | 117 | ![show settings preview](images/psclock-preview.png) 118 | 119 | You can select a combination of font elements and view the preview. If you want to apply the new settings, click the `Apply` button. Don't forget to run `Save-PSClock` to save the settings if you want to re-use them the next time you start a clock. 120 | 121 | You can also run `Show-PSClockSettingPreview`. 122 | 123 | If you don't want to apply and changes, close the form. 124 | 125 | ### [Stop-PSClock](docs/Stop-PSClock.md) 126 | 127 | Use this command to stop a running PSClock from the PowerShell prompt. 128 | 129 | ```powershell 130 | Stop-PSClock 131 | ``` 132 | 133 | You can also right-click the clock to dismiss it, or close and remove the runspace it is using. You can still use `Get-PSClock` which should now reflect that a clock is not running. 134 | 135 | ```cmd 136 | PS C:\> Get-PSClock 137 | 138 | Running Format FontFamily Size Weight Color Style OnTop RunspaceID 139 | ------- ------ ---------- ---- ------ ----- ----- ----- ---------- 140 | False G Baskerville Old Face 30 Normal white Normal False 141 | ``` 142 | 143 | ## Profile Integration 144 | 145 | Ideally, you will start and stop the PSClock from the PowerShell prompt. This ensures that the flag file is removed. When you terminate a PowerShell session with a running clock, the flag file will not be removed. One way to ensure that the clock is stopped is to add the following code to your PowerShell profile. This will remove the flag file when you end the PowerShell session. 146 | 147 | ```powershell 148 | Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action { 149 | If ($PSClockSettings.Running) { 150 | $flag = "$ENV:temp\psclock-flag.txt" 151 | If (Test-Path $flag) { 152 | Remove-Item $flag -Force 153 | } 154 | Stop-PSClock 155 | } 156 | } | Out-Null 157 | ``` 158 | 159 | However, this will only run if you type `exit` to terminate the session. If you simply close the window, the `PowerShell.Exiting` event will not be triggered. You can also add the code to your profile to automatically start the clock when you open a new PowerShell session. In Windows Terminal, you still might need to manually close the profile tab once you see that the clock has ended. 160 | 161 | ## Runspaces and Limitations 162 | 163 | The clock runs in a separate runspace launched from your PowerShell session. If you close the session, the clock will also be closed. 164 | 165 | The command is designed to only have one clock running at a time. If you try to start another clock from another PowerShell session, you will get a warning. 166 | 167 | ```cmd 168 | PS C:\> Start-PSClock 169 | WARNING: 170 | A running clock has been detected from another PowerShell session: 171 | 172 | [3/30/2025 11:00:36 AM] PSClock started by Jeff under PowerShell process id 46900 173 | 174 | If this is incorrect, delete C:\Users\Jeff\AppData\Local\Temp\psclock-flag.txt and try again. 175 | 176 | Do you want to remove the flag file? Y/N: 177 | ``` 178 | 179 | If you close PowerShell without properly shutting down the clock you may be left with the flag file. Delete the file and try again. 180 | 181 | ## Font Preview 182 | 183 | This module also includes a font preview utility. Run `Show-FontPreview` to display a WPF form that will let you preview different fonts. 184 | 185 | ![font preview](images/show-fontpreview.png) 186 | 187 | You can use the arrow keys or buttons to navigate through the fonts. Press Ctrl+Q to quit or manually close the form. 188 | 189 | ## Module Design 190 | 191 | For more details about the module design and technical implementation, read the [design document](Design.md). 192 | 193 | ## Related Modules 194 | 195 | For a WPF-based countdown timer, take a look at the [Start-PSCountdownTimer](https://bit.ly/3T5ntz1) command in the [PSTimers](https://github.com/jdhitsolutions/PSTimers) module. 196 | 197 | ## Known Issues 198 | 199 | There are no known issues at this time. Please post any bugs or feature requests in the [Issues](https://github.com/jdhitsolutions/PSClock/issues) section of this repository. 200 | -------------------------------------------------------------------------------- /docs/Get-PSClock.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSClock-help.xml 3 | Module Name: PSClock 4 | online version: https://jdhitsolutions.com/yourls/747a96 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-PSClock 9 | 10 | ## SYNOPSIS 11 | 12 | Get PSClock details. 13 | 14 | ## SYNTAX 15 | 16 | ```yaml 17 | Get-PSClock [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | This command will provide detailed information about a PSClock. 23 | 24 | ## EXAMPLES 25 | 26 | ### Example 1 27 | 28 | ```powershell 29 | PS C:\> Get-PSClock 30 | 31 | Running Format FontFamily Size Weight Color Style OnTop RunspaceID 32 | ------- ------ ---------- ---- ------ ----- ----- ----- ---------- 33 | True F Segoi UI 30 Normal yellow Normal False 62 34 | ``` 35 | 36 | Get details about the currently running clock. 37 | 38 | ### Example 2 39 | 40 | ```powershell 41 | PS C:\> Get-PSClock | Select * 42 | 43 | Started : 11/7/2024 4:18:30 PM 44 | Format : F 45 | Output : Thursday, November 7, 2024 4:26:18 PM 46 | Running : True 47 | FontFamily : Segoi UI 48 | Size : 30 49 | Weight : Normal 50 | Color : yellow 51 | Style : Normal 52 | OnTop : False 53 | CurrentPosition : {1635, 1089} 54 | RunspaceID : 62 55 | ``` 56 | 57 | Get all details about the current clock. 58 | 59 | ## PARAMETERS 60 | 61 | ### CommonParameters 62 | 63 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 64 | 65 | ## INPUTS 66 | 67 | ### None 68 | 69 | ## OUTPUTS 70 | 71 | ### PSClock 72 | 73 | ## NOTES 74 | 75 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 76 | 77 | ## RELATED LINKS 78 | 79 | [Set-PSClock](Set-PSClock.md) 80 | 81 | [Start-PSClock](Start-PSClock.md) 82 | 83 | [Stop-PSClock](Stop-PSClock.md) 84 | 85 | [Save-PSClock](Save-PSClock.md) 86 | -------------------------------------------------------------------------------- /docs/Get-PrimaryDisplaySize.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSClock-help.xml 3 | Module Name: PSClock 4 | online version: https://jdhitsolutions.com/yourls/e9e07f 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-PrimaryDisplaySize 9 | 10 | ## SYNOPSIS 11 | 12 | Get the primary display size in pixels. 13 | 14 | ## SYNTAX 15 | 16 | ```yaml 17 | Get-PrimaryDisplaySize [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | When positioning the PSClock, or any WPF form, you might need to know the dimension of your display. 23 | 24 | ## EXAMPLES 25 | 26 | ### Example 1 27 | 28 | ```powershell 29 | PS C:\> Get-PrimaryDisplaySize 30 | 31 | Width Height WorkArea 32 | ----- ------ -------- 33 | 1536.00 864.00 0,0,1536,816 34 | ``` 35 | 36 | These values are different than $host.UI.RawUI.WindowSize.Width and $host.UI.RawUI.WindowSize.Height. The $host values are dimensions of the console window, not the display screen. 37 | 38 | ### Example 2 39 | 40 | ```powershell 41 | PS C:\> Get-PrimaryDisplaySize | Select-Object -ExpandProperty WorkArea 42 | 43 | IsEmpty : False 44 | Location : 0,0 45 | Size : 1536,816 46 | X : 0 47 | Y : 0 48 | Width : 1536 49 | Height : 816 50 | Left : 0 51 | Top : 0 52 | Right : 1536 53 | Bottom : 816 54 | TopLeft : 0,0 55 | TopRight : 1536,0 56 | BottomLeft : 0,816 57 | BottomRight : 1536,816 58 | ``` 59 | 60 | ## PARAMETERS 61 | 62 | ### CommonParameters 63 | 64 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 65 | 66 | ## INPUTS 67 | 68 | ### None 69 | 70 | ## OUTPUTS 71 | 72 | ### PSPrimaryDisplaySize 73 | 74 | ## NOTES 75 | 76 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 77 | 78 | ## RELATED LINKS 79 | -------------------------------------------------------------------------------- /docs/Save-PSClock.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSClock-help.xml 3 | Module Name: PSClock 4 | online version: https://jdhitsolutions.com/yourls/9116fc 5 | schema: 2.0.0 6 | --- 7 | 8 | # Save-PSClock 9 | 10 | ## SYNOPSIS 11 | 12 | Save current PSClock settings to a file. 13 | 14 | ## SYNTAX 15 | 16 | ```yaml 17 | Save-PSClock [-Passthru] [-WhatIf] [-Confirm] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | This command will export the settings for a PSClock to an xml file,using Export-CliXML. The file PSClockSettings.xml will be created in $HOME. The next time you run Start-PSClock, if this file is detected, the settings will be imported and used for the clock unless you use -Force. If you no longer wish to use the saved settings, you can manually delete the file. 23 | 24 | The clock does not have to be running in order to export the settings. 25 | 26 | ## EXAMPLES 27 | 28 | ### Example 1 29 | 30 | ```powershell 31 | PS C:\> Save-PSClock 32 | ``` 33 | 34 | Save current settings to $HOME\PSClockSettings.xml. 35 | 36 | ### Example 2 37 | 38 | ```powershell 39 | PS C:\> Save-PSClock -passthru 40 | 41 | Directory: C:\Users\Jeff 42 | 43 | 44 | Mode LastWriteTime Length Name 45 | ---- ------------- ------ ---- 46 | -a--- 3/30/2025 2:26 PM 1123 󰗀 PSClockSettings.xml 47 | ``` 48 | 49 | Save current settings and display the file. 50 | 51 | ## PARAMETERS 52 | 53 | ### -Confirm 54 | 55 | Prompts you for confirmation before running the cmdlet. 56 | 57 | ```yaml 58 | Type: SwitchParameter 59 | Parameter Sets: (All) 60 | Aliases: cf 61 | 62 | Required: False 63 | Position: Named 64 | Default value: None 65 | Accept pipeline input: False 66 | Accept wildcard characters: False 67 | ``` 68 | 69 | ### -WhatIf 70 | 71 | Shows what would happen if the cmdlet runs. 72 | The cmdlet is not run. 73 | 74 | ```yaml 75 | Type: SwitchParameter 76 | Parameter Sets: (All) 77 | Aliases: wi 78 | 79 | Required: False 80 | Position: Named 81 | Default value: None 82 | Accept pipeline input: False 83 | Accept wildcard characters: False 84 | ``` 85 | 86 | ### -Passthru 87 | 88 | Display the file with saved settings. 89 | 90 | ```yaml 91 | Type: SwitchParameter 92 | Parameter Sets: (All) 93 | Aliases: 94 | 95 | Required: False 96 | Position: Named 97 | Default value: None 98 | Accept pipeline input: False 99 | Accept wildcard characters: False 100 | ``` 101 | 102 | ### CommonParameters 103 | 104 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 105 | 106 | ## INPUTS 107 | 108 | ### None 109 | 110 | ## OUTPUTS 111 | 112 | ### None 113 | 114 | ## NOTES 115 | 116 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 117 | 118 | ## RELATED LINKS 119 | 120 | [Start-PSClock](Start-PSClock.md) 121 | 122 | [Get-PSClock](Get-PSClock.md) 123 | -------------------------------------------------------------------------------- /docs/Set-PSClock.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSClock-help.xml 3 | Module Name: PSClock 4 | online version: https://jdhitsolutions.com/yourls/98a370 5 | schema: 2.0.0 6 | --- 7 | 8 | # Set-PSClock 9 | 10 | ## SYNOPSIS 11 | 12 | Modify a running PSClock. 13 | 14 | ## SYNTAX 15 | 16 | ```yaml 17 | Set-PSClock [[-Color] ] [[-DateFormat] ] [-FontSize ] [-FontStyle ] 18 | [-FontWeight ] [-FontFamily ] [-OnTop] [-CurrentPosition ] [-PassThru] [-WhatIf] [-Confirm] [] 19 | ``` 20 | 21 | ## DESCRIPTION 22 | 23 | Use this command to modify the settings of a running PSClock. You can also increase the size by selecting the clock and use the + key. Decrease using the - key. Each change takes a second to be applied. You might need to "grab" the clock and move it slightly to ensure you have it selected. 24 | 25 | If you want to change the position, left-click and drag to re-position. 26 | 27 | ## EXAMPLES 28 | 29 | ### Example 1 30 | 31 | ```powershell 32 | PS C:\> Set-PSClock -size 28 -FontStyle Oblique -FontFamily 'Tahoma' 33 | ``` 34 | 35 | ### Example 36 | 37 | ```powershell 38 | PS C:\> Set-PSClock -size 35 -Position 500,100 39 | ``` 40 | 41 | Adjust the font size and clock position. This example is using the Position parameter alias. 42 | 43 | ## PARAMETERS 44 | 45 | ### -Color 46 | 47 | Specify a font color like Green or an HTML code like '#FF1257EA'. You can also use any [System.Drawing.Brushes] color like Coral or SkyBlue. If you press Ctrl+Space after the parameter, you can use PSReadLine to display options formatted in the corresponding color. 48 | 49 | ```yaml 50 | Type: String 51 | Parameter Sets: (All) 52 | Aliases: 53 | 54 | Required: False 55 | Position: 0 56 | Default value: None 57 | Accept pipeline input: True (ByPropertyName) 58 | Accept wildcard characters: False 59 | ``` 60 | 61 | ### -Confirm 62 | 63 | Prompts you for confirmation before running the cmdlet. 64 | 65 | ```yaml 66 | Type: SwitchParameter 67 | Parameter Sets: (All) 68 | Aliases: cf 69 | 70 | Required: False 71 | Position: Named 72 | Default value: None 73 | Accept pipeline input: False 74 | Accept wildcard characters: False 75 | ``` 76 | 77 | ### -DateFormat 78 | 79 | Specify a .NET format string value like F, or G. 80 | 81 | ```yaml 82 | Type: String 83 | Parameter Sets: (All) 84 | Aliases: format 85 | 86 | Required: False 87 | Position: 1 88 | Default value: None 89 | Accept pipeline input: True (ByPropertyName) 90 | Accept wildcard characters: False 91 | ``` 92 | 93 | ### -FontFamily 94 | 95 | Specify a font family. 96 | 97 | ```yaml 98 | Type: String 99 | Parameter Sets: (All) 100 | Aliases: family 101 | 102 | Required: False 103 | Position: Named 104 | Default value: None 105 | Accept pipeline input: True (ByPropertyName) 106 | Accept wildcard characters: False 107 | ``` 108 | 109 | ### -FontSize 110 | 111 | How large do you want the font size? 112 | 113 | ```yaml 114 | Type: Int32 115 | Parameter Sets: (All) 116 | Aliases: size 117 | 118 | Required: False 119 | Position: Named 120 | Default value: None 121 | Accept pipeline input: True (ByPropertyName) 122 | Accept wildcard characters: False 123 | ``` 124 | 125 | ### -FontStyle 126 | 127 | Specify a font style. Accepted values: Normal, Italic, Oblique 128 | 129 | ```yaml 130 | Type: String 131 | Parameter Sets: (All) 132 | Aliases: style 133 | Accepted values: Normal, Italic, Oblique 134 | 135 | Required: False 136 | Position: Named 137 | Default value: None 138 | Accept pipeline input: True (ByPropertyName) 139 | Accept wildcard characters: False 140 | ``` 141 | 142 | ### -FontWeight 143 | 144 | Specify a font weight. Accepted values: 'Normal', 'Bold', 'Light', 'Medium', 'SemiBold' 145 | 146 | ```yaml 147 | Type: String 148 | Parameter Sets: (All) 149 | Aliases: weight 150 | Accepted values: 'Normal', 'Bold', 'Light', 'Medium', 'SemiBold' 151 | 152 | Required: False 153 | Position: Named 154 | Default value: None 155 | Accept pipeline input: True (ByPropertyName) 156 | Accept wildcard characters: False 157 | ``` 158 | 159 | ### -OnTop 160 | 161 | Should the clock be on top of other applications? 162 | 163 | ```yaml 164 | Type: SwitchParameter 165 | Parameter Sets: (All) 166 | Aliases: 167 | 168 | Required: False 169 | Position: Named 170 | Default value: None 171 | Accept pipeline input: True (ByPropertyName) 172 | Accept wildcard characters: False 173 | ``` 174 | 175 | ### -WhatIf 176 | 177 | Shows what would happen if the cmdlet runs. 178 | The cmdlet is not run. 179 | 180 | ```yaml 181 | Type: SwitchParameter 182 | Parameter Sets: (All) 183 | Aliases: wi 184 | 185 | Required: False 186 | Position: Named 187 | Default value: None 188 | Accept pipeline input: False 189 | Accept wildcard characters: False 190 | ``` 191 | 192 | ### -CurrentPosition 193 | 194 | Specify an array of (X,Y) coordinates for the clock position. Use Get-PrimaryDisplaySize to determine the values. 195 | 196 | ```yaml 197 | Type: Double[] 198 | Parameter Sets: (All) 199 | Aliases: Position 200 | 201 | Required: False 202 | Position: Named 203 | Default value: None 204 | Accept pipeline input: False 205 | Accept wildcard characters: False 206 | ``` 207 | 208 | ### -PassThru 209 | 210 | ```yaml 211 | Type: SwitchParameter 212 | Parameter Sets: (All) 213 | Aliases: 214 | 215 | Required: False 216 | Position: Named 217 | Default value: None 218 | Accept pipeline input: False 219 | Accept wildcard characters: False 220 | ``` 221 | 222 | ### CommonParameters 223 | 224 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 225 | 226 | ## INPUTS 227 | 228 | ### None 229 | 230 | ## OUTPUTS 231 | 232 | ### None 233 | 234 | ## NOTES 235 | 236 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 237 | 238 | ## RELATED LINKS 239 | 240 | [Show-PSClockSettingPreview](Show-PSClockSettingPreview.md) 241 | 242 | [Start-PSClock](Start-PSClock.md) 243 | 244 | [Get-PSClock](Get-PSClock.md) 245 | 246 | [Stop-PSClock](Stop-PSClock.md) 247 | 248 | [Save-PSClock](Save-PSClock.md) 249 | -------------------------------------------------------------------------------- /docs/Show-FontPreview.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSClock-help.xml 3 | Module Name: PSClock 4 | online version: https://jdhitsolutions.com/yourls/b68fcd 5 | schema: 2.0.0 6 | --- 7 | 8 | # Show-FontPreview 9 | 10 | ## SYNOPSIS 11 | 12 | Show a font preview in a WPF form. 13 | 14 | ## SYNTAX 15 | 16 | ```yaml 17 | Show-FontPreview [-SampleText ] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | Use this command to display a preview of a font in a WPF form. This can be useful when you need to see what a font looks like before using it in a clock. You can use the buttons or arrow keys to navigate through the fonts. Press Ctrl+Q to quit or manually close the form. 23 | 24 | ## EXAMPLES 25 | 26 | ### Example 1 27 | 28 | ```powershell 29 | PS C:\> Show-FontPreview 30 | ``` 31 | 32 | Your prompt will be blocked until you close the form. This will display the default sample text 33 | from Get-Date -Format F. 34 | 35 | ### Example 2 36 | 37 | ```powershell 38 | PS C:\> Show-FontPreview -Verbose -SampleText (Get-Date -Format D) 39 | ``` 40 | 41 | Launch the preview form with the current date displayed. You can always modify the text in the text box. 42 | 43 | ## PARAMETERS 44 | 45 | ### -SampleText 46 | 47 | The default text to display. 48 | 49 | ```yaml 50 | Type: String 51 | Parameter Sets: (All) 52 | Aliases: 53 | 54 | Required: False 55 | Position: Named 56 | Default value: $(Get-Date -Format F) 57 | Accept pipeline input: False 58 | Accept wildcard characters: False 59 | ``` 60 | 61 | ### CommonParameters 62 | 63 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 64 | 65 | ## INPUTS 66 | 67 | ### None 68 | 69 | ## OUTPUTS 70 | 71 | ### None 72 | 73 | ## NOTES 74 | 75 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 76 | 77 | ## RELATED LINKS 78 | 79 | [Set-PSClock](Set-PSClock.md) 80 | 81 | [Show-PSClockSettingPreview](Show-PSClockSettingPreview.md) 82 | -------------------------------------------------------------------------------- /docs/Show-PSClockSettingPreview.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSClock-help.xml 3 | Module Name: PSClock 4 | online version: https://jdhitsolutions.com/yourls/9a6ebc 5 | schema: 2.0.0 6 | --- 7 | 8 | # Show-PSClockSettingPreview 9 | 10 | ## SYNOPSIS 11 | 12 | Show a GUI preview of PSClock settings 13 | 14 | ## SYNTAX 15 | 16 | ```yaml 17 | Show-PSClockSettingPreview [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | Use this command to display a GUI preview of the settings that can be applied to a PSClock. The preview text will adjust to the selected font family, weight, style, color and size. Changes will be reflected in the preview box. Click the Apply button to commit the changes to the current clock. If you don't want to apply any changes, close the form. The form elements have tooltips to help you understand what each setting does. Hover your mouse over the element to see the tooltip. 23 | 24 | You can also invoke this command by selecting the PSClock and pressing 'p'. 25 | 26 | If you have a running clock, the form will default to the current clock settings. If you don't have a running clock, the form will use the default settings from Start-PSClock. 27 | 28 | ## EXAMPLES 29 | 30 | ### Example 1 31 | 32 | ```powershell 33 | PS C:\> Show-PSClockSettingPreview 34 | ``` 35 | 36 | Your prompt will be blocked until you close the form. 37 | 38 | ## PARAMETERS 39 | 40 | ### CommonParameters 41 | 42 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 43 | 44 | ## INPUTS 45 | 46 | ### None 47 | 48 | ## OUTPUTS 49 | 50 | ### None 51 | 52 | ## NOTES 53 | 54 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 55 | 56 | ## RELATED LINKS 57 | 58 | [Set-PSClock](Set-PSClock.md) 59 | -------------------------------------------------------------------------------- /docs/Start-PSClock.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSClock-help.xml 3 | Module Name: PSClock 4 | online version: https://jdhitsolutions.com/yourls/0d5ea1 5 | schema: 2.0.0 6 | --- 7 | 8 | # Start-PSClock 9 | 10 | ## SYNOPSIS 11 | 12 | Start a PSClock. 13 | 14 | ## SYNTAX 15 | 16 | ```yaml 17 | Start-PSClock [[-DateFormat] ] [-FontSize ] [-FontStyle ] [-FontWeight ] [-Color ] [-FontFamily ] [-OnTop] [-Position ] [-Force] [-Passthru] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | Start a WPF-based PSClock that will run in a background runspace. The clock will be displayed in the center of the screen. You can click and drag the clock to reposition using the left mouse button. You might have to try a few times to "grab" the clock. You can close the clock with a right-click or the Stop-PSClock command. 23 | 24 | The command lets you specify any datetime format string. This is the same value you would use in a command like Get-Date -format U. Note that these strings are case-sensitive. 25 | 26 | The clock runs in a separate runspace launched from your PowerShell session. If you close the session, the clock will also be closed. 27 | 28 | The command is designed to only have one clock running at a time. If you try to start another clock from another PowerShell session, you will get a warning. 29 | 30 | If you have saved PSClock settings, the exported values will be used unless you use -Force. The saved settings file will not be deleted. 31 | 32 | ## EXAMPLES 33 | 34 | ### Example 1 35 | 36 | ```powershell 37 | PS C:\> Start-PSClock 38 | ``` 39 | 40 | Start a new PSClock using the default parameter values. If you have saved PSClock settings, then those values will be used. 41 | 42 | ### Example 2 43 | 44 | ```powershell 45 | PS C:\> Start-PSClock -size 24 -FontFamily 'Bahnschrift Light' -OnTop 46 | ``` 47 | 48 | Start a clock using specific font settings. The clock will be displayed center screen. It will use the default datetime format string. 49 | 50 | ## PARAMETERS 51 | 52 | ### -Color 53 | 54 | Specify a font color like Green or an HTML code like '#FF1257EA'. You can also use any [System.Drawing.Brushes] color like Coral or SkyBlue. 55 | 56 | ```yaml 57 | Type: String 58 | Parameter Sets: (All) 59 | Aliases: 60 | 61 | Required: False 62 | Position: Named 63 | Default value: White 64 | Accept pipeline input: True (ByPropertyName) 65 | Accept wildcard characters: False 66 | ``` 67 | 68 | ### -DateFormat 69 | 70 | Specify a .NET format string value like F, or G. See https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings for more information. 71 | 72 | ```yaml 73 | Type: String 74 | Parameter Sets: (All) 75 | Aliases: format 76 | 77 | Required: False 78 | Position: 0 79 | Default value: F 80 | Accept pipeline input: True (ByPropertyName) 81 | Accept wildcard characters: False 82 | ``` 83 | 84 | ### -FontFamily 85 | 86 | Specify a font family. 87 | 88 | ```yaml 89 | Type: String 90 | Parameter Sets: (All) 91 | Aliases: family 92 | 93 | Required: False 94 | Position: Named 95 | Default value: Segoi UI 96 | Accept pipeline input: True (ByPropertyName) 97 | Accept wildcard characters: False 98 | ``` 99 | 100 | ### -FontSize 101 | 102 | Specify a font size. 103 | 104 | ```yaml 105 | Type: Int32 106 | Parameter Sets: (All) 107 | Aliases: size 108 | 109 | Required: False 110 | Position: Named 111 | Default value: 18 112 | Accept pipeline input: True (ByPropertyName) 113 | Accept wildcard characters: False 114 | ``` 115 | 116 | ### -FontStyle 117 | 118 | Specify a font style. Accepted values: Normal, Italic, Oblique 119 | 120 | ```yaml 121 | Type: String 122 | Parameter Sets: (All) 123 | Aliases: style 124 | Accepted values: Normal, Italic, Oblique 125 | 126 | Required: False 127 | Position: Named 128 | Default value: Normal 129 | Accept pipeline input: True (ByPropertyName) 130 | Accept wildcard characters: False 131 | ``` 132 | 133 | ### -FontWeight 134 | 135 | Specify a font weight. Accepted values: 'Normal', 'Bold', 'Light', 'Medium', 'SemiBold' 136 | 137 | ```yaml 138 | Type: String 139 | Parameter Sets: (All) 140 | Aliases: weight 141 | Accepted values: 'Normal', 'Bold', 'Light', 'Medium', 'SemiBold' 142 | 143 | Required: False 144 | Position: Named 145 | Default value: Normal 146 | Accept pipeline input: True (ByPropertyName) 147 | Accept wildcard characters: False 148 | ``` 149 | 150 | ### -OnTop 151 | 152 | Do you want the clock to always be on top? 153 | 154 | ```yaml 155 | Type: SwitchParameter 156 | Parameter Sets: (All) 157 | Aliases: 158 | 159 | Required: False 160 | Position: Named 161 | Default value: None 162 | Accept pipeline input: True (ByPropertyName) 163 | Accept wildcard characters: False 164 | ``` 165 | 166 | ### -Passthru 167 | 168 | ```yaml 169 | Type: SwitchParameter 170 | Parameter Sets: (All) 171 | Aliases: 172 | 173 | Required: False 174 | Position: Named 175 | Default value: None 176 | Accept pipeline input: False 177 | Accept wildcard characters: False 178 | ``` 179 | 180 | ### -Force 181 | 182 | Force a new PSClock, ignoring any previously saved settings. The saved settings file will remain. 183 | 184 | ```yaml 185 | Type: SwitchParameter 186 | Parameter Sets: (All) 187 | Aliases: 188 | 189 | Required: False 190 | Position: Named 191 | Default value: None 192 | Accept pipeline input: False 193 | Accept wildcard characters: False 194 | ``` 195 | 196 | ### -Position 197 | 198 | Specify the clock position as an array of left and top values. 199 | 200 | ```yaml 201 | Type: Int32[] 202 | Parameter Sets: (All) 203 | Aliases: 204 | 205 | Required: False 206 | Position: Named 207 | Default value: None 208 | Accept pipeline input: True (ByPropertyName) 209 | Accept wildcard characters: False 210 | ``` 211 | 212 | ### CommonParameters 213 | 214 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 215 | 216 | ## INPUTS 217 | 218 | ### String 219 | 220 | ## OUTPUTS 221 | 222 | ### None 223 | 224 | ### PSClock 225 | 226 | ## NOTES 227 | 228 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 229 | 230 | ## RELATED LINKS 231 | 232 | [Set-PSClock](Set-PSClock.md) 233 | 234 | [Get-PSClock](Get-PSClock.md) 235 | 236 | [Stop-PSClock](Stop-PSClock.md) 237 | 238 | [Save-PSClock](Save-PSClock.md) 239 | 240 | [Get-Date]() 241 | -------------------------------------------------------------------------------- /docs/Stop-PSClock.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: PSClock-help.xml 3 | Module Name: PSClock 4 | online version: https://jdhitsolutions.com/yourls/7ed4f9 5 | schema: 2.0.0 6 | --- 7 | 8 | # Stop-PSClock 9 | 10 | ## SYNOPSIS 11 | 12 | Stop a running PSClock. 13 | 14 | ## SYNTAX 15 | 16 | ```yaml 17 | Stop-PSClock [-WhatIf] [-Confirm] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | Use this command to stop a running PSClock from the PowerShell prompt. You can also right-click the clock to dismiss it, or close and remove the runspace it is using. 23 | 24 | If you close the PowerShell session that launched the clock, the clock will also be closed. Note that this forced closing will not delete the flag file which indicates that a clock is running. The next time you try to start a clock you may see a warning. Delete the specified file and try starting a clock again. 25 | 26 | ## EXAMPLES 27 | 28 | ### Example 1 29 | 30 | ```powershell 31 | PS C:\> Stop-PSClock 32 | ``` 33 | 34 | ## PARAMETERS 35 | 36 | ### -Confirm 37 | 38 | Prompts you for confirmation before running the cmdlet. 39 | 40 | ```yaml 41 | Type: SwitchParameter 42 | Parameter Sets: (All) 43 | Aliases: cf 44 | 45 | Required: False 46 | Position: Named 47 | Default value: None 48 | Accept pipeline input: False 49 | Accept wildcard characters: False 50 | ``` 51 | 52 | ### -WhatIf 53 | 54 | Shows what would happen if the cmdlet runs. 55 | The cmdlet is not run. 56 | 57 | ```yaml 58 | Type: SwitchParameter 59 | Parameter Sets: (All) 60 | Aliases: wi 61 | 62 | Required: False 63 | Position: Named 64 | Default value: None 65 | Accept pipeline input: False 66 | Accept wildcard characters: False 67 | ``` 68 | 69 | ### CommonParameters 70 | 71 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 72 | 73 | ## INPUTS 74 | 75 | ### None 76 | 77 | ## OUTPUTS 78 | 79 | ### None 80 | 81 | ## NOTES 82 | 83 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 84 | 85 | ## RELATED LINKS 86 | 87 | [Set-PSClock](Set-PSClock.md) 88 | 89 | [Get-PSClock](Get-PSClock.md) 90 | 91 | [Start-PSClock](Start-PSClock.md) 92 | -------------------------------------------------------------------------------- /docs/about_psclock.md: -------------------------------------------------------------------------------- 1 | # PSClock 2 | 3 | ## about_psclock 4 | 5 | # SHORT DESCRIPTION 6 | 7 | This module will create a WPF-based clock launched from a PowerShell prompt that runs on your Windows desktop. The clock runs in a background PowerShell runspace so that it doesn't block. You can customize the clock's appearance including how you want to format the date and time. The clock background is transparent so all you see is formatted text. 8 | 9 | # LONG DESCRIPTION 10 | 11 | Use `Start-PSClock` or the `psclock` alias to launch a PSClock. 12 | 13 | ```powershell 14 | PS C:\> Start-PSClock -size 24 -FontFamily 'Bahnschrift Light' 15 | ``` 16 | 17 | The font size must be at least 8. You should have tab completion for the `Color`, `FontFamily`, and other font-related parameters. 18 | 19 | By default, the clock will be displayed on the center of your screen. You can click and drag the clock to reposition using the left mouse button. You might have to try a few times to "grab" the clock. You can close the clock with a right click or the `Stop-PSClock` command. 20 | 21 | The command lets you specify any `DateTime` format string. This is the same value you would use in a command like `Get-Date -format U`. Note that these strings are case-sensitive. See https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings for more information. 22 | 23 | ```powershell 24 | PS C:\> Start-PSClock -size 30 -Color Yellow -format G -FontFamily Verdana 25 | ``` 26 | 27 | ## Get-PSClock 28 | 29 | Use this command to get information about the current clock. 30 | 31 | ```dos 32 | PS C:\> Get-PSClock 33 | 34 | Running Format FontFamily Size Weight Color Style OnTop RunspaceID 35 | ------- ------ ---------- ---- ------ ----- ----- ----- ---------- 36 | True G Verdana 30 Normal Yellow Normal False 28 37 | ``` 38 | 39 | If the clock is not running, the `Running` value will be displayed in Red and there will be no `RunspaceID`. There are other properties to this object you might want to use. 40 | 41 | ```dos 42 | PS C:\> Get-PSClock | Select * 43 | 44 | Started : 11/6/2024 10:47:33 AM 45 | Format : G 46 | Output : 11/6/2024 10:59:08 AM 47 | Running : True 48 | FontFamily : Verdana 49 | Size : 30 50 | Weight : Normal 51 | Color : Yellow 52 | Style : Normal 53 | OnTop : False 54 | CurrentPosition : {1635, 1089} 55 | RunspaceID : 28 56 | ``` 57 | 58 | The `Output` property is a sample using the specified format string. 59 | 60 | ## Stop-PSClock 61 | 62 | Use this command to stop a running PSClock from the PowerShell prompt. 63 | 64 | ```powershell 65 | PS C:\> Stop-PSClock 66 | ``` 67 | 68 | You can also right-click the clock to dismiss it, or close and remove the runspace it is using. You can still use `Get-PSClock` which should now reflect that a clock is not running. 69 | 70 | ```dos 71 | PS C:\> Get-PSClock 72 | 73 | Running Format FontFamily Size Weight Color Style OnTop RunspaceID 74 | ------- ------ ---------- ---- ------ ----- ----- ----- ---------- 75 | False G Baskerville Old Face 30 Normal white Normal False 76 | ``` 77 | 78 | ## Set-PSClock 79 | 80 | Use this command to modify the settings of a running PSClock. 81 | 82 | ```powershell 83 | Set-PSClock -size 30 -color white -FontFamily 'Baskerville Old Face' 84 | ``` 85 | You can also increase the size by selecting the clock and using the + key. Decrease using the - key. Each change takes a second to be applied. You might need to "grab" the clock and move it slightly to ensure you have it selected. 86 | 87 | If you only want to change the color, you can use PSReadLine to display a formatted list of color options. After the `-Color` parameter, press Ctrl+Space and answer `Y`. Move the cursor to your selected choice and press Enter. 88 | 89 | ### Settings Preview Form 90 | 91 | Version 1.4.0 updates the PSClock and allows you to configure the font family, style, and color via a WPF-based GUI. Select the clock and press `p` to display the form. The form elements have tooltips to help you understand what each setting does. Hover your mouse over the element to see the tooltip. 92 | 93 | You can select a combination of font elements and view the preview. If you want to apply the new settings, click the `Apply` button. Don't forget to run `Save-PSClock` to save the settings if you want to re-use them the next time you start a clock. 94 | 95 | You can also run `Show-PSClockSettingPreview`. 96 | 97 | If you don't want to apply and changes, close the form. 98 | 99 | ## Save-PSClock 100 | 101 | You can use `Save-PSClock` to export current clock settings to an XML file. 102 | 103 | ```powershell 104 | PS C:\> Save-PSClock 105 | ``` 106 | 107 | The file, PSClockSettings.xml, will be stored in `$HOME`. If the file is detected when you run `Start-PSClock`, the saved settings will be imported. If the file exists and you want to specify new settings, use the `-Force` parameter with `Start-PSClock`. This will not remove the saved settings file, only ignore it. 108 | 109 | You need to manually delete the file if you no longer wish to use it. 110 | 111 | ## Runspaces and Limitations 112 | 113 | The clock runs in a separate runspace launched from your PowerShell session. If you close the session, the clock will also be closed. 114 | 115 | The command is designed to only have one clock running at a time. If you try to start another clock from another PowerShell session, you will get a warning. 116 | 117 | ```dos 118 | PS C:\> Start-PSClock 119 | WARNING: 120 | A running clock has been detected from another PowerShell session: 121 | 122 | [11/6/2024 10:47:33 AM] PSClock started by Jeff under PowerShell process id 13752 123 | 124 | If this is incorrect, delete `C:\Users\Jeff\AppData\Local\Temp\psclock-flag.txt` and try again. 125 | ``` 126 | 127 | If you close PowerShell without properly shutting down the clock you may be left with the flag file. Manually delete the file and try again. 128 | 129 | # NOTE 130 | 131 | For a WPF-based countdown timer, take a look at the `Start-PSCountdownTimer` command in the [PSTimers](https://github.com/jdhitsolutions/PSTimers) module. 132 | 133 | # TROUBLESHOOTING NOTE 134 | 135 | There are no known issues at this time. Please post any bugs or feature requests in the [Issues](https://github.com/jdhitsolutions/PSClock/issues) section of this repository. 136 | 137 | # SEE ALSO 138 | 139 | For more details about the module design and technical implementation, read the [design document](https://github.com/jdhitsolutions/PSClock/blob/main/Design.md). Or read the project's [README](https://github.com/jdhitsolutions/PSClock/blob/main/README.md) file which is similar to this document but contains screen shots and additional information. 140 | 141 | # KEYWORDS 142 | 143 | - psclock 144 | 145 | - clock 146 | -------------------------------------------------------------------------------- /en-US/PSClock-help.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Get-PrimaryDisplaySize 6 | Get 7 | PrimaryDisplaySize 8 | 9 | Get the primary display size in pixels. 10 | 11 | 12 | 13 | When positioning the PSClock, or any WPF form, you might need to know the dimension of your display. 14 | 15 | 16 | 17 | Get-PrimaryDisplaySize 18 | 19 | 20 | 21 | 22 | 23 | 24 | None 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | PSPrimaryDisplaySize 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 44 | 45 | 46 | 47 | 48 | -------------------------- Example 1 -------------------------- 49 | PS C:\> Get-PrimaryDisplaySize 50 | 51 | Width Height WorkArea 52 | ----- ------ -------- 53 | 1536.00 864.00 0,0,1536,816 54 | 55 | These values are different than $host.UI.RawUI.WindowSize.Width and $host.UI.RawUI.WindowSize.Height. The $host values are dimensions of the console window, not the display screen. 56 | 57 | 58 | 59 | -------------------------- Example 2 -------------------------- 60 | PS C:\> Get-PrimaryDisplaySize | Select-Object -ExpandProperty WorkArea 61 | 62 | IsEmpty : False 63 | Location : 0,0 64 | Size : 1536,816 65 | X : 0 66 | Y : 0 67 | Width : 1536 68 | Height : 816 69 | Left : 0 70 | Top : 0 71 | Right : 1536 72 | Bottom : 816 73 | TopLeft : 0,0 74 | TopRight : 1536,0 75 | BottomLeft : 0,816 76 | BottomRight : 1536,816 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | Online Version: 85 | https://jdhitsolutions.com/yourls/e9e07f 86 | 87 | 88 | 89 | 90 | 91 | Get-PSClock 92 | Get 93 | PSClock 94 | 95 | Get PSClock details. 96 | 97 | 98 | 99 | This command will provide detailed information about a PSClock. 100 | 101 | 102 | 103 | Get-PSClock 104 | 105 | 106 | 107 | 108 | 109 | 110 | None 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | PSClock 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 130 | 131 | 132 | 133 | 134 | -------------------------- Example 1 -------------------------- 135 | PS C:\> Get-PSClock 136 | 137 | Running Format FontFamily Size Weight Color Style OnTop RunspaceID 138 | ------- ------ ---------- ---- ------ ----- ----- ----- ---------- 139 | True F Segoi UI 30 Normal yellow Normal False 62 140 | 141 | Get details about the currently running clock. 142 | 143 | 144 | 145 | -------------------------- Example 2 -------------------------- 146 | PS C:\> Get-PSClock | Select * 147 | 148 | Started : 11/7/2024 4:18:30 PM 149 | Format : F 150 | Output : Thursday, November 7, 2024 4:26:18 PM 151 | Running : True 152 | FontFamily : Segoi UI 153 | Size : 30 154 | Weight : Normal 155 | Color : yellow 156 | Style : Normal 157 | OnTop : False 158 | CurrentPosition : {1635, 1089} 159 | RunspaceID : 62 160 | 161 | Get all details about the current clock. 162 | 163 | 164 | 165 | 166 | 167 | Online Version: 168 | https://jdhitsolutions.com/yourls/747a96 169 | 170 | 171 | Set-PSClock 172 | 173 | 174 | 175 | Start-PSClock 176 | 177 | 178 | 179 | Stop-PSClock 180 | 181 | 182 | 183 | Save-PSClock 184 | 185 | 186 | 187 | 188 | 189 | 190 | Save-PSClock 191 | Save 192 | PSClock 193 | 194 | Save current PSClock settings to a file. 195 | 196 | 197 | 198 | This command will export the settings for a PSClock to an xml file,using Export-CliXML. The file PSClockSettings.xml will be created in $HOME. The next time you run Start-PSClock, if this file is detected, the settings will be imported and used for the clock unless you use -Force. If you no longer wish to use the saved settings, you can manually delete the file. 199 | The clock does not have to be running in order to export the settings. 200 | 201 | 202 | 203 | Save-PSClock 204 | 205 | Confirm 206 | 207 | Prompts you for confirmation before running the cmdlet. 208 | 209 | 210 | SwitchParameter 211 | 212 | 213 | False 214 | 215 | 216 | WhatIf 217 | 218 | Shows what would happen if the cmdlet runs. The cmdlet is not run. 219 | 220 | 221 | SwitchParameter 222 | 223 | 224 | False 225 | 226 | 227 | Passthru 228 | 229 | Display the file with saved settings. 230 | 231 | 232 | SwitchParameter 233 | 234 | 235 | False 236 | 237 | 238 | 239 | 240 | 241 | Confirm 242 | 243 | Prompts you for confirmation before running the cmdlet. 244 | 245 | SwitchParameter 246 | 247 | SwitchParameter 248 | 249 | 250 | False 251 | 252 | 253 | WhatIf 254 | 255 | Shows what would happen if the cmdlet runs. The cmdlet is not run. 256 | 257 | SwitchParameter 258 | 259 | SwitchParameter 260 | 261 | 262 | False 263 | 264 | 265 | Passthru 266 | 267 | Display the file with saved settings. 268 | 269 | SwitchParameter 270 | 271 | SwitchParameter 272 | 273 | 274 | False 275 | 276 | 277 | 278 | 279 | 280 | None 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | None 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 300 | 301 | 302 | 303 | 304 | -------------------------- Example 1 -------------------------- 305 | PS C:\> Save-PSClock 306 | 307 | Save current settings to $HOME\PSClockSettings.xml. 308 | 309 | 310 | 311 | -------------------------- Example 2 -------------------------- 312 | PS C:\> Save-PSClock -passthru 313 | 314 | Directory: C:\Users\Jeff 315 | 316 | 317 | Mode LastWriteTime Length Name 318 | ---- ------------- ------ ---- 319 | -a--- 3/30/2025 2:26 PM 1123 󰗀 PSClockSettings.xml 320 | 321 | Save current settings and display the file. 322 | 323 | 324 | 325 | 326 | 327 | Online Version: 328 | https://jdhitsolutions.com/yourls/9116fc 329 | 330 | 331 | Start-PSClock 332 | 333 | 334 | 335 | Get-PSClock 336 | 337 | 338 | 339 | 340 | 341 | 342 | Set-PSClock 343 | Set 344 | PSClock 345 | 346 | Modify a running PSClock. 347 | 348 | 349 | 350 | Use this command to modify the settings of a running PSClock. You can also increase the size by selecting the clock and use the + key. Decrease using the - key. Each change takes a second to be applied. You might need to "grab" the clock and move it slightly to ensure you have it selected. 351 | If you want to change the position, left-click and drag to re-position. 352 | 353 | 354 | 355 | Set-PSClock 356 | 357 | Color 358 | 359 | Specify a font color like Green or an HTML code like '#FF1257EA'. You can also use any [System.Drawing.Brushes] color like Coral or SkyBlue. If you press Ctrl+Space after the parameter, you can use PSReadLine to display options formatted in the corresponding color. 360 | 361 | String 362 | 363 | String 364 | 365 | 366 | None 367 | 368 | 369 | DateFormat 370 | 371 | Specify a .NET format string value like F, or G. 372 | 373 | String 374 | 375 | String 376 | 377 | 378 | None 379 | 380 | 381 | Confirm 382 | 383 | Prompts you for confirmation before running the cmdlet. 384 | 385 | 386 | SwitchParameter 387 | 388 | 389 | False 390 | 391 | 392 | FontFamily 393 | 394 | Specify a font family. 395 | 396 | String 397 | 398 | String 399 | 400 | 401 | None 402 | 403 | 404 | FontSize 405 | 406 | How large do you want the font size? 407 | 408 | Int32 409 | 410 | Int32 411 | 412 | 413 | None 414 | 415 | 416 | FontStyle 417 | 418 | Specify a font style. Accepted values: Normal, Italic, Oblique 419 | 420 | 421 | Normal 422 | Italic 423 | Oblique 424 | 425 | String 426 | 427 | String 428 | 429 | 430 | None 431 | 432 | 433 | FontWeight 434 | 435 | Specify a font weight. Accepted values: 'Normal', 'Bold', 'Light', 'Medium', 'SemiBold' 436 | 437 | 438 | 'Normal' 439 | 'Bold' 440 | 'Light' 441 | 'Medium' 442 | 'SemiBold' 443 | 444 | String 445 | 446 | String 447 | 448 | 449 | None 450 | 451 | 452 | OnTop 453 | 454 | Should the clock be on top of other applications? 455 | 456 | 457 | SwitchParameter 458 | 459 | 460 | False 461 | 462 | 463 | WhatIf 464 | 465 | Shows what would happen if the cmdlet runs. The cmdlet is not run. 466 | 467 | 468 | SwitchParameter 469 | 470 | 471 | False 472 | 473 | 474 | CurrentPosition 475 | 476 | Specify an array of (X,Y) coordinates for the clock position. Use Get-PrimaryDisplaySize to determine the values. 477 | 478 | Double[] 479 | 480 | Double[] 481 | 482 | 483 | None 484 | 485 | 486 | PassThru 487 | 488 | 489 | 490 | 491 | SwitchParameter 492 | 493 | 494 | False 495 | 496 | 497 | 498 | 499 | 500 | Color 501 | 502 | Specify a font color like Green or an HTML code like '#FF1257EA'. You can also use any [System.Drawing.Brushes] color like Coral or SkyBlue. If you press Ctrl+Space after the parameter, you can use PSReadLine to display options formatted in the corresponding color. 503 | 504 | String 505 | 506 | String 507 | 508 | 509 | None 510 | 511 | 512 | Confirm 513 | 514 | Prompts you for confirmation before running the cmdlet. 515 | 516 | SwitchParameter 517 | 518 | SwitchParameter 519 | 520 | 521 | False 522 | 523 | 524 | DateFormat 525 | 526 | Specify a .NET format string value like F, or G. 527 | 528 | String 529 | 530 | String 531 | 532 | 533 | None 534 | 535 | 536 | FontFamily 537 | 538 | Specify a font family. 539 | 540 | String 541 | 542 | String 543 | 544 | 545 | None 546 | 547 | 548 | FontSize 549 | 550 | How large do you want the font size? 551 | 552 | Int32 553 | 554 | Int32 555 | 556 | 557 | None 558 | 559 | 560 | FontStyle 561 | 562 | Specify a font style. Accepted values: Normal, Italic, Oblique 563 | 564 | String 565 | 566 | String 567 | 568 | 569 | None 570 | 571 | 572 | FontWeight 573 | 574 | Specify a font weight. Accepted values: 'Normal', 'Bold', 'Light', 'Medium', 'SemiBold' 575 | 576 | String 577 | 578 | String 579 | 580 | 581 | None 582 | 583 | 584 | OnTop 585 | 586 | Should the clock be on top of other applications? 587 | 588 | SwitchParameter 589 | 590 | SwitchParameter 591 | 592 | 593 | False 594 | 595 | 596 | WhatIf 597 | 598 | Shows what would happen if the cmdlet runs. The cmdlet is not run. 599 | 600 | SwitchParameter 601 | 602 | SwitchParameter 603 | 604 | 605 | False 606 | 607 | 608 | CurrentPosition 609 | 610 | Specify an array of (X,Y) coordinates for the clock position. Use Get-PrimaryDisplaySize to determine the values. 611 | 612 | Double[] 613 | 614 | Double[] 615 | 616 | 617 | None 618 | 619 | 620 | PassThru 621 | 622 | 623 | 624 | SwitchParameter 625 | 626 | SwitchParameter 627 | 628 | 629 | False 630 | 631 | 632 | 633 | 634 | 635 | None 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | None 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 655 | 656 | 657 | 658 | 659 | -------------------------- Example 1 -------------------------- 660 | PS C:\> Set-PSClock -size 28 -FontStyle Oblique -FontFamily 'Tahoma' 661 | 662 | 663 | 664 | 665 | 666 | --------------------------- Example --------------------------- 667 | PS C:\> Set-PSClock -size 35 -Position 500,100 668 | 669 | Adjust the font size and clock position. This example is using the Position parameter alias. 670 | 671 | 672 | 673 | 674 | 675 | Online Version: 676 | https://jdhitsolutions.com/yourls/98a370 677 | 678 | 679 | Show-PSClockSettingPreview 680 | 681 | 682 | 683 | Start-PSClock 684 | 685 | 686 | 687 | Get-PSClock 688 | 689 | 690 | 691 | Stop-PSClock 692 | 693 | 694 | 695 | Save-PSClock 696 | 697 | 698 | 699 | 700 | 701 | 702 | Show-FontPreview 703 | Show 704 | FontPreview 705 | 706 | Show a font preview in a WPF form. 707 | 708 | 709 | 710 | Use this command to display a preview of a font in a WPF form. This can be useful when you need to see what a font looks like before using it in a clock. You can use the buttons or arrow keys to navigate through the fonts. Press Ctrl+Q to quit or manually close the form. 711 | 712 | 713 | 714 | Show-FontPreview 715 | 716 | SampleText 717 | 718 | The default text to display. 719 | 720 | String 721 | 722 | String 723 | 724 | 725 | $(Get-Date -Format F) 726 | 727 | 728 | 729 | 730 | 731 | SampleText 732 | 733 | The default text to display. 734 | 735 | String 736 | 737 | String 738 | 739 | 740 | $(Get-Date -Format F) 741 | 742 | 743 | 744 | 745 | 746 | None 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | None 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 766 | 767 | 768 | 769 | 770 | -------------------------- Example 1 -------------------------- 771 | PS C:\> Show-FontPreview 772 | 773 | Your prompt will be blocked until you close the form. This will display the default sample text from Get-Date -Format F. 774 | 775 | 776 | 777 | -------------------------- Example 2 -------------------------- 778 | PS C:\> Show-FontPreview -Verbose -SampleText (Get-Date -Format D) 779 | 780 | Launch the preview form with the current date displayed. You can always modify the text in the text box. 781 | 782 | 783 | 784 | 785 | 786 | Online Version: 787 | https://jdhitsolutions.com/yourls/b68fcd 788 | 789 | 790 | Set-PSClock 791 | 792 | 793 | 794 | Show-PSClockSettingPreview 795 | 796 | 797 | 798 | 799 | 800 | 801 | Show-PSClockSettingPreview 802 | Show 803 | PSClockSettingPreview 804 | 805 | Show a GUI preview of PSClock settings 806 | 807 | 808 | 809 | Use this command to display a GUI preview of the settings that can be applied to a PSClock. The preview text will adjust to the selected font family, weight, style, color and size. Changes will be reflected in the preview box. Click the Apply button to commit the changes to the current clock. If you don't want to apply any changes, close the form. The form elements have tooltips to help you understand what each setting does. Hover your mouse over the element to see the tooltip. 810 | You can also invoke this command by selecting the PSClock and pressing 'p'. 811 | If you have a running clock, the form will default to the current clock settings. If you don't have a running clock, the form will use the default settings from Start-PSClock. 812 | 813 | 814 | 815 | Show-PSClockSettingPreview 816 | 817 | 818 | 819 | 820 | 821 | 822 | None 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | None 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 842 | 843 | 844 | 845 | 846 | -------------------------- Example 1 -------------------------- 847 | PS C:\> Show-PSClockSettingPreview 848 | 849 | Your prompt will be blocked until you close the form. 850 | 851 | 852 | 853 | 854 | 855 | Online Version: 856 | https://jdhitsolutions.com/yourls/9a6ebc 857 | 858 | 859 | Set-PSClock 860 | 861 | 862 | 863 | 864 | 865 | 866 | Start-PSClock 867 | Start 868 | PSClock 869 | 870 | Start a PSClock. 871 | 872 | 873 | 874 | Start a WPF-based PSClock that will run in a background runspace. The clock will be displayed in the center of the screen. You can click and drag the clock to reposition using the left mouse button. You might have to try a few times to "grab" the clock. You can close the clock with a right-click or the Stop-PSClock command. 875 | The command lets you specify any datetime format string. This is the same value you would use in a command like Get-Date -format U. Note that these strings are case-sensitive. 876 | The clock runs in a separate runspace launched from your PowerShell session. If you close the session, the clock will also be closed. 877 | The command is designed to only have one clock running at a time. If you try to start another clock from another PowerShell session, you will get a warning. 878 | If you have saved PSClock settings, the exported values will be used unless you use -Force. The saved settings file will not be deleted. 879 | 880 | 881 | 882 | Start-PSClock 883 | 884 | DateFormat 885 | 886 | Specify a .NET format string value like F, or G. See https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings for more information. 887 | 888 | String 889 | 890 | String 891 | 892 | 893 | F 894 | 895 | 896 | Color 897 | 898 | Specify a font color like Green or an HTML code like '#FF1257EA'. You can also use any [System.Drawing.Brushes] color like Coral or SkyBlue. 899 | 900 | String 901 | 902 | String 903 | 904 | 905 | White 906 | 907 | 908 | FontFamily 909 | 910 | Specify a font family. 911 | 912 | String 913 | 914 | String 915 | 916 | 917 | Segoi UI 918 | 919 | 920 | FontSize 921 | 922 | Specify a font size. 923 | 924 | Int32 925 | 926 | Int32 927 | 928 | 929 | 18 930 | 931 | 932 | FontStyle 933 | 934 | Specify a font style. Accepted values: Normal, Italic, Oblique 935 | 936 | 937 | Normal 938 | Italic 939 | Oblique 940 | 941 | String 942 | 943 | String 944 | 945 | 946 | Normal 947 | 948 | 949 | FontWeight 950 | 951 | Specify a font weight. Accepted values: 'Normal', 'Bold', 'Light', 'Medium', 'SemiBold' 952 | 953 | 954 | 'Normal' 955 | 'Bold' 956 | 'Light' 957 | 'Medium' 958 | 'SemiBold' 959 | 960 | String 961 | 962 | String 963 | 964 | 965 | Normal 966 | 967 | 968 | OnTop 969 | 970 | Do you want the clock to always be on top? 971 | 972 | 973 | SwitchParameter 974 | 975 | 976 | False 977 | 978 | 979 | Passthru 980 | 981 | 982 | 983 | 984 | SwitchParameter 985 | 986 | 987 | False 988 | 989 | 990 | Force 991 | 992 | Force a new PSClock, ignoring any previously saved settings. The saved settings file will remain. 993 | 994 | 995 | SwitchParameter 996 | 997 | 998 | False 999 | 1000 | 1001 | Position 1002 | 1003 | Specify the clock position as an array of left and top values. 1004 | 1005 | Int32[] 1006 | 1007 | Int32[] 1008 | 1009 | 1010 | None 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | Color 1017 | 1018 | Specify a font color like Green or an HTML code like '#FF1257EA'. You can also use any [System.Drawing.Brushes] color like Coral or SkyBlue. 1019 | 1020 | String 1021 | 1022 | String 1023 | 1024 | 1025 | White 1026 | 1027 | 1028 | DateFormat 1029 | 1030 | Specify a .NET format string value like F, or G. See https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings for more information. 1031 | 1032 | String 1033 | 1034 | String 1035 | 1036 | 1037 | F 1038 | 1039 | 1040 | FontFamily 1041 | 1042 | Specify a font family. 1043 | 1044 | String 1045 | 1046 | String 1047 | 1048 | 1049 | Segoi UI 1050 | 1051 | 1052 | FontSize 1053 | 1054 | Specify a font size. 1055 | 1056 | Int32 1057 | 1058 | Int32 1059 | 1060 | 1061 | 18 1062 | 1063 | 1064 | FontStyle 1065 | 1066 | Specify a font style. Accepted values: Normal, Italic, Oblique 1067 | 1068 | String 1069 | 1070 | String 1071 | 1072 | 1073 | Normal 1074 | 1075 | 1076 | FontWeight 1077 | 1078 | Specify a font weight. Accepted values: 'Normal', 'Bold', 'Light', 'Medium', 'SemiBold' 1079 | 1080 | String 1081 | 1082 | String 1083 | 1084 | 1085 | Normal 1086 | 1087 | 1088 | OnTop 1089 | 1090 | Do you want the clock to always be on top? 1091 | 1092 | SwitchParameter 1093 | 1094 | SwitchParameter 1095 | 1096 | 1097 | False 1098 | 1099 | 1100 | Passthru 1101 | 1102 | 1103 | 1104 | SwitchParameter 1105 | 1106 | SwitchParameter 1107 | 1108 | 1109 | False 1110 | 1111 | 1112 | Force 1113 | 1114 | Force a new PSClock, ignoring any previously saved settings. The saved settings file will remain. 1115 | 1116 | SwitchParameter 1117 | 1118 | SwitchParameter 1119 | 1120 | 1121 | False 1122 | 1123 | 1124 | Position 1125 | 1126 | Specify the clock position as an array of left and top values. 1127 | 1128 | Int32[] 1129 | 1130 | Int32[] 1131 | 1132 | 1133 | None 1134 | 1135 | 1136 | 1137 | 1138 | 1139 | String 1140 | 1141 | 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 | None 1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 | 1157 | PSClock 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | 1165 | 1166 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 1167 | 1168 | 1169 | 1170 | 1171 | -------------------------- Example 1 -------------------------- 1172 | PS C:\> Start-PSClock 1173 | 1174 | Start a new PSClock using the default parameter values. If you have saved PSClock settings, then those values will be used. 1175 | 1176 | 1177 | 1178 | -------------------------- Example 2 -------------------------- 1179 | PS C:\> Start-PSClock -size 24 -FontFamily 'Bahnschrift Light' -OnTop 1180 | 1181 | Start a clock using specific font settings. The clock will be displayed center screen. It will use the default datetime format string. 1182 | 1183 | 1184 | 1185 | 1186 | 1187 | Online Version: 1188 | https://jdhitsolutions.com/yourls/0d5ea1 1189 | 1190 | 1191 | Set-PSClock 1192 | 1193 | 1194 | 1195 | Get-PSClock 1196 | 1197 | 1198 | 1199 | Stop-PSClock 1200 | 1201 | 1202 | 1203 | Save-PSClock 1204 | 1205 | 1206 | 1207 | Get-Date 1208 | 1209 | 1210 | 1211 | 1212 | 1213 | 1214 | Stop-PSClock 1215 | Stop 1216 | PSClock 1217 | 1218 | Stop a running PSClock. 1219 | 1220 | 1221 | 1222 | Use this command to stop a running PSClock from the PowerShell prompt. You can also right-click the clock to dismiss it, or close and remove the runspace it is using. 1223 | If you close the PowerShell session that launched the clock, the clock will also be closed. Note that this forced closing will not delete the flag file which indicates that a clock is running. The next time you try to start a clock you may see a warning. Delete the specified file and try starting a clock again. 1224 | 1225 | 1226 | 1227 | Stop-PSClock 1228 | 1229 | Confirm 1230 | 1231 | Prompts you for confirmation before running the cmdlet. 1232 | 1233 | 1234 | SwitchParameter 1235 | 1236 | 1237 | False 1238 | 1239 | 1240 | WhatIf 1241 | 1242 | Shows what would happen if the cmdlet runs. The cmdlet is not run. 1243 | 1244 | 1245 | SwitchParameter 1246 | 1247 | 1248 | False 1249 | 1250 | 1251 | 1252 | 1253 | 1254 | Confirm 1255 | 1256 | Prompts you for confirmation before running the cmdlet. 1257 | 1258 | SwitchParameter 1259 | 1260 | SwitchParameter 1261 | 1262 | 1263 | False 1264 | 1265 | 1266 | WhatIf 1267 | 1268 | Shows what would happen if the cmdlet runs. The cmdlet is not run. 1269 | 1270 | SwitchParameter 1271 | 1272 | SwitchParameter 1273 | 1274 | 1275 | False 1276 | 1277 | 1278 | 1279 | 1280 | 1281 | None 1282 | 1283 | 1284 | 1285 | 1286 | 1287 | 1288 | 1289 | 1290 | 1291 | None 1292 | 1293 | 1294 | 1295 | 1296 | 1297 | 1298 | 1299 | 1300 | Learn more about PowerShell: https://jdhitsolutions.com/yourls/newsletter 1301 | 1302 | 1303 | 1304 | 1305 | -------------------------- Example 1 -------------------------- 1306 | PS C:\> Stop-PSClock 1307 | 1308 | 1309 | 1310 | 1311 | 1312 | 1313 | 1314 | Online Version: 1315 | https://jdhitsolutions.com/yourls/7ed4f9 1316 | 1317 | 1318 | Set-PSClock 1319 | 1320 | 1321 | 1322 | Get-PSClock 1323 | 1324 | 1325 | 1326 | Start-PSClock 1327 | 1328 | 1329 | 1330 | 1331 | -------------------------------------------------------------------------------- /en-US/PSClock.psd1: -------------------------------------------------------------------------------- 1 | #localized string data for verbose messaging, errors, and warnings. 2 | 3 | ConvertFrom-StringData @" 4 | SynchHash = Building a synchronized hashtable 5 | CantFind = Cant find a running PSClock. Do you need to start one? 6 | CreatingFlag = Creating the flag file {0} 7 | DefiningRunspace = Defining the runspace command 8 | DefiningWPF = Defining the WPF form and controls 9 | Detected = Detected PowerShell host: {0} 10 | Ending = Ending module command: {0} 11 | FlagFound = A running clock has been detected from another PowerShell session on this desktop: \n\n{0}\n\nIf this is incorrect, delete {1} and try again. 12 | Launching = Launching the runspace 13 | LoadingColor = Loading color values 14 | LoadingFont = Loading font families 15 | Measuring = Measuring primary display. 16 | RemovePrompt = Do you want to remove the flag file? Y/N 17 | Running = Running in PowerShell: {0} 18 | Saving = Saving PSClock settings to {0} 19 | Setting = Setting {0} to {1} 20 | Showing = Showing the WPF form 21 | Starting = Starting module command: {0} 22 | WarnDateFormat = The DateFormat value {0} is not a valid format string. Try something like F, G, or U, which are case-sensitive. 23 | Requires = This requires Windows PowerShell or PowerShell 7 on Windows. 24 | UsingText = Using sample text: {0} 25 | UsingImported = Using imported value for {0} 26 | UsingSaved = Using saved settings 27 | Validating = Validating clock parameter values 28 | RunningClock = You already have a clock running. You can only have one clock running at a time. 29 | "@ 30 | -------------------------------------------------------------------------------- /en-US/about_psclock.help.txt: -------------------------------------------------------------------------------- 1 | TOPIC 2 | about_psclock 3 | 4 | SHORT DESCRIPTION 5 | 6 | This module will create a WPF-based clock launched from a PowerShell prompt 7 | that runs on your Windows desktop. The clock runs in a background PowerShell 8 | runspace so that it doesn't block. You can customize the clock's appearance 9 | including how you want to format the date and time. The clock background is 10 | transparent so all you see is formatted text. 11 | 12 | LONG DESCRIPTION 13 | 14 | Use Start-PSClock or the psclock alias to launch a PSClock. 15 | 16 | PS C:\> Start-PSClock -size 24 -FontFamily 'Bahnschrift Light' 17 | 18 | The font size must be at least 8. You should have tab completion for the 19 | Color, FontFamily, and other font-related parameters. 20 | 21 | By default, the clock will be displayed on the center of your screen. You 22 | can click and drag the clock to reposition using the left mouse button. You 23 | might have to try a few times to "grab" the clock. You can close the clock 24 | with a right click or the Stop-PSClock command. 25 | 26 | The command lets you specify any DateTime format string. This is the same 27 | value you would use in a command like Get-Date -format U. Note that these 28 | strings are case-sensitive. See 29 | https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings 30 | for more information. 31 | 32 | Start-PSClock -size 30 -Color Yellow -format G -FontFamily Verdana 33 | 34 | Get-PSClock 35 | 36 | Use this command to get information about the current clock. 37 | 38 | PS C:\> Get-PSClock 39 | 40 | Running Format FontFamily Size Weight Color Style OnTop RunspaceID 41 | ------- ------ ---------- ---- ------ ----- ----- ----- ---------- 42 | True G Verdana 30 Normal Yellow Normal False 28 43 | 44 | If the clock is not running, the Running value will be displayed in Red 45 | and there will be no RunspaceID. There are other properties to this object 46 | you might want to use. 47 | 48 | PS C:\> Get-PSClock | Select * 49 | 50 | Started : 11/6/2024 10:47:33 AM 51 | Format : G 52 | Output : 11/6/2024 10:59:08 AM 53 | Running : True 54 | FontFamily : Verdana 55 | Size : 30 56 | Weight : Normal 57 | Color : Yellow 58 | Style : Normal 59 | OnTop : False 60 | CurrentPosition : {1635, 1089} 61 | RunspaceID : 28 62 | 63 | The Output property is a sample using the specified format string. 64 | 65 | Stop-PSClock 66 | 67 | Use this command to stop a running PSClock from the PowerShell prompt. 68 | 69 | PS C:\> Stop-PSClock 70 | 71 | You can also right-click the clock to dismiss it, or close and remove the 72 | runspace it is using. You can still use Get-PSClock which should now 73 | reflect that a clock is not running. 74 | 75 | PS C:\> Get-PSClock 76 | 77 | Running Format FontFamily Size Weight Color Style OnTop RunspaceID 78 | ------- ------ ---------- ---- ------ ----- ----- ----- ---------- 79 | False G Baskerville Old Face 30 Normal white Normal False 80 | 81 | Set-PSClock 82 | 83 | Use this command to modify the settings of a running PSClock. 84 | 85 | PS C:\> Set-PSClock -size 30 -color white -FontFamily 'Baskerville Old Face' 86 | 87 | You can also increase the size by selecting the clock and using the 88 | + key. Decrease using the - key. Each change takes a second to be applied. 89 | You might need to "grab" the clock and move it slightly to ensure you have 90 | it selected. 91 | 92 | If you only want to change the color, you can use PSReadLine to display a 93 | formatted list of color options. 94 | 95 | SETTINGS PREVIEW FORM 96 | 97 | Version 1.4.0 updates the PSClock and allows you to configure the font 98 | family, style, and color via a WPF-based GUI. Select the clock and press p 99 | to display the form. The form elements have tooltips to help you understand 100 | what each setting does. Hover your mouse over the element to see the tooltip. 101 | You can select a combination of font elements and view the preview. If you 102 | want to apply the new settings, click the Apply button. Don't forget to 103 | run Save-PSClock to save the settings if you want to re-use them the next 104 | time you start a clock. 105 | 106 | You can also run Show-PSClockSettingPreview. 107 | 108 | If you don't want to apply and changes, close the form. 109 | 110 | Save-PSClock 111 | 112 | You can use Save-PSClock to export current clock settings to an XML file. 113 | 114 | PS C:\> Save-PSClock 115 | 116 | The file, PSClockSettings.xml, will be stored in $HOME. If the file is 117 | detected when you run Start-PSClock, the saved settings will be imported. 118 | If the file exists and you want to specify new settings, use the -Force 119 | parameter with Start-PSClock. This will not remove the saved settings 120 | file, only ignore it. 121 | 122 | You need to manually delete the file if you no longer wish to use it. 123 | 124 | Runspaces and Limitations 125 | 126 | The clock runs in a separate runspace launched from your PowerShell session. 127 | If you close the session, the clock will also be closed. 128 | 129 | The command is designed to only have one clock running at a time. If you try 130 | to start another clock from another PowerShell session, you will get a 131 | warning. 132 | 133 | PS C:\> Start-PSClock 134 | WARNING: 135 | A running clock has been detected from another PowerShell session: 136 | 137 | [11/6/2024 10:47:33 AM] PSClock started by Jeff under PowerShell process id 13752 138 | 139 | If this is incorrect, delete C:\Users\Jeff\AppData\Local\Temp\psclock-flag.txt 140 | and try again. 141 | 142 | If you close PowerShell without properly shutting down the clock you may be 143 | left with the flag file. Manually delete the file and try again. 144 | 145 | NOTE 146 | 147 | For a WPF-based countdown timer, take a look at the Start-PSCountdownTimer command 148 | in the PSTimers module. (https://github.com/jdhitsolutions/PSTimers) 149 | 150 | TROUBLESHOOTING NOTE 151 | 152 | There are no known issues at this time. Please post any bugs or feature 153 | requests in the Issues section of this project's repository. 154 | 155 | https://github.com/jdhitsolutions/PSClock/issues 156 | 157 | SEE ALSO 158 | 159 | For more details about the module design and technical implementation, read 160 | the design document at: 161 | 162 | https://github.com/jdhitsolutions/PSClock/blob/main/Design.md 163 | 164 | Or read the project's README file: 165 | 166 | https://github.com/jdhitsolutions/PSClock/blob/main/README.md 167 | 168 | which is similar to this document but contains screen shots and additional information. 169 | 170 | KEYWORDS 171 | 172 | - psclock 173 | - clock 174 | -------------------------------------------------------------------------------- /formats/psclock.format.ps1xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | default 14 | 15 | PSClock 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 10 24 | left 25 | 26 | 27 | 28 | 9 29 | Center 30 | 31 | 32 | 33 | 13 34 | left 35 | 36 | 37 | 38 | 7 39 | right 40 | 41 | 42 | 43 | 9 44 | left 45 | 46 | 47 | 48 | 8 49 | left 50 | 51 | 52 | 53 | 9 54 | left 55 | 56 | 57 | 58 | 8 59 | left 60 | 61 | 62 | 63 | 13 64 | right 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | if ($host.name -match "console|code" -AND (-Not $_.Running)) { 73 | "$([char]27)[91m$($_.Running)$([char]27)[0m" 74 | } 75 | else { 76 | $_.Running 77 | } 78 | 79 | 80 | 81 | Format 82 | 83 | 84 | FontFamily 85 | 86 | 87 | Size 88 | 89 | 90 | Weight 91 | 92 | 93 | Color 94 | 95 | 96 | Style 97 | 98 | 99 | OnTop 100 | 101 | 102 | RunspaceID 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /functions/ClockSettingsPreview.ps1: -------------------------------------------------------------------------------- 1 | Function Show-PSClockSettingPreview { 2 | [CmdletBinding()] 3 | Param() 4 | 5 | <# 6 | define form titles and tooltips here so I can easily change 7 | them without digging through the code. I am using a custom 8 | object instead of a hashtable so I can define a script property 9 | to get the current font size setting. 10 | #> 11 | $formConfig = [PSCustomObject]@{ 12 | PSTypeName = 'formConfig' 13 | Title = 'PSClock Settings Preview [Ctrl+Q to close]' 14 | FontFamilyTip = 'Select a PSClock font family' 15 | FontStyleTip = 'Select a PSClock font style' 16 | FontWeightTip = 'Select a PSClock font weight' 17 | ColorTip = 'Select a foreground color for the PSClock' 18 | ApplyTip = 'Apply the new settings to the current clock' 19 | ApplyWarning = 'Cannot apply settings to a stopped or non-existent PSClock.' 20 | } 21 | 22 | #defining a dynamic tooltip for the font size slider 23 | $updateSplat = @{ 24 | TypeName = 'formConfig' 25 | MemberType = 'ScriptProperty' 26 | MemberName = 'FontSizeTip' 27 | Value = {"Select a PSClock font size: $($sliderSize.Value -as [int])"} 28 | Force = $true 29 | } 30 | Update-TypeData @updateSplat 31 | 32 | _verbose ($strings.Starting -f $MyInvocation.MyCommand) 33 | _verbose ($strings.Running -f $PSVersionTable.PSVersion) 34 | _verbose ($strings.Detected -f $Host.Name) 35 | 36 | _verbose $strings.LoadingFont 37 | $Families = [System.Drawing.Text.InstalledFontCollection]::new().Families 38 | _verbose $strings.LoadingColor 39 | $Colors = [System.Drawing.Brushes].GetProperties().name | Select-Object -Skip 1 40 | $defaultText = $(Get-Date -Format F) 41 | 42 | _verbose ($strings.UsingText -f $defaultText) 43 | _verbose $strings.DefiningWPF 44 | $window = [System.Windows.Window]@{ 45 | Title = $formConfig.Title 46 | Height = 400 47 | Width = 600 48 | WindowStartupLocation = 'CenterScreen' 49 | } 50 | 51 | #add a handler to resize controls if the window is resized 52 | $window.Add_SizeChanged({ 53 | $txtPreview.Height = $window.Height - 275 54 | $txtPreview.Width = $window.Width - 50 55 | }) 56 | 57 | #add a handler to go to next font if the > key is pressed 58 | $window.Add_KeyDown({ 59 | if ($_.Key -eq 'Right' -OR $_.Key -eq 'Down') { 60 | $comboFont.SelectedIndex++ 61 | } 62 | }) 63 | 64 | #add a handler to go to previous font if the < key is pressed 65 | $window.Add_KeyDown({ 66 | if (($comboFont.SelectedIndex -gt 0) -AND ($_.Key -eq 'Up' -OR $_.Key -eq 'Left' )) { 67 | $comboFont.SelectedIndex-- 68 | } 69 | }) 70 | 71 | #add a handler to close window with Ctrl+Q 72 | $window.Add_KeyDown({ 73 | if ($_.Key -eq 'Q' -AND $_.KeyboardDevice.Modifiers -eq 'Control') { 74 | $window.Close() 75 | } 76 | }) 77 | 78 | $Stack = [System.Windows.Controls.StackPanel]@{ 79 | Orientation = 'Vertical' 80 | Background = 'Ivory' 81 | } 82 | $comboStyle = [System.Windows.Controls.ComboBox]@{ 83 | ItemsSource = 'Normal', 'Italic', 'Oblique' 84 | SelectedIndex = 0 85 | FontSize = 14 86 | Height = 25 87 | Width = 100 88 | ToolTip = $formConfig.FontStyleTip 89 | HorizontalAlignment = 'Left' 90 | Margin = '5,5,0,0' 91 | } 92 | 93 | $comboStyle.Add_SelectionChanged({ $txtPreview.FontStyle = $comboStyle.SelectedItem }) 94 | 95 | $Stack.AddChild($comboStyle) 96 | 97 | #add a combo box to select the font weight 98 | $comboWeight = [System.Windows.Controls.ComboBox]@{ 99 | ItemsSource = 'Normal', 'Bold', 'Light', 'Medium', 'SemiBold' 100 | SelectedIndex = 0 101 | FontSize = 14 102 | Height = 25 103 | Width = 100 104 | ToolTip = $formConfig.FontWeightTip 105 | HorizontalAlignment = 'Left' 106 | Margin = '5,5,0,0' 107 | } 108 | 109 | $comboWeight.Add_SelectionChanged({ $txtPreview.FontWeight = $comboWeight.SelectedItem }) 110 | $Stack.AddChild($comboWeight) 111 | 112 | $comboFont = [System.Windows.Controls.ComboBox]@{ 113 | ItemsSource = $Families.Name 114 | SelectedIndex = 0 115 | FontSize = 14 116 | Height = 25 117 | Width = 250 118 | HorizontalAlignment = 'left' 119 | ToolTip = $formConfig.FontFamilyTip 120 | Margin = '5,5,0,0' 121 | } 122 | #change the text box to use the selected font 123 | $comboFont.Add_SelectionChanged({ $txtPreview.FontFamily = $comboFont.SelectedItem }) 124 | 125 | $Stack.AddChild($comboFont) 126 | 127 | $comboColor = [System.Windows.Controls.ComboBox]@{ 128 | ItemsSource = $Colors 129 | SelectedIndex = 0 130 | FontSize = 14 131 | Height = 25 132 | Width = 250 133 | HorizontalAlignment = 'left' 134 | ToolTip = $formConfig.ColorTip 135 | Margin = '5,5,0,0' 136 | } 137 | #change the text box to use the selected color 138 | $comboColor.Add_SelectionChanged({$txtPreview.Foreground = $comboColor.SelectedItem}) 139 | 140 | $Stack.AddChild($comboColor) 141 | 142 | #use a slider control to set the font size 143 | $sliderSize = [System.Windows.Controls.Slider]@{ 144 | Minimum = 10 145 | Maximum = 100 146 | Value = 18 147 | Width = 200 148 | Height = 25 149 | HorizontalAlignment = 'Left' 150 | Margin = '5,10,5,5' 151 | ToolTip = $formConfig.FontSizeTip 152 | } 153 | 154 | $sliderSize.Add_ValueChanged({ 155 | #force an update of the tooltip 156 | $SliderSize.Tooltip = $formConfig.FontSizeTip 157 | $txtPreview.FontSize = $sliderSize.Value -as [int] 158 | }) 159 | $Stack.AddChild($sliderSize) 160 | 161 | $txtPreview = [System.Windows.Controls.TextBox]@{ 162 | TextWrapping = 'Wrap' 163 | AcceptsReturn = $true 164 | VerticalScrollBarVisibility = 'Auto' 165 | HorizontalScrollBarVisibility = 'Auto' 166 | FontSize = 20 167 | Height = $Window.Height - 275 168 | Width = $window.Width - 50 169 | FontFamily = $comboFont.SelectedItem 170 | FontStyle = 'Normal' 171 | Foreground = $comboColor.SelectedItem 172 | Background = 'DarkGray' 173 | Text = $DefaultText 174 | TextAlignment = 'Center' 175 | VerticalAlignment = 'Top' 176 | HorizontalAlignment = 'Center' 177 | Margin = '5,10,5,5' 178 | } 179 | 180 | $Stack.AddChild($txtPreview) 181 | 182 | $btnApply = [System.Windows.Controls.Button]@{ 183 | Content = 'Apply' 184 | Width = 75 185 | HorizontalAlignment = 'Left' 186 | VerticalAlignment = 'Bottom' 187 | FontSize = 14 188 | Margin = '5,25,0,0' 189 | ToolTip = $formConfig.ApplyTip 190 | } 191 | $btnApply.Add_Click({ 192 | #only apply to a running clock 193 | if ($PSClockSettings.Running) { 194 | $PSClockSettings.FontFamily = $comboFont.SelectedItem 195 | $PSClockSettings.FontStyle = $comboStyle.SelectedItem 196 | $PSClockSettings.FontWeight = $comboWeight.SelectedItem 197 | $PSClockSettings.Color = $comboColor.SelectedItem 198 | $PSClockSettings.FontSize = $sliderSize.Value -As [int] 199 | } 200 | else { 201 | Write-Warning $formConfig.ApplyWarning 202 | } 203 | }) 204 | 205 | $Stack.AddChild($btnApply) 206 | 207 | $window.Add_Loaded({ 208 | if ($PSClockSettings) { 209 | $comboFont.SelectedItem = $PSClockSettings.FontFamily 210 | $comboWeight.SelectedItem = $PSClockSettings.FontWeight 211 | $comboStyle.SelectedItem = $PSClockSettings.FontStyle 212 | $comboColor.SelectedItem = $PSClockSettings.Color 213 | $sliderSize.Value = $PSClockSettings.FontSize 214 | } 215 | $SliderSize.Tooltip = $formConfig.FontSizeTip 216 | }) 217 | 218 | $window.AddChild($Stack) 219 | Write-Information -MessageData $window -Tags wpf 220 | _verbose $strings.Showing 221 | [void]$Window.ShowDialog() 222 | 223 | _verbose ($strings.Ending -f $MyInvocation.MyCommand) 224 | Write-Information -MessageData $formConfig -tags wpf 225 | 226 | } -------------------------------------------------------------------------------- /functions/Get-PSClock.ps1: -------------------------------------------------------------------------------- 1 | Function Get-PSClock { 2 | [CmdletBinding()] 3 | [OutputType('PSClock')] 4 | [Alias('gpc')] 5 | Param() 6 | 7 | _verbose ($strings.Starting -f $MyInvocation.MyCommand) 8 | if ($MyInvocation.CommandOrigin -eq 'Runspace') { 9 | _verbose ($strings.Running -f $PSVersionTable.PSVersion) 10 | _verbose ($strings.Detected -f $Host.Name) 11 | } 12 | 13 | #test if there is a settings hashtable 14 | if ($global:PSClockSettings) { 15 | #remove runspace setting if not running 16 | if ( -not ($global:PSClockSettings.running)) { 17 | $global:PSClockSettings.remove('Runspace') 18 | } 19 | 20 | [PSCustomObject]@{ 21 | PSTypeName = 'PSClock' 22 | Started = $global:PSClockSettings.Started 23 | Format = $global:PSClockSettings.DateFormat 24 | Output = (Get-Date -Format $global:PSClockSettings.DateFormat) 25 | Running = $global:PSClockSettings.Running 26 | FontFamily = $global:PSClockSettings.FontFamily 27 | Size = $global:PSClockSettings.fontSize 28 | Weight = $global:PSClockSettings.FontWeight 29 | Color = $global:PSClockSettings.Color 30 | Style = $global:PSClockSettings.FontStyle 31 | OnTop = $global:PSClockSettings.OnTop 32 | CurrentPosition = $global:PSClockSettings.CurrentPosition 33 | RunspaceID = $global:PSClockSettings.Runspace.id 34 | } 35 | } 36 | Else { 37 | Write-Warning $strings.CantFind 38 | } 39 | 40 | _verbose ($strings.Ending -f $MyInvocation.MyCommand) 41 | } 42 | -------------------------------------------------------------------------------- /functions/Get-ScreenWidth.ps1: -------------------------------------------------------------------------------- 1 | Function Get-PrimaryDisplaySize { 2 | [cmdletbinding()] 3 | [OutputType('PSPrimaryDisplaySize')] 4 | Param() 5 | 6 | Begin { 7 | _verbose ($strings.Starting -f $MyInvocation.MyCommand) 8 | _verbose ($strings.Running -f $PSVersionTable.PSVersion) 9 | _verbose ($strings.Detected -f $Host.Name) 10 | } #begin 11 | 12 | Process { 13 | _verbose $strings.Measuring 14 | [PSCustomObject]@{ 15 | PSTypeName = 'PSPrimaryDisplaySize' 16 | Width = [System.Windows.SystemParameters]::PrimaryScreenWidth 17 | Height = [System.Windows.SystemParameters]::PrimaryScreenHeight 18 | WorkArea = [System.Windows.SystemParameters]::WorkArea 19 | } 20 | Write-Information -MessageData [System.Windows.SystemParameters] -Tags raw 21 | } #process 22 | 23 | End { 24 | _verbose ($strings.Ending -f $MyInvocation.MyCommand) 25 | } #end 26 | 27 | } #close Get-ScreenWidth -------------------------------------------------------------------------------- /functions/Save-PSClock.ps1: -------------------------------------------------------------------------------- 1 | Function Save-PSClock { 2 | [CmdletBinding(SupportsShouldProcess)] 3 | Param( 4 | [Parameter(HelpMessage = "Display the file with saved settings.")] 5 | [switch]$Passthru 6 | ) 7 | _verbose ($strings.Starting -f $MyInvocation.MyCommand) 8 | _verbose ($strings.Running -f $PSVersionTable.PSVersion) 9 | _verbose ($strings.Detected -f $Host.Name) 10 | 11 | #define a list of properties to export 12 | $props = @{Name="DateFormat";Expression={$_.Format}},"Color", 13 | @{Name="FontSize";Expression={$_.Size}}, 14 | @{Name="FontWeight";Expression={$_.weight}},"FontFamily", 15 | @{Name="FontStyle";Expression={$_.Style}},"OnTop", 16 | @{Name="Position";Expression = {$_.CurrentPosition}} 17 | 18 | if ($global:PSClockSettings) { 19 | _verbose ($strings.Saving -f $SavePath) 20 | Get-PSClock | Select-Object -property $props | Export-Clixml -Path $SavePath 21 | If ($Passthru -AND (-Not $WhatIfPreference)) { 22 | Get-Item -Path $SavePath 23 | } 24 | } 25 | else { 26 | Write-Warning $strings.CantFind 27 | } 28 | 29 | _verbose ($strings.Ending -f $MyInvocation.MyCommand) 30 | } 31 | -------------------------------------------------------------------------------- /functions/Set-PSClock.ps1: -------------------------------------------------------------------------------- 1 | Function Set-PSClock { 2 | [CmdletBinding(SupportsShouldProcess)] 3 | [OutputType("none")] 4 | [Alias("spc")] 5 | Param( 6 | [Parameter( 7 | Position=0, 8 | HelpMessage = "Specify a font color like Green or an HTML code like '#FF1257EA'", 9 | ValueFromPipelineByPropertyName 10 | )] 11 | [ValidateNotNullOrEmpty()] 12 | [String]$Color, 13 | 14 | [Parameter( 15 | Position = 1, 16 | HelpMessage = "Specify a .NET format string value like F, or G.", 17 | ValueFromPipelineByPropertyName 18 | )] 19 | [alias("Format")] 20 | [ValidateNotNullOrEmpty()] 21 | [String]$DateFormat, 22 | 23 | [Parameter( 24 | HelpMessage = "How large do you want the font size?", 25 | ValueFromPipelineByPropertyName 26 | )] 27 | [ValidateScript({ $_ -gt 8 })] 28 | [alias("Size")] 29 | [Int]$FontSize, 30 | 31 | [Parameter( 32 | HelpMessage = "Specify a font style.", 33 | ValueFromPipelineByPropertyName 34 | )] 35 | [ValidateSet("Normal", "Italic", "Oblique")] 36 | [alias("Style")] 37 | [String]$FontStyle, 38 | 39 | [Parameter( 40 | HelpMessage = "Specify a font weight.", 41 | ValueFromPipelineByPropertyName 42 | )] 43 | [ValidateSet('Normal', 'Bold', 'Light', 'Medium', 'SemiBold')] 44 | [alias("Weight")] 45 | [String]$FontWeight, 46 | 47 | [Parameter( 48 | HelpMessage = "Specify a font family.", 49 | ValueFromPipelineByPropertyName 50 | )] 51 | [ValidateNotNullOrEmpty()] 52 | [alias("Family")] 53 | [String]$FontFamily, 54 | 55 | [Parameter( 56 | HelpMessage = "Should the clock be on top of other applications?", 57 | ValueFromPipelineByPropertyName 58 | )] 59 | [Switch]$OnTop, 60 | 61 | [Parameter( 62 | HelpMessage = "Specify an array of (X,Y) coordinates for the clock position." 63 | )] 64 | [ValidateNotNullOrEmpty()] 65 | [ValidateCount(2,2)] 66 | [alias("Position")] 67 | [Double[]]$CurrentPosition, 68 | [Switch]$PassThru 69 | ) 70 | 71 | _verbose ($strings.Starting -f $MyInvocation.MyCommand) 72 | _verbose ($strings.Running -f $PSVersionTable.PSVersion) 73 | _verbose ($strings.Detected -f $Host.Name) 74 | 75 | $settings = "FontSize", "FontStyle", "FontWeight", "Color", "OnTop", "DateFormat", "FontFamily","CurrentPosition" 76 | if ($PSClockSettings -And $PSClockSettings.Running) { 77 | Foreach ($setting in $settings) { 78 | if ($PSBoundParameters.ContainsKey($setting)) { 79 | $value = $PSBoundParameters[$setting] 80 | $action = ($strings.Setting -f $Null,$value) 81 | _verbose ($strings.Setting -f $setting,$value) 82 | if ($PSCmdlet.ShouldProcess($setting, $action)) { 83 | $Global:PSClockSettings[$setting] = $Value 84 | } 85 | } 86 | } #foreach setting 87 | 88 | if ($PassThru) { 89 | Start-Sleep -Seconds 1 90 | Get-PSClock 91 | } 92 | } #if running clock found 93 | else { 94 | Write-Warning $strings.CantFind 95 | } 96 | 97 | _verbose ($strings.Ending -f $MyInvocation.MyCommand) 98 | } 99 | 100 | -------------------------------------------------------------------------------- /functions/Start-PSClock.ps1: -------------------------------------------------------------------------------- 1 | Function Start-PSClock { 2 | [CmdletBinding()] 3 | [alias('psclock')] 4 | [OutputType('None', 'PSClock')] 5 | Param( 6 | [Parameter( 7 | Position = 0, 8 | HelpMessage = 'Specify a .NET format string value like F, or G.', 9 | ValueFromPipelineByPropertyName 10 | )] 11 | [alias('format')] 12 | [ValidateNotNullOrEmpty()] 13 | [String]$DateFormat = 'F', 14 | 15 | [Parameter(ValueFromPipelineByPropertyName)] 16 | [ValidateScript({ $_ -gt 8 })] 17 | [alias('Size')] 18 | [Int]$FontSize = 18, 19 | 20 | [Parameter( 21 | HelpMessage = 'Specify a font style.', 22 | ValueFromPipelineByPropertyName 23 | )] 24 | [ValidateSet('Normal', 'Italic', 'Oblique')] 25 | [alias('Style')] 26 | [String]$FontStyle = 'Normal', 27 | 28 | [Parameter( 29 | HelpMessage = 'Specify a font weight.', 30 | ValueFromPipelineByPropertyName 31 | )] 32 | [ValidateSet('Normal', 'Bold', 'Light', 'Medium', 'SemiBold')] 33 | [alias('Weight')] 34 | [String]$FontWeight = 'Normal', 35 | 36 | [Parameter( 37 | HelpMessage = "Specify a font color like Green or an HTML code like '#FF1257EA'", 38 | ValueFromPipelineByPropertyName 39 | )] 40 | [ValidateNotNullOrEmpty()] 41 | [String]$Color = 'White', 42 | 43 | [Parameter( 44 | HelpMessage = 'Specify a font family.', 45 | ValueFromPipelineByPropertyName 46 | )] 47 | [ValidateNotNullOrEmpty()] 48 | [alias('Family')] 49 | [String]$FontFamily = 'Segoi UI', 50 | 51 | [Parameter( 52 | HelpMessage = 'Do you want the clock to always be on top?', 53 | ValueFromPipelineByPropertyName 54 | )] 55 | [Switch]$OnTop, 56 | 57 | [Parameter( 58 | HelpMessage = 'Specify the clock position as an array of left and top values.', 59 | ValueFromPipelineByPropertyName 60 | )] 61 | [ValidateCount(2, 2)] 62 | [Int32[]]$Position, 63 | 64 | [Parameter(HelpMessage = 'Force a new PSClock, ignoring any previously saved settings. The saved settings file will remain.')] 65 | [Switch]$Force, 66 | 67 | [Switch]$PassThru 68 | ) 69 | 70 | Begin { 71 | _verbose ($strings.Starting -f $MyInvocation.MyCommand) 72 | _verbose ($strings.Running -f $PSVersionTable.PSVersion) 73 | _verbose ($strings.Detected -f $Host.Name) 74 | } #begin 75 | Process { 76 | _verbose $strings.Validating 77 | 78 | if ($PSClockSettings.Running) { 79 | Write-Warning $strings.RunningClock 80 | Return 81 | } 82 | 83 | #FlagPath is a module-scoped variable set in the psm1 file 84 | if (Test-Path $FlagPath) { 85 | Write-Warning ($strings.FlagFound -f (Get-Content -path $FlagPath),$FlagPath) 86 | 87 | $r = Read-Host $strings.RemovePrompt 88 | if ($r -eq 'Y') { 89 | Remove-Item $FlagPath 90 | } 91 | else { 92 | #bail out 93 | Return 94 | } 95 | } 96 | 97 | #verify the DateTime format 98 | Try { 99 | [void](Get-Date -Format $DateFormat -ErrorAction Stop) 100 | } 101 | Catch { 102 | Write-Warning ($strings.WarnDateFormat -f $DateFormat) 103 | Return 104 | } 105 | 106 | #Test if there is a saved settings file and no other parameters have been called 107 | # $SavePath is a module-scoped variable set in the psm1 file 108 | # $SavePath = Join-Path -Path $home -ChildPath PSClockSettings.xml 109 | if ((Test-Path $SavePath) -AND (-not $Force)) { 110 | _verbose $strings.UsingSaved 111 | $import = Import-Clixml -Path $SavePath 112 | foreach ($prop in $import.PSObject.properties) { 113 | _verbose ($strings.UsingImported -f $prop.name) 114 | Set-Variable -Name $prop.name -Value $prop.Value 115 | } 116 | } 117 | 118 | _verbose $strings.SynchHash 119 | $global:PSClockSettings = [hashtable]::Synchronized(@{ 120 | DateFormat = $DateFormat 121 | FontSize = $FontSize 122 | FontStyle = $FontStyle 123 | FontWeight = $FontWeight 124 | Color = $Color 125 | FontFamily = $FontFamily 126 | OnTop = $OnTop 127 | StartingPosition = $Position 128 | CurrentPosition = $Null 129 | CommandPath = $PSScriptRoot 130 | }) 131 | Write-Debug $global:PSClockSettings 132 | #Run the clock in a runspace 133 | $rs = [RunspaceFactory]::CreateRunspace() 134 | $rs.ApartmentState = 'STA' 135 | $rs.ThreadOptions = 'ReuseThread' 136 | $rs.Open() 137 | 138 | $global:PSClockSettings.add('Runspace', $rs) 139 | 140 | #pass variable values to the runspace 141 | $rs.SessionStateProxy.SetVariable('PSClockSettings', $global:PSClockSettings) 142 | $rs.SessionStateProxy.SetVariable('FlagPath', $script:FlagPath) 143 | 144 | _verbose $strings.DefiningRunspace 145 | $PSCmd = [PowerShell]::Create().AddScript({ 146 | Add-Type -AssemblyName PresentationFramework -ErrorAction Stop 147 | Add-Type -AssemblyName PresentationCore -ErrorAction Stop 148 | 149 | #dot source the private settings preview function 150 | $previewFunction = Join-Path -Path "$($global:PSClockSettings.CommandPath)" -childPath ClockSettingsPreview.ps1 151 | . $previewFunction 152 | # a private function to stop the clock and clean up 153 | Function _QuitClock { 154 | $timer.stop() 155 | $timer.IsEnabled = $False 156 | $form.close() 157 | $PSClockSettings.Running = $False 158 | 159 | #define a thread job to clean up the runspace 160 | $cmd = { 161 | Param([Int]$ID) 162 | $r = Get-Runspace -Id $id 163 | $r.close() 164 | $r.dispose() 165 | } 166 | Start-ThreadJob -ScriptBlock $cmd -ArgumentList $PSClockSettings.runspace.id 167 | 168 | #delete the flag file 169 | if (Test-Path $FlagPath) { 170 | Remove-Item $FlagPath 171 | } 172 | } 173 | 174 | $form = New-Object System.Windows.Window 175 | 176 | <# 177 | Some of the form settings are irrelevant because the form is transparent, 178 | but leaving them in the event I need to turn off transparency 179 | to debug or troubleshoot. 180 | #> 181 | 182 | $form.Title = 'PSClock' 183 | $form.Height = 200 184 | $form.Width = 400 185 | $form.SizeToContent = 'WidthAndHeight' 186 | $form.AllowsTransparency = $True 187 | $form.Topmost = $PSClockSettings.OnTop 188 | 189 | $form.Background = 'Transparent' 190 | $form.BorderThickness = '1,1,1,1' 191 | $form.VerticalAlignment = 'top' 192 | 193 | if ($PSClockSettings.StartingPosition) { 194 | $form.left = $PSClockSettings.StartingPosition[0] 195 | $form.top = $PSClockSettings.StartingPosition[1] 196 | } 197 | else { 198 | $form.WindowStartupLocation = 'CenterScreen' 199 | } 200 | $form.WindowStyle = 'None' 201 | $form.ShowInTaskbar = $False 202 | 203 | #define events 204 | #call the private function to stop the clock and clean up 205 | $form.Add_MouseRightButtonUp({ _QuitClock }) 206 | 207 | $form.Add_MouseLeftButtonDown({ 208 | #temporarily stop the timer while moving the clock 209 | $timer.stop() 210 | $form.DragMove() 211 | #update the positions 212 | $PSClockSettings.CurrentPosition = $form.left, $form.top 213 | #restart the timer 214 | $timer.start() 215 | }) 216 | 217 | #press + to increase the size and - to decrease 218 | #the clock needs to refresh to see the result 219 | $form.Add_KeyDown({ 220 | switch ($_.key) { 221 | { 'Add', 'OemPlus' -contains $_ } { 222 | If ( $PSClockSettings.fontSize -ge 8) { 223 | $PSClockSettings.fontSize++ 224 | $form.UpdateLayout() 225 | } 226 | } 227 | { 'Subtract', 'OemMinus' -contains $_ } { 228 | If ($PSClockSettings.FontSize -ge 8) { 229 | $PSClockSettings.FontSize-- 230 | $form.UpdateLayout() 231 | } 232 | } 233 | { 'P' -contains $_ } { 234 | #show the preview settings form 235 | Show-PSClockSettingPreview 236 | } 237 | } 238 | }) 239 | 240 | #fail safe to remove flag file 241 | $form.Add_Unloaded({ 242 | if (Test-Path $FlagPath) { 243 | Remove-Item $FlagPath 244 | } 245 | }) 246 | 247 | $stack = New-Object System.Windows.Controls.StackPanel 248 | 249 | $label = New-Object System.Windows.Controls.label 250 | $label.Content = Get-Date -Format $PSClockSettings.DateFormat 251 | 252 | $label.HorizontalContentAlignment = 'Center' 253 | $label.Foreground = $PSClockSettings.Color 254 | $label.FontStyle = $PSClockSettings.FontStyle 255 | $label.FontWeight = $PSClockSettings.FontWeight 256 | $label.FontSize = $PSClockSettings.FontSize 257 | $label.FontFamily = $PSClockSettings.FontFamily 258 | 259 | $label.VerticalAlignment = 'Top' 260 | 261 | $stack.AddChild($label) 262 | $form.AddChild($stack) 263 | 264 | $timer = New-Object System.Windows.Threading.DispatcherTimer 265 | $timer.Interval = [TimeSpan]'0:0:1.00' 266 | $timer.Add_Tick({ 267 | if ($PSClockSettings.Running) { 268 | $label.Foreground = $PSClockSettings.Color 269 | $label.FontStyle = $PSClockSettings.FontStyle 270 | $label.FontWeight = $PSClockSettings.FontWeight 271 | $label.FontSize = $PSClockSettings.FontSize 272 | $label.FontFamily = $PSClockSettings.FontFamily 273 | $label.Content = Get-Date -Format $PSClockSettings.DateFormat 274 | 275 | $form.TopMost = $PSClockSettings.OnTop 276 | $form.left = $PSClockSettings.CurrentPosition[0] 277 | $form.top = $PSClockSettings.CurrentPosition[1] 278 | $form.UpdateLayout() 279 | 280 | $PSClockSettings.CurrentPosition = $form.left, $form.top 281 | } 282 | else { 283 | _QuitClock 284 | } 285 | }) 286 | $timer.Start() 287 | 288 | $PSClockSettings.Running = $True 289 | $PSClockSettings.Started = Get-Date 290 | #Show the clock form 291 | [void]$form.ShowDialog() 292 | }) 293 | 294 | $PSCmd.runspace = $rs 295 | _verbose $strings.Launching 296 | [void]$PSCmd.BeginInvoke() 297 | Write-Information -MessageData $PSCmd -Tags raw 298 | 299 | _verbose ($strings.CreatingFlag -f "$FlagPath") 300 | "[{0}] PSClock started by {1} under PowerShell process id $pid" -f (Get-Date), $env:USERNAME | 301 | Out-File -FilePath $FlagPath 302 | 303 | if ($PassThru) { 304 | Start-Sleep -Seconds 1 305 | Get-PSClock 306 | } 307 | } #process 308 | End { 309 | _verbose ($strings.Ending -f $MyInvocation.MyCommand) 310 | } #end 311 | 312 | } #close function 313 | -------------------------------------------------------------------------------- /functions/Stop-PSClock.ps1: -------------------------------------------------------------------------------- 1 | Function Stop-PSClock { 2 | [CmdletBinding(SupportsShouldProcess)] 3 | [OutputType("none")] 4 | Param() 5 | 6 | _verbose ($strings.Starting -f $MyInvocation.MyCommand) 7 | _verbose ($strings.Running -f $PSVersionTable.PSVersion) 8 | _verbose ($strings.Detected -f $Host.Name) 9 | 10 | if ($PSClockSettings -And $PSClockSettings.Running) { 11 | if ($PSCmdlet.ShouldProcess("PSClock [runspace id $($PSClockSettings.runspace.id)]")) { 12 | $PSClockSettings.Running = $False 13 | } 14 | } 15 | else { 16 | Write-Warning $strings.CantFind 17 | } 18 | _verbose ($strings.Ending -f $MyInvocation.MyCommand) 19 | } 20 | -------------------------------------------------------------------------------- /functions/WPFFontPreview.ps1: -------------------------------------------------------------------------------- 1 | Function Show-FontPreview { 2 | [CmdletBinding()] 3 | Param( 4 | [Parameter(Position = 0, HelpMessage = "The default text to display")] 5 | [string]$SampleText = $(Get-Date -Format F) 6 | ) 7 | 8 | _verbose ($strings.Starting -f $MyInvocation.MyCommand) 9 | _verbose ($strings.Running -f $PSVersionTable.PSVersion) 10 | _verbose ($strings.Detected -f $Host.Name) 11 | 12 | _verbose $strings.LoadingFont 13 | $Families = [System.Drawing.text.installedFontCollection]::new().Families 14 | 15 | $defaultText = @" 16 | 17 | $sampleText 18 | 19 | "@ 20 | _verbose ($strings.UsingText -f $SampleText) 21 | _verbose $strings.definingWPF 22 | $window = [System.Windows.Window]@{ 23 | Title = 'Font Family Preview [Ctrl+Q to close]' 24 | Height = 325 25 | Width = 400 26 | WindowStartupLocation = 'CenterScreen' 27 | icon = [System.Windows.Media.ImageSource]"$PSScriptRoot\fonts.ico" 28 | } 29 | 30 | #add a handler to resize controls if the window is resized 31 | $window.Add_SizeChanged({ $txtPreview.Height = $window.Height - 200 }) 32 | 33 | #add a handler to go to next font if the > key is pressed 34 | $window.Add_KeyDown({ 35 | if ($_.Key -eq 'Right' -OR $_.Key -eq 'Down') { 36 | $comboFont.SelectedIndex++ 37 | } 38 | }) 39 | 40 | #add a handler to go to previous font if the < key is pressed 41 | $window.Add_KeyDown({ 42 | if (($comboFont.SelectedIndex -gt 0) -AND ($_.Key -eq 'Up' -OR $_.Key -eq 'Left' )) { 43 | $comboFont.SelectedIndex-- 44 | } 45 | }) 46 | 47 | #add a handler to close window with Ctrl+Q 48 | $window.Add_KeyDown({ 49 | if ($_.Key -eq 'Q' -AND $_.KeyboardDevice.Modifiers -eq 'Control') { 50 | $window.Close() 51 | } 52 | }) 53 | 54 | $Stack = [System.Windows.Controls.StackPanel]@{ 55 | Orientation = 'Vertical' 56 | Background = 'CornSilk' 57 | } 58 | $comboStyle = [System.Windows.Controls.ComboBox]@{ 59 | ItemsSource = 'Normal', 'Italic', 'Oblique' 60 | SelectedIndex = 0 61 | FontSize = 14 62 | Height = 25 63 | Width = 100 64 | ToolTip = 'Select a font style' 65 | HorizontalAlignment = 'Left' 66 | Margin = '5,5,0,0' 67 | } 68 | 69 | $comboStyle.Add_SelectionChanged({ 70 | $txtPreview.FontStyle = $comboStyle.SelectedItem 71 | }) 72 | 73 | $stack.AddChild($comboStyle) 74 | 75 | $comboFont = [System.Windows.Controls.ComboBox]@{ 76 | ItemsSource = $Families.Name 77 | SelectedIndex = 0 78 | FontSize = 14 79 | Height = 25 80 | Width = 250 81 | HorizontalAlignment = 'left' 82 | ToolTip = 'Select a font family' 83 | Margin = '5,5,0,0' 84 | } 85 | #change the text box to use the selected font 86 | $comboFont.Add_SelectionChanged({ $txtPreview.FontFamily = $comboFont.SelectedItem }) 87 | 88 | $Stack.AddChild($comboFont) 89 | 90 | $grid = [System.Windows.Controls.Grid]@{ 91 | Height = 25 92 | } 93 | 94 | $btnPrevious = [System.Windows.Controls.Button]@{ 95 | Content = '<' 96 | Width = 20 97 | HorizontalAlignment = 'Left' 98 | VerticalAlignment = 'Center' 99 | ToolTip = 'Previous Font' 100 | Margin = '10,5,0,0' 101 | } 102 | 103 | $btnPrevious.Add_Click({ 104 | if ($comboFont.SelectedIndex -gt 0) { 105 | $comboFont.SelectedIndex-- 106 | } 107 | }) 108 | 109 | $grid.AddChild($btnPrevious) 110 | 111 | $btnNext = [System.Windows.Controls.Button]@{ 112 | Content = '>' 113 | Width = 20 114 | HorizontalAlignment = 'Left' 115 | VerticalAlignment = 'Center' 116 | ToolTip = 'Next Font' 117 | Margin = '40,5,0,0' 118 | } 119 | 120 | $btnNext.Add_Click({ $comboFont.SelectedIndex++ }) 121 | 122 | $grid.AddChild($btnNext) 123 | $Stack.AddChild($grid) 124 | 125 | $txtPreview = [System.Windows.Controls.TextBox]@{ 126 | TextWrapping = 'Wrap' 127 | AcceptsReturn = $true 128 | VerticalScrollBarVisibility = 'Auto' 129 | HorizontalScrollBarVisibility = 'Auto' 130 | FontSize = 24 131 | Height = $window.Height - 200 132 | Width = $window.Width - 50 133 | FontFamily = $comboFont.SelectedItem 134 | FontStyle = 'Normal' 135 | Text = $DefaultText 136 | TextAlignment = 'Center' 137 | VerticalAlignment = 'Center' 138 | HorizontalAlignment = 'Center' 139 | Margin = '5,10,5,5' 140 | } 141 | 142 | $stack.AddChild($txtPreview) 143 | 144 | $btnReset = [System.Windows.Controls.Button]@{ 145 | Content = 'Reset' 146 | Width = 75 147 | HorizontalAlignment = 'Left' 148 | VerticalAlignment = 'Bottom' 149 | Margin = '5,25,0,0' 150 | ToolTip = 'Reset to default text and font' 151 | } 152 | $btnReset.Add_Click({ 153 | $txtPreview.Text = $defaultText 154 | $comboStyle.SelectedIndex = 0 155 | $comboFont.SelectedIndex = 0 156 | }) 157 | $stack.AddChild($btnReset) 158 | 159 | $window.AddChild($Stack) 160 | _verbose $strings.Showing 161 | [void]$Window.ShowDialog() 162 | 163 | _verbose ($strings.Ending -f $MyInvocation.MyCommand) 164 | 165 | } -------------------------------------------------------------------------------- /functions/fonts.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdhitsolutions/PSClock/b04882b571c2840fe77e9810f8ab88ea4d5bc2b3/functions/fonts.ico -------------------------------------------------------------------------------- /functions/private.ps1: -------------------------------------------------------------------------------- 1 | #these are private functions 2 | 3 | #define a custom Verbose function 4 | 5 | function _verbose { 6 | [CmdletBinding()] 7 | Param([string]$Message) 8 | 9 | $m = "[$([char]27)[3m{0}$([char]27)[0m] {1}" -f (Get-Date).TimeOfDay, $Message 10 | Microsoft.PowerShell.Utility\Write-Verbose $m 11 | } 12 | 13 | function Get-RGB { 14 | [CmdletBinding()] 15 | [OutputType('RGB')] 16 | Param( 17 | [Parameter(Mandatory, HelpMessage = 'Enter the name of a system color like Tomato')] 18 | [ValidateNotNullOrEmpty()] 19 | [String]$Name 20 | ) 21 | Try { 22 | $Color = [System.Drawing.Color]::FromName($Name) 23 | [PSCustomObject]@{ 24 | PSTypeName = 'RGB' 25 | Name = $Name 26 | Red = $color.R 27 | Green = $color.G 28 | Blue = $color.B 29 | } 30 | } 31 | Catch { 32 | Throw $_ 33 | } 34 | } 35 | function Convert-RGBtoAnsi { 36 | #This will write an opening ANSI escape sequence to the pipeline 37 | [CmdletBinding()] 38 | [OutputType('String')] 39 | Param( 40 | [parameter(Position = 0, ValueFromPipelineByPropertyName)] 41 | [Int]$Red, 42 | [parameter(Position = 1, ValueFromPipelineByPropertyName)] 43 | [Int]$Green, 44 | [parameter(Position = 2, ValueFromPipelineByPropertyName)] 45 | [Int]$Blue 46 | ) 47 | Process { 48 | "$([char]27)[38;2;{0};{1};{2}m" -f $red, $green, $blue 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /images/custom-verbose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdhitsolutions/PSClock/b04882b571c2840fe77e9810f8ab88ea4d5bc2b3/images/custom-verbose.png -------------------------------------------------------------------------------- /images/get-psclock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdhitsolutions/PSClock/b04882b571c2840fe77e9810f8ab88ea4d5bc2b3/images/get-psclock.png -------------------------------------------------------------------------------- /images/psclock-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdhitsolutions/PSClock/b04882b571c2840fe77e9810f8ab88ea4d5bc2b3/images/psclock-preview.png -------------------------------------------------------------------------------- /images/psclock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdhitsolutions/PSClock/b04882b571c2840fe77e9810f8ab88ea4d5bc2b3/images/psclock.png -------------------------------------------------------------------------------- /images/pstoolmaking-thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdhitsolutions/PSClock/b04882b571c2840fe77e9810f8ab88ea4d5bc2b3/images/pstoolmaking-thumbnail.png -------------------------------------------------------------------------------- /images/sample-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdhitsolutions/PSClock/b04882b571c2840fe77e9810f8ab88ea4d5bc2b3/images/sample-1.png -------------------------------------------------------------------------------- /images/sample-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdhitsolutions/PSClock/b04882b571c2840fe77e9810f8ab88ea4d5bc2b3/images/sample-2.png -------------------------------------------------------------------------------- /images/sample-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdhitsolutions/PSClock/b04882b571c2840fe77e9810f8ab88ea4d5bc2b3/images/sample-3.png -------------------------------------------------------------------------------- /images/set-psclock-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdhitsolutions/PSClock/b04882b571c2840fe77e9810f8ab88ea4d5bc2b3/images/set-psclock-color.png -------------------------------------------------------------------------------- /images/show-fontpreview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdhitsolutions/PSClock/b04882b571c2840fe77e9810f8ab88ea4d5bc2b3/images/show-fontpreview.png -------------------------------------------------------------------------------- /images/tab-complete-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdhitsolutions/PSClock/b04882b571c2840fe77e9810f8ab88ea4d5bc2b3/images/tab-complete-example.png -------------------------------------------------------------------------------- /tests/PSClock.tests.ps1: -------------------------------------------------------------------------------- 1 | #To be written --------------------------------------------------------------------------------