Update tools and template

This commit is contained in:
2025-02-28 15:51:21 -06:00
parent ce8db4db9a
commit 950f9b63f8
2 changed files with 241 additions and 110 deletions

View File

@@ -16,10 +16,12 @@
param ( param (
# Allows modules required by the script to be predefined, and loaded or installed as needed # Allows modules required by the script to be predefined, and loaded or installed as needed
[Parameter(DontShow = $true)] [Array] $ModuleNames = @(), [Parameter(DontShow = $true)] [Array] $ModuleNames = @(),
# Sets the script storage directory into the user profile instead of in the ProgramData folder # Sets the script storage location
[Parameter(Mandatory = $false)] [Switch] $UserScript = $false, [Parameter(DontShow = $true)] [ValidateSet('System', 'User', 'Custom')] [String] $ScriptType = "System",
# Allows adding verbose logging and what-if command simulation to the script
[Parameter(DontShow = $true)] [Switch] $Dev,
# Allows for the script logs to output to a nonstandard location. Overrides user/computer script paths # Allows for the script logs to output to a nonstandard location. Overrides user/computer script paths
[Parameter(Mandatory = $false)] [String] $LogDir, [Parameter(Mandatory = $false)] [String] $ScriptDir,
# Flag to disable log file output # Flag to disable log file output
[Parameter(Mandatory = $false)] [Switch] $NoLog, [Parameter(Mandatory = $false)] [Switch] $NoLog,
# Allows for uninstallation of script # Allows for uninstallation of script
@@ -55,7 +57,7 @@ If ($Env:PROCESSOR_ARCHITECTURE -ne "AMD64") {
#endregion Architecture Check #endregion Architecture Check
#region Imports #region Imports
# Import Test-CommandExists, Add-LogEntry, Add-ListItem, Start-Logging, Import-JSONConfig # Import Test-CommandExists, Add-LogEntry, Add-ListItem, Import-JSONConfig, Import-YAMLConfig, Set-RegistryKey, Test-AsAdmin, Format-Hyperlink
Invoke-WebRequest "https://gitea.taco.quest/Mindfang/ProjectTools/raw/branch/main/PSUtilities/ScriptTools.ps1" -OutFile "$Env:Temp\ScriptTools.ps1" Invoke-WebRequest "https://gitea.taco.quest/Mindfang/ProjectTools/raw/branch/main/PSUtilities/ScriptTools.ps1" -OutFile "$Env:Temp\ScriptTools.ps1"
Import-Module -Name "$Env:Temp\ScriptTools.ps1" -Force Import-Module -Name "$Env:Temp\ScriptTools.ps1" -Force
#endregion Imports #endregion Imports
@@ -66,11 +68,13 @@ Import-Module -Name "$Env:Temp\ScriptTools.ps1" -Force
#region Prep #region Prep
# Set the working directory for logs and additional files # Set the working directory for logs and additional files
$ThisScript = ([IO.FileInfo]$MyInvocation.MyCommand.Definition).BaseName $ThisScript = ([IO.FileInfo]$MyInvocation.MyCommand.Definition).BaseName
If ($UserScript) { Switch ($ScriptType) {
$AppDir = "$Env:AppData\Mindfang\$ThisScript" "System" { $AppDir = "$Env:AppData\Mindfang\$ThisScript" }
"User" { $AppDir = "$Env:ProgramData\Mindfang\$ThisScript" }
"Custom" {
If ($ScriptDir) { $AppDir = $ScriptDir }
Else { $AppDir = $PWD }
} }
Else {
$AppDir = "$Env:ProgramData\Mindfang\$ThisScript"
} }
# Create specified appdir if it does not already exist # Create specified appdir if it does not already exist
@@ -79,7 +83,7 @@ If (-Not (Test-Path $AppDir)) {
} }
# Begin recording transcript file # Begin recording transcript file
If (-not $NoLog) { If (-Not $NoLog) {
If (-not $LogDir) { If (-not $LogDir) {
$LogDir = $AppDir $LogDir = $AppDir
} }
@@ -87,8 +91,41 @@ If (-not $NoLog) {
} }
# Load any modules required by script # Load any modules required by script
If ($ModuleNames) {
If ([Net.ServicePointManager]::SecurityProtocol -ne [Net.SecurityProtocolType]::SystemDefault) {
Add-LogEntry "Upgrading TLS security protocol to 1.2"
Try { [Net.ServicePointManager]::SecurityProtocol = @([Net.SecurityProtocolType]::Tls, [Net.SecurityProtocolType]::Tls11, [Net.SecurityProtocolType]::Tls12) }
Catch {
Add-LogEntry "TLS upgrade failed, script is exiting" -As Error
Exit
}
}
If ((Get-PackageProvider).Name -notcontains "NuGet") {
Add-LogEntry "Installing NuGet package provider"
Try { Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -ErrorAction Stop }
Catch {
Add-LogEntry "Installation failed, script is exiting" -As Error
Exit
}
}
If ((Get-PSRepository).Name -notcontains "PSGallery") {
Add-LogEntry "Registering PSGallery as script source"
Try { Register-PSRepository -Default -InstallationPolicy Trusted -ErrorAction Stop }
Catch {
Add-LogEntry "Unable to register PSGallery, script is exiting" -As Error
Exit
}
}
ElseIf (Get-PSRepository | Where-Object { $_.Name -eq "PSGallery" -and $_.InstallationPolicy -ne "Trusted" }) {
Add-LogEntry "Trusting packages from PSGallery"
Try { Set-PSRepository PSGallery -InstallationPolicy Trusted -ErrorAction Stop }
Catch {
Add-LogEntry "Unable to set PSGallery as trusted, script is exiting" -As Error
Exit
}
}
ForEach ($Module in $ModuleNames) { ForEach ($Module in $ModuleNames) {
If (-not(Get-Module -ListAvailable -Name $Module)) { If (-Not (Get-Module -ListAvailable -Name $Module)) {
Try { Try {
Add-LogEntry "Module `"$Module`" not found, installing" Add-LogEntry "Module `"$Module`" not found, installing"
Install-Module -Name $Module -Scope CurrentUser -Force -AllowClobber Install-Module -Name $Module -Scope CurrentUser -Force -AllowClobber
@@ -100,11 +137,12 @@ ForEach ($Module in $ModuleNames) {
} }
Import-Module $Module Import-Module $Module
} }
}
#endregion Prep #endregion Prep
#region Execution #region Execution
Try { Try {
If ( -not $Uninstall) { If (-Not $Uninstall) {
#TODO: "Install actions" for the script go here #TODO: "Install actions" for the script go here
} }
Else { Else {
@@ -113,14 +151,16 @@ Try {
} }
Catch { Catch {
# Write error to logs, if an exception is caught # Write error to logs, if an exception is caught
Write-Output "Script execution failed!" Write-Host "Script execution failed!"
Write-Output $_ Write-Host $_
Write-Output $_.InvocationInfo Write-Host $_.InvocationInfo
Write-Output $_.ScriptStackTrace Write-Host $_.ScriptStackTrace
Exit 1 Exit 1
} }
Finally { Finally {
# Stop transcript, even if an error has occurred # Stop transcript, even if an error has occurred
If (-Not $NoLog) {
Stop-Transcript Stop-Transcript
} }
}
#endregion Execution #endregion Execution

View File

@@ -32,23 +32,13 @@ Function Test-CommandExists {
Detail on what the script does, if this is needed. Detail on what the script does, if this is needed.
#> #>
Param ( Param (
$Command [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $Command
) )
$OldPreference = $ErrorActionPreference
$ErrorActionPreference = 'Stop'
Try { Try {
If (Get-Command $Command) { If (Get-Command $Command -ErrorAction Stop) { Return $true }
Return $true
}
}
Catch {
Return $false
}
Finally {
$ErrorActionPreference = $OldPreference
} }
Catch { Return $false }
} }
Function Add-LogEntry { Function Add-LogEntry {
@@ -85,23 +75,24 @@ Function Add-LogEntry {
Detail on what the script does, if this is needed. Detail on what the script does, if this is needed.
#> #>
Param ( Param (
[Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()]$Message, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $Message,
[Parameter(Mandatory = $false)] [ValidateSet('Notify', 'Warning', 'Error')]$As, [Parameter(Mandatory = $false)] [ValidateSet('Notify', 'Warning', 'Error', 'Debug')] [String] $As,
[Parameter(Mandatory = $false)] [Switch] $NewLine [Parameter(Mandatory = $false)] [Switch] $NewLine
) )
Switch ($As) { Switch ($As) {
"Notify" { $FGC = "Cyan" } "Notify" { $FGC = "Cyan" }
"Warning" { $FGC = "Yellow" } "Warning" { $FGC = "Yellow" }
"Error" { $FGC = "Red" } "Error" { $FGC = "Red" }
"Debug" { $FGC = "Magenta" }
Default { $FGC = "White" } Default { $FGC = "White" }
} }
If ($Newline) { $Output += "`n" }
If ($Newline) { $Output += "`n" }
$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$Output += "[$Timestamp] $Message" $Output += "[$Timestamp] $Message"
Write-Host $Output -ForegroundColor $FGC If ($As -eq "Debug") { If ($Dev) { Write-Host $Output -ForegroundColor $FGC } }
Else { Write-Host $Output -ForegroundColor $FGC }
} }
Function Add-ListItem () { Function Add-ListItem () {
@@ -138,75 +129,16 @@ Function Add-ListItem () {
Detail on what the script does, if this is needed. Detail on what the script does, if this is needed.
#> #>
Param ( Param (
[Parameter(Mandatory = $true)] [ValidateNotNullorEmpty()]$Message, [Parameter(Mandatory = $true)] [ValidateNotNullorEmpty()] [String] $Message,
[Parameter(Mandatory = $false)] [Int16] $Indent = 0 [Parameter(Mandatory = $false)] [Int16] $Indent = 0
) )
For ($Counter = 0; $Counter -le $Indent; $Counter++) { $Output += "`t" } For ($Counter = 0; $Counter -le $Indent; $Counter++) { $Output += " " }
$Output += "* $Message" $Output += "* $Message"
Write-Host $Output Write-Host $Output
} }
Function Start-Logging {
<#
.SYNOPSIS
A brief description of the function or script.
.DESCRIPTION
A longer description.
.PARAMETER FirstParameter
Description of each of the parameters.
Note:
To make it easier to keep the comments synchronized with changes to the parameters,
the preferred location for parameter documentation comments is not here,
but within the param block, directly above each parameter.
.PARAMETER SecondParameter
Description of each of the parameters.
.INPUTS
Description of objects that can be piped to the script.
.OUTPUTS
Description of objects that are output by the script.
.EXAMPLE
Example of how to run the script.
.LINK
Links to further documentation.
.NOTES
Detail on what the script does, if this is needed.
#>
Param (
[Parameter(Mandatory)][String]$ScriptName,
[String]$LogDir,
[Switch]$User,
[Switch]$Append
)
If (Not $LogDir -eq $null) {
If ($User) {
$LogDir = "$Env:USERPROFILE\Mindfang\$ScriptName"
}
Else {
$LogDir = "$Env:ProgramData\Mindfang\$ScriptName"
}
}
If ($Append) {
Add-LogEntry (Start-Transcript -Path "$LogDir\$ScriptName.log" -Append)
}
Else {
Add-LogEntry (Start-Transcript -Path "$LogDir\$ScriptName.log")
}
}
Function Import-JSONConfig () { Function Import-JSONConfig () {
<# <#
.SYNOPSIS .SYNOPSIS
@@ -242,21 +174,180 @@ Function Import-JSONConfig () {
#> #>
Param ( Param (
[Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] $ConfigFile [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $ConfigFile
) )
If (Test-Path -Path $ConfigFile) { If (Test-Path -Path $ConfigFile) {
Try { Try {
Return (Get-Content -Raw -Path $ConfigFile | ConvertFrom-Json) Return (Get-Content -Raw -Path $ConfigFile | ConvertFrom-Json)
} }
Catch { Catch {
Add-LogEntry "Error loading config file! Please make sure the correct path was provided, and that it is a properly formatted JSON file" -As Error Write-Output "Error loading config file! Please make sure the correct path was provided, and that it is a properly formatted JSON file" -As Error
Write-Host $_ Write-Output $_
Exit 1 Exit 1
} }
} }
Else { Else {
Add-LogEntry "Error loading config file! Please make sure the correct path was provided, and that it is a properly formatted JSON file" -As Error Write-Output "Error loading config file! Please make sure the correct path was provided, and that it is a properly formatted JSON file" -As Error
Write-Host $_ Write-Output $_
Exit 1 Exit 1
} }
} }
Function Import-YAMLConfig () {
<#
.SYNOPSIS
A brief description of the function or script.
.DESCRIPTION
A longer description.
.PARAMETER FirstParameter
Description of each of the parameters.
Note:
To make it easier to keep the comments synchronized with changes to the parameters,
the preferred location for parameter documentation comments is not here,
but within the param block, directly above each parameter.
.PARAMETER SecondParameter
Description of each of the parameters.
.INPUTS
Description of objects that can be piped to the script.
.OUTPUTS
Description of objects that are output by the script.
.EXAMPLE
Example of how to run the script.
.LINK
Links to further documentation.
.NOTES
Detail on what the script does, if this is needed.
#>
Param (
[Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $ConfigFile
)
If (Test-CommandExists -Command "ConvertFrom-Yaml") {
If (Test-Path -Path $ConfigFile) {
Try {
Return (Get-Content -Raw -Path $ConfigFile | ConvertFrom-Json)
}
Catch {
Write-Output "Error loading config file! Please make sure the correct path was provided, and that it is a properly formatted JSON file" -As Error
Write-Output $_
Exit 1
}
}
Else {
Write-Output "Error loading config file! Please make sure the correct path was provided, and that it is a properly formatted JSON file" -As Error
Write-Output $_
Exit 1
}
}
Else {
Write-Output "Cannot import YAML config, module `"powershell-yaml`" is not installed"
Exit 1
}
}
Function Set-RegistryKey {
Param(
[Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] $TestPath,
[Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] $TestKey,
[Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] $TestValue,
[Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] $TestType
)
If (-Not (Test-Path -Path $TestPath)) {
Write-Output "Registry path not found, creating..."
New-Item $TestPath -Force -ErrorAction SilentlyContinue | Out-Null
}
If ($null -ne (Get-Item -Path $TestPath).GetValue($TestKey)) {
If ((Get-ItemPropertyValue -Path $TestPath -Name $TestKey) -eq $TestValue) {
Write-Output "Current key value is `"$((Get-Item -Path $TestPath).GetValue($TestKey))`", no action needed"
}
Else {
Write-Output "Setting value of `"$($TestKey)`" to `"$($TestValue)`""
Set-ItemProperty -Path $TestPath -Name $TestKey -Value $TestValue
}
}
Else {
Write-Output "Registry key does not exist, creating..."
New-ItemProperty -Path $TestPath -Name $TestKey -Value $TestValue -PropertyType $TestType -Force -ErrorAction SilentlyContinue | Out-Null
}
}
Function Test-AsAdmin () {
<#
.SYNOPSIS
A brief description of the function or script.
.DESCRIPTION
A longer description.
.PARAMETER FirstParameter
Description of each of the parameters.
Note:
To make it easier to keep the comments synchronized with changes to the parameters,
the preferred location for parameter documentation comments is not here,
but within the param block, directly above each parameter.
.PARAMETER SecondParameter
Description of each of the parameters.
.INPUTS
Description of objects that can be piped to the script.
.OUTPUTS
Description of objects that are output by the script.
.EXAMPLE
Example of how to run the script.
.LINK
Links to further documentation.
.NOTES
Detail on what the script does, if this is needed.
#>
Param (
[Parameter(Mandatory = $false)] [String] $AdditionalFlags
)
Write-Output "Checking to see if script has been run with administrative privileges"
if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
Write-Output "Performing script elevation, please approve the admin prompt"
Start-Sleep -Seconds 3
if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
$CommandLine = "$AdditionalFlags -File `"" + $MyInvocation.MyCommand.Path + "`" " + (Save-Parameters $MyInvocation.BoundParameters) + " " + $MyInvocation.UnboundArguments
Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
Exit
}
}
Else {
Write-Output "Script already running as admin"
}
}
# Origin: https://lucyllewy.com/powershell-clickable-hyperlinks/
Function Format-Hyperlink {
Param(
[Parameter(ValueFromPipeline = $true, Position = 0)][ValidateNotNullOrEmpty()] [Uri] $Uri,
[Parameter(Mandatory = $false, Position = 1)] [String] $Label
)
If (($PSVersionTable.PSVersion.Major -lt 6 -or $IsWindows) -and -not $Env:WT_SESSION) {
# Fallback for Windows users not inside Windows Terminal
If ($Label) {
Return "$Label ($Uri)"
}
Return "$Uri"
}
If ($Label) {
Return "`e]8;;$Uri`e\$Label`e]8;;`e\"
}
Return "$Uri"
}