Skip to content

Commit

Permalink
Merge pull request #8 from StefanGreve/1.5.0
Browse files Browse the repository at this point in the history
1.5.0
  • Loading branch information
StefanGreve authored Jun 1, 2023
2 parents c7ef263 + e699c7e commit 99dc4aa
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 34 deletions.
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*.ps1]
end_of_line = lf
indent_style = space
indent_size = 4
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
80 changes: 71 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,85 @@ New-Item -Path $ProfilePath -ItemType SymbolicLink -Value $(Resolve-Path profile

## Configuration

Enable storing daily transcript:
Some additional features can be turned on by setting their respective environment
variables:

```powershell
Set-EnvironmentVariable -Key PROFILE_ENABLE_DAILYTRANSCRIPTS -Value 1
```
- `PROFILE_ENABLE_DAILY_TRANSCRIPTS`: Set this environment variable to `1` to
enable automatic transcript storing in `MyDocuments\Transcripts` (off by default.)

- `PROFILE_LOAD_CUSTOM_SCRIPTS`: Declare a single path to dot-source Powershell
scripts from on profile launch.

## Features

<details>
<summary>Content</summary>

### System Maintenance

- `Update-Configuration`
- `Update-System`

### Utilities

- `Get-Battery`
- `Get-Calendar`
- `Set-PowerState`
- `Set-EnvironmentVariable`
- `Get-EnvironmentVariable`
- `Get-WorldClock`
- `Remove-EnvironmentVariable`
- `Start-DailyTranscript`
- `Start-ElevatedConsole`
- `Start-Timer`

### Development

- `Export-Branch`
- `Get-NameOf`
- `Get-ExecutionTime`
- `Measure-ScriptBlock`
- `New-DotnetProject`
- `Stop-Work`

### File Extensions

- `Copy-FilePath`
- `Export-Icon`
- `Get-FileCount`
- `Get-FileSize`
- `Get-FilePath`
- `Get-MaxPathLength`
- `Remove-Directory`

### Cryptography

- `Get-Salt`
- `Get-StringHash`
- `Get-RandomPassword`

### Miscellaneous

- `Get-XCKD`

### Enums

- `OS`
- `Month`

</details>

## Remarks

Some optional external dependencies may be added over time, although they will never
interfere with the core features of this profile.
While this script attempts to be as lightweight as possible, a few externals are
required to run some of the Cmdlets from this profile.

<details>
<summary>Additional Features</summary>

### Winfetch

Creates an alias for [`winfetch`](https://github.com/kiedtl/winfetch) as a faster
replacement for `neofetch` on Windows.
Creates an alias for `neofetch` using https://github.com/kiedtl/winfetch on Windows.

```powershell
Install-Script -Name pwshfetch-test-1 -Scope CurrentUser
Expand All @@ -53,6 +114,7 @@ requires [`inkscape`](https://inkscape.org/) for the actual image conversion.
### Get-Calendar

Thin wrapper over Python's built-in `calendar` module to pretty print a calendar.
Notice that this Cmdlet does *not* emit a PowerShell object.
Notice that this Cmdlet does *not* emit a PowerShell object. The behavior of this
Cmdlet is subject to future changes, see alo: [issue #9](https://github.com/StefanGreve/profile/issues/9).

</details>
135 changes: 110 additions & 25 deletions profile.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using namespace System
using namespace System.Collections.Generic
using namespace System.Diagnostics
using namespace System.Globalization
using namespace System.IO
Expand All @@ -14,8 +15,8 @@ using namespace Microsoft.PowerShell

$global:ProfileVersion = [PSCustomObject]@{
Major = 1
Minor = 4
Patch = 1
Minor = 5
Patch = 0
}

$global:OperatingSystem = if ([OperatingSystem]::IsWindows()) {
Expand All @@ -31,6 +32,12 @@ $global:OperatingSystem = if ([OperatingSystem]::IsWindows()) {
[CultureInfo]::CurrentCulture = "ja-JP"
$PSDefaultParameterValues["*:Encoding"] = "utf8"

if ($env:PROFILE_LOAD_CUSTOM_SCRIPTS) {
Get-ChildItem -Path $env:PROFILE_LOAD_CUSTOM_SCRIPTS -Filter "*.ps1" | ForEach-Object {
. $_.FullName
}
}

if ([OperatingSystem]::IsWindows()) {
$global:PSRC = "$HOME\Documents\PowerShell\profile.ps1"
$global:VSRC = "$env:APPDATA\Code\User\settings.json"
Expand All @@ -45,6 +52,10 @@ if ([OperatingSystem]::IsWindows()) {
$global:IsAdmin = ([Principal.WindowsPrincipal][Principal.WindowsIdentity]::GetCurrent()).IsInRole([Principal.WindowsBuiltInRole]::Administrator)
}

if ([OperatingSystem]::IsLinux()) {
$global:IsAdmin = $(id -u) -eq 0
}

$global:Desktop = [Environment]::GetFolderPath("Desktop")
$global:Documents = [Environment]::GetFolderPath("MyDocuments")
$global:Natural = { [Regex]::Replace($_.Name, '\d+', { $Args[0].Value.PadLeft(20) }) }
Expand Down Expand Up @@ -215,7 +226,18 @@ function Update-System {
}

if ($Applications.IsPresent || $All.IsPresent) {
winget upgrade --all --silent
switch ($global:OperatingSystem) {
([OS]::Windows) {
winget upgrade --all --silent
}
([OS]::Linux) {
apt-get update
apt-get full-upgrade --yes
}
([OS]::MacOS) {
brew upgrade
}
}
}

if ($Modules.IsPresent || $All.IsPresent) {
Expand Down Expand Up @@ -375,7 +397,7 @@ function Get-FileCount {
[Parameter(Position = 0, Mandatory, ValueFromPipeline)]
[string[]] $Path,

[SearchOption] $SearchOption = [SearchOption]::TopDirectoryOnly
[SearchOption] $SearchOption = [SearchOption]::AllDirectories
)

process {
Expand All @@ -386,6 +408,33 @@ function Get-FileCount {
}
}

function Remove-Directory {
[Alias("rd")]
[OutputType([void])]
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = "High")]
param(
[Parameter(Position = 0, ValueFromPipeline, Mandatory)]
[string[]] $Path
)

process {
foreach ($p in $Path) {
$Directory = [Path]::Combine($PWD.Path, $p)

if (![Directory]::Exists($Directory)) {
Write-Warning "Not a directory: $Directory"
continue
}

if ($PSCmdlet.ShouldProcess($Directory, "Remove $Path")) {
$SystemEntries = [Directory]::GetFileSystemEntries($Directory, "*.*", [SearchOption]::AllDirectories)
Remove-Item -Recurse -Force -Path $Directory
Write-Verbose "Removed $($SystemEntries.Count) file(s) in $Directory"
}
}
}
}

function Copy-FilePath {
[Alias("copy")]
[OutputType([void])]
Expand All @@ -400,6 +449,31 @@ function Copy-FilePath {
}
}

function Get-MaxPathLength {
process {
switch ($global:OperatingSystem) {
([OS]::Windows) {
# On Windows, file names cannot exceed 256 bytes. Starting in Windows 10 (version 1607), the limit max
# path limit can be extended via setting this registry key to a value of 1 (property type: DWORD)
# https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry
$FileSystem = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled"
$MaxPathLength = $FileSystem.LongPathsEnabled -eq 1 ? 32767 : 260
Write-Output $MaxPathLength
}
([OS]::Linux) {
# On virtually all file systems, file names are restricted to 255 bytes in length (cf. NAME_MAX).
# PATH_MAX equals 4096 bytes in Unix environments, though Unix can deal with longer file paths by using
# relative paths or symbolic links. To convert bytes to characters, you need to know the encoding ahead
# of time. For example, an ASCII or Unicode character in UTF-8 is 8 bits (1 byte), while a Unicode character
# in UTF-16 may take between 16 bits (2 bytes) and 32 bits (4 bytes) in memory, whereas UTF-32 encoded
# Unicode characters always require 32 bits (4 bytes) of memory
$MaxPathLength = getconf PATH_MAX /
Write-Output $MaxPathLength
}
}
}
}

class Battery
{
[int] $ChargeRemaining
Expand Down Expand Up @@ -603,6 +677,7 @@ function Get-RandomPassword {
}

function New-DotnetProject {
[OutputType([void])]
param(
[Parameter(Mandatory)]
[string] $Name,
Expand All @@ -626,19 +701,19 @@ function New-DotnetProject {
Push-Location $OutputDirectory
}
process {
dotnet new sln
dotnet new $Template --name $Name --language $Language --output $RootDirectory
dotnet new gitignore --output $OutputDirectory
dotnet new editorconfig --output $OutputDirectory
dotnet sln add $Name
dotnet restore $OutputDirectory
dotnet build $OutputDirectory
dotnet restore $RootDirectory
dotnet build $RootDirectory

$Readme = New-Item -ItemType File -Name "README.md" -Path $OutputDirectory
Set-Content $Readme -Value "# $Name"

$Packages | ForEach-Object {
dotnet add $RootDirectory package $_
if ($PSBoundParameters.ContainsKey("Packages")) {
$Packages | ForEach-Object {
dotnet add $RootDirectory package $_
}
}

if ($InitRepository.IsPresent) {
Expand All @@ -647,7 +722,7 @@ function New-DotnetProject {
git commit -m "Init commit"
}
}
end {
clean {
Pop-Location
}
}
Expand Down Expand Up @@ -876,12 +951,14 @@ function Set-EnvironmentVariable {
[string] $Value,

[Parameter(Position = 2)]
[EnvironmentVariableTarget] $Scope = [EnvironmentVariableTarget]::User
[EnvironmentVariableTarget] $Scope = [EnvironmentVariableTarget]::Process,

[switch] $Override
)

$Token = $global:OperatingSystem -eq [OS]::Windows ? ";" : ":"
$Token = [OperatingSystem]::IsWindows() ? ";" : ":"

$OldValue = [Environment]::GetEnvironmentVariable($Key, $Scope)
$OldValue = $Override.IsPresent ? [string]::Empty : [Environment]::GetEnvironmentVariable($Key, $Scope)
$NewValue = $OldValue.Length ? [string]::Join($Token, $OldValue, $Value) : $Value

if ($PSCmdlet.ShouldProcess("Adding $Value to $Key", "Are you sure you want to add '$Value' to the environment variable '$Key'?", "Add '$Value' to '$Key'")) {
Expand All @@ -897,10 +974,10 @@ function Get-EnvironmentVariable {
[string] $Key = "PATH",

[Parameter(Position = 1)]
[EnvironmentVariableTarget] $Scope = [EnvironmentVariableTarget]::User
[EnvironmentVariableTarget] $Scope = [EnvironmentVariableTarget]::Process
)

$Token = $global:OperatingSystem -eq [OS]::Windows ? ";" : ":"
$Token = [OperatingSystem]::IsWindows() ? ";" : ":"

$EnvironmentVariables = [Environment]::GetEnvironmentVariable($Key, $Scope) -Split $Token
Write-Output $EnvironmentVariables
Expand All @@ -913,17 +990,25 @@ function Remove-EnvironmentVariable {
[Parameter(Position = 0, Mandatory)]
[string] $Key,

[Parameter()]
[Parameter(Position = 1)]
[string] $Value,

[EnvironmentVariableTarget] $Scope = [EnvironmentVariableTarget]::User
[EnvironmentVariableTarget] $Scope = [EnvironmentVariableTarget]::Process
)

$Token = $global:OperatingSystem -eq [OS]::Windows ? ";" : ":"
$Token = [OperatingSystem]::IsWindows() ? ";" : ":"

$RemoveValue = $Key -eq "PATH" ? $([Environment]::GetEnvironmentVariable("PATH", $Scope) -Split $Token | Where-Object { $_ -ne $Value }) -join $Token : $null
$Title = "Remove '$Value' from '$Key'"
$Description = "Are you sure that you want to remove '$Value' from the environment variable '$Key'?"
$RemoveValue = $([Environment]::GetEnvironmentVariable($Key, $Scope) -Split $Token | Where-Object { $_ -ne $Value }) -join $Token

if (!$PSBoundParameters.ContainsKey("Value")) {
$Title = "Remove all values in '$Key'"
$Description = "Are you sure that you want to remove the environment variable '$Key'?"
$RemoveValue = $null
}

if ($PSCmdlet.ShouldProcess("Removing value '$Value' from environment variable '$Key'", "Are you sure you want to remove '$Value' from the environment variable '$Key'?", "Remove '$Value' from '$Key'")) {
if ($PSCmdlet.ShouldProcess($null, $Description, $Title)) {
[Environment]::SetEnvironmentVariable($Key, $RemoveValue, $Scope)
}
}
Expand Down Expand Up @@ -999,7 +1084,7 @@ function Measure-ScriptBlock {

begin {
$StopWatch = [Stopwatch]::new()
$Measurements = New-Object System.Collections.Generic.List[System.TimeSpan]
$Measurements = New-Object List[System.TimeSpan]

if (![Stopwatch]::IsHighResolution) {
Write-Error -Message "Your hardware doesn't support the high resolution counter required to run this test" -Category DeviceError -ErrorAction Stop
Expand Down Expand Up @@ -1178,7 +1263,7 @@ function Start-DailyTranscript {
$Filename = [Path]::Combine($Transcripts, [string]::Format("{0}.txt", [datetime]::Now.ToString("yyyy-MM-dd")))
}
process {
if ($env:PROFILE_ENABLE_DAILYTRANSCRIPTS -eq 1) {
if ($env:PROFILE_ENABLE_DAILY_TRANSCRIPTS -eq 1) {
Write-Verbose "Started a new transcript, output file is $Filename"
Start-Transcript -Path $Filename -Append -IncludeInvocationHeader -UseMinimalHeader | Out-Null
}
Expand All @@ -1190,7 +1275,7 @@ function Start-DailyTranscript {

function Get-ExecutionTime {
$History = Get-History
$ExecTime = if ($History) { $History[-1].EndExecutionTime - $History[-1].StartExecutionTime } else { New-TimeSpan }
$ExecTime = $History ? ($History[-1].EndExecutionTime - $History[-1].StartExecutionTime) : (New-TimeSpan)
Write-Output $ExecTime
}

Expand All @@ -1201,7 +1286,7 @@ function Get-ExecutionTime {
$EnvironmentVariableKeyCompleter = {
param($Command, $Parameter, $WordToComplete, $CommandAst, $FakeBoundParameters)

$Scope = $FakeBoundParameters.ContainsKey("Scope") ? $FakeBoundParameters.Scope : [EnvironmentVariableTarget]::User
$Scope = $FakeBoundParameters.ContainsKey("Scope") ? $FakeBoundParameters.Scope : [EnvironmentVariableTarget]::Process
[Environment]::GetEnvironmentVariables($Scope).Keys | ForEach-Object { [CompletionResult]::new($_) }
}

Expand Down

0 comments on commit 99dc4aa

Please sign in to comment.