diff --git a/CHANGELOG.md b/CHANGELOG.md index 327388e..8e94509 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,32 @@ All notable changes to the [PSTK](https://github.com/Akaizoku/PSTK) project will The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.2.6](https://github.com/Akaizoku/PSTK/releases/1.2.6) - 2024-10-07 + +Quality of life + +### Added + +The following functions have been added: + +- Ping-Host: Check connectivity to a specified host +- Show-EnvironmentVariables: Fetch environment variables +- Get-PowerShellError: Returns the latest error +- New-ProcessObject: Create standardised process object to monitor custom processes +- Update-ProcessObject: Update standardised process object to monitor custom processes + +### Changed + +The following functions have been updated: + +- Get-Properties: Now provides an option to pull metadata such as section and description +- Read-Properties: Now provides an option to pull metadata such as section and description +- Write-Log: Added notice message option + +### Fixed + +- Compare-Version: Fixed version comparison issues by using built-in version compare function when applciable + ## [1.2.5](https://github.com/Akaizoku/PSTK/releases/1.2.5) - 2021-11-21 Maintenance automation and incremental update diff --git a/PSTK.psd1 b/PSTK.psd1 index e18fa13..e12f06c 100644 --- a/PSTK.psd1 +++ b/PSTK.psd1 @@ -3,7 +3,7 @@ # # Generated by: Florian Carrier # -# Generated on: 21/11/2021 +# Generated on: 24/09/2024 # @{ @@ -12,7 +12,7 @@ RootModule = 'PSTK.psm1' # Version number of this module. -ModuleVersion = '1.2.5' +ModuleVersion = '1.2.6' # Supported PSEditions # CompatiblePSEditions = @() @@ -24,28 +24,28 @@ GUID = '065d3e48-45c0-4b6b-9052-b92fe22b4e51' Author = 'Florian Carrier' # Company or vendor of this module -CompanyName = '' +CompanyName = 'Unknown' # Copyright statement for this module -Copyright = '(c) 2019-2021 Florian Carrier. All rights reserved.' +Copyright = '(c) 2019-2024 Florian Carrier. All rights reserved.' # Description of the functionality provided by this module Description = 'Collection of useful functions and procedures for PowerShell scripting' -# Minimum version of the Windows PowerShell engine required by this module +# Minimum version of the PowerShell engine required by this module PowerShellVersion = '3.0' -# Name of the Windows PowerShell host required by this module +# Name of the PowerShell host required by this module # PowerShellHostName = '' -# Minimum version of the Windows PowerShell host required by this module +# Minimum version of the PowerShell host required by this module # PowerShellHostVersion = '' # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. # DotNetFrameworkVersion = '' # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. -# CLRVersion = '' +# ClrVersion = '' # Processor architecture (None, X86, Amd64) required by this module # ProcessorArchitecture = '' @@ -75,18 +75,19 @@ FunctionsToExport = 'Compare-Hashtable', 'Compare-Properties', 'Compare-Version' 'ConvertTo-RegularExpression', 'Copy-Object', 'Copy-OrderedHashtable', 'Expand-CompressedFile', 'Find-Key', 'Format-String', 'Get-CallerPreference', 'Get-EnvironmentVariable', 'Get-HTTPStatus', - 'Get-KeyValue', 'Get-Object', 'Get-Path', 'Get-Properties', 'Get-URI', - 'Import-CSVProperties', 'Import-Function', 'Import-Properties', - 'Invoke-OracleCmd', 'New-DynamicParameter', 'New-RandomPassword', - 'New-SelfContainedPackage', 'Out-Hashtable', - 'Protect-WindowsCmdValue', 'Remove-EnvironmentVariable', - 'Remove-Object', 'Rename-NumberedFile', 'Resolve-Array', - 'Resolve-Boolean', 'Resolve-Tags', 'Resolve-URI', 'Select-XMLNode', - 'Set-EnvironmentVariable', 'Set-RelativePath', 'Set-Tags', - 'Start-Script', 'Stop-AllTranscripts', 'Stop-Script', - 'Sync-EnvironmentVariable', 'Test-EnvironmentVariable', - 'Test-HTTPStatus', 'Test-Object', 'Test-OracleConnection', - 'Test-Service', 'Test-SQLConnection', 'Update-File', 'Wait-WebResource', + 'Get-KeyValue', 'Get-Object', 'Get-Path', 'Get-PowerShellError', + 'Get-Properties', 'Get-URI', 'Import-CSVProperties', 'Import-Function', + 'Import-Properties', 'Invoke-OracleCmd', 'New-DynamicParameter', + 'New-ProcessObject', 'New-RandomPassword', 'New-SelfContainedPackage', + 'Out-Hashtable', 'Ping-Host', 'Protect-WindowsCmdValue', + 'Remove-EnvironmentVariable', 'Remove-Object', 'Rename-NumberedFile', + 'Resolve-Array', 'Resolve-Boolean', 'Resolve-Tags', 'Resolve-URI', + 'Select-XMLNode', 'Set-EnvironmentVariable', 'Set-RelativePath', + 'Set-Tags', 'Show-EnvironmentVariables', 'Start-Script', + 'Stop-AllTranscripts', 'Stop-Script', 'Sync-EnvironmentVariable', + 'Test-EnvironmentVariable', 'Test-HTTPStatus', 'Test-Object', + 'Test-OracleConnection', 'Test-Service', 'Test-SQLConnection', + 'Update-File', 'Update-ProcessObject', 'Wait-WebResource', 'Write-Checksum', 'Write-ErrorLog', 'Write-InsertOrUpdate', 'Write-Log' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. @@ -125,7 +126,7 @@ PrivateData = @{ # IconUri = '' # ReleaseNotes of this module - ReleaseNotes = 'https://github.com/Akaizoku/PSAYX/blob/main/CHANGELOG.md' + ReleaseNotes = 'https://github.com/Akaizoku/PSTK/blob/main/CHANGELOG.md' # Prerelease string of this module # Prerelease = '' diff --git a/Private/Read-Properties.ps1 b/Private/Read-Properties.ps1 index 870c01c..89600da 100644 --- a/Private/Read-Properties.ps1 +++ b/Private/Read-Properties.ps1 @@ -1,122 +1,157 @@ -# ------------------------------------------------------------------------------ -# Properties parsing function -# ------------------------------------------------------------------------------ function Read-Properties { - <# - .SYNOPSIS - Parse properties file + <# + .SYNOPSIS + Parse properties file - .DESCRIPTION - Parse properties file to generate configuration variables + .DESCRIPTION + Parse properties file to generate configuration variables - .PARAMETER Path - The patch parameter corresponds to the path to the property file to read. + .PARAMETER Path + [String] The patch parameter corresponds to the path to the property file to read. - .PARAMETER Section - [Switch] The Section parameter indicates if properties should be grouped depending on - existing sections in the file. + .PARAMETER Section + [Switch] The Section parameter indicates if properties should be grouped depending on existing sections in the file. - .OUTPUTS - [System.Collections.Specialized.OrderedDictionary] Read-Properties returns an - ordered hash table containing the content of the property file. + .PARAMETER Metadata + [Switch] The metadata parameter indicates that the value (data) as well as the description and section (metadata) should be returned. This does not apply is the section switch is enabled. - .EXAMPLE - Read-Properties -Path ".\conf\default.ini" -Section + .OUTPUTS + [System.Collections.Specialized.OrderedDictionary] Read-Properties returns an ordered hash table containing the content of the property file. - In this example, Read-Properties will parse the default.ini file contained - in the .\conf directory and generate an ordered hashtable containing the - key-values pairs. - #> - [CmdletBinding ()] - Param ( - [Parameter ( - Position = 1, - Mandatory = $true, - HelpMessage = "Path to the property file" - )] - [ValidateNotNullOrEmpty ()] - [String] - $Path, - [Parameter ( - Position = 3, - Mandatory = $false, - HelpMessage = "Define if section headers should be used to group properties or be ignored" - )] - [Switch] - $Section - ) - Begin { - # Get global preference variables - Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState - # Instantiate variables - $Properties = New-Object -TypeName "System.Collections.Specialized.OrderedDictionary" - $Sections = New-Object -TypeName "System.Collections.Specialized.OrderedDictionary" - $Header = $null - $errors = 0 - } - Process { - # Check that the file exists - if (Test-Path -Path $Path) { - $ListOfProperties = Get-Content -Path $Path - $LineNumber = 0 - # Read the property file line by line - foreach ($Property in $ListOfProperties) { - $LineNumber += 1 - # If properties have to be grouped by section - if ($Section) { - # If end of file and section is open - if ($LineNumber -eq $ListOfProperties.Count -And $Header) { - if ($Property[0] -ne "#" -And $Property[0] -ne ";" -And $Property -ne "") { - $Property = Read-Property -Property $Property - if ($Property.Count -gt 0) { - $Sections.Add($Property.Key, $Property.Value) - } else { - Write-Log -Type "WARN" -Message "Unable to process line $LineNumber from $Path" - } - } - $Clone = Copy-OrderedHashtable -Hashtable $Sections -Deep - $Properties.Add($Header, $Clone) - } elseif ($Property[0] -eq "[") { - # If previous section exists add it to the property list - if ($Header) { - $Clone = Copy-OrderedHashtable -Hashtable $Sections -Deep - $Properties.Add($Header, $Clone) - } - # Create new property group - $Header = $Property.Substring(1, $Property.Length - 2) - $Sections.Clear() - } elseif ($Header -And $Property[0] -ne "#" -And $Property[0] -ne ";" -And $Property -ne "") { - $Property = Read-Property -Property $Property - if ($Property.Count -gt 0) { - $Sections.Add($Property.Key, $Property.Value) - } else { - Write-Log -Type "WARN" -Message "Unable to process line $LineNumber from $Path" - } - } - } else { - # Ignore comments, sections, and blank lines - if ($Property[0] -ne "#" -And $Property[0] -ne ";" -And $Property[0] -ne "[" -And $Property -ne "") { - $Property = Read-Property -Property $Property - if ($Property.Count -gt 0) { - try { - $Properties.Add($Property.Key, $Property.Value) - } catch { - Write-Log -Type "WARN" -Object "Two distinct definitions of the property $($Property.Key) have been found in the configuration file" - $Errors += 1 - } - } else { - Write-Log -Type "WARN" -Message "Unable to process line $LineNumber from $Path" - } - } - } - } - } else { - # Alert that configuration file does not exist at specified location - Write-Log -Type "ERROR" -Message "Path not found $Path" -ExitCode 1 - } - if ($Errors -gt 0) { - Write-Log -Type "ERROR" -Object "Unable to proceed. Resolve the issues in $Path" -ExitCode 1 - } - return $Properties - } + .EXAMPLE + Read-Properties -Path ".\conf\default.ini" -Section + + In this example, Read-Properties will parse the default.ini file contained in the .\conf directory and generate an ordered hashtable containing the key-values pairs. + + .NOTES + File name: Read-Properties.ps1 + Author: Florian Carrier + Creation date: 2018-11-27 + Last modified: 2024-09-13 + #> + [CmdletBinding ()] + Param ( + [Parameter ( + Position = 1, + Mandatory = $true, + HelpMessage = "Path to the property file" + )] + [ValidateNotNullOrEmpty ()] + [String] + $Path, + [Parameter ( + Position = 3, + Mandatory = $false, + HelpMessage = "Define if section headers should be used to group properties or be ignored" + )] + [Switch] + $Section, + [Parameter ( + HelpMessage = "Switch to retrieve metadata about properties" + )] + [Switch] + $Metadata + ) + Begin { + # Get global preference variables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + } + Process { + # Check that the file exists + if (Test-Path -Path $Path) { + # Load property file content + $Content = Get-Content -Path $Path + # Instantiate variables + $Properties = New-Object -TypeName "System.Collections.Specialized.OrderedDictionary" + $Sections = New-Object -TypeName "System.Collections.Specialized.OrderedDictionary" + $Errors = 0 + $LineNumber = 0 + $Header = $null + $PreviousLine = $null + # Read content line by line + foreach ($Line in $Content) { + $LineNumber += 1 + # If properties have to be grouped by section + if ($Section) { + # If end of file and section is open + if ($LineNumber -eq $Content.Count -And $Header) { + if ($Line[0] -ne "#" -And $Line[0] -ne ";" -And $Line -ne "") { + $Property = Read-Property -Property $Line + if ($Property.Count -gt 0) { + $Sections.Add($Property.Key, $Property.Value) + } else { + Write-Log -Type "WARN" -Message "Unable to process line $LineNumber from $Path" + } + } + $Clone = Copy-OrderedHashtable -Hashtable $Sections -Deep + $Properties.Add($Header, $Clone) + } elseif ($Line[0] -eq "[") { + # If previous section exists add it to the property list + if ($Header) { + $Clone = Copy-OrderedHashtable -Hashtable $Sections -Deep + $Properties.Add($Header, $Clone) + } + # Create new property group + $Header = $Line.Substring(1, $Line.Length - 2) + $Sections.Clear() + } elseif ($Header -And $Line[0] -ne "#" -And $Line[0] -ne ";" -And $Line -ne "") { + $Property = Read-Property -Property $Line + if ($Property.Count -gt 0) { + $Sections.Add($Property.Key, $Property.Value) + } else { + Write-Log -Type "WARN" -Message "Unable to process line $LineNumber from $Path" + } + } + } else { + # Parse rows + if ($null -eq $Line -or $Line -eq "") { + # Ignore empty lines + } elseif ($Line[0] -eq "[") { + # Parse sections + $Header = $Line.Substring(1, $Line.Length - 2).Trim() + } elseif ($Line[0] -eq "#" -Or $Line[0] -eq ";" ) { + # Parse comments + $PreviousLine = $Line.Substring(1, $Line.Length - 1).Trim() + } else { + # Parse properties + $Property = Read-Property -Property $Line + if ($Property.Count -gt 0) { + if ($Metadata -eq $true) { + # Create custom object including metadata + $Value = [Ordered]@{ + "Value" = $Property.Value + "Description" = $PreviousLine + "Section" = $Header + } + } else { + # Return raw value + $Value = $Property.Value + } + try { + # Assign property + $Properties.Add($Property.Key, $Value) + } catch { + Write-Log -Type "WARN" -Object "Two distinct definitions of the property $($Property.Key) have been found in the configuration file" + $Errors += 1 + } + # Reset metadata + $PreviousLine = $null + } else { + Write-Log -Type "WARN" -Message "Unable to process line $LineNumber from $Path" + } + } + } + } + } else { + # Alert that configuration file does not exist at specified location + Write-Log -Type "ERROR" -Message "Path not found $Path" -ExitCode 1 + } + if ($Errors -gt 0) { + Write-Log -Type "ERROR" -Object "Unable to proceed. Resolve the issues in $Path" -ExitCode 1 + } + } + End { + # Return list of properties + return $Properties + } } diff --git a/Private/Read-Property.ps1 b/Private/Read-Property.ps1 index 476c848..ad39b92 100644 --- a/Private/Read-Property.ps1 +++ b/Private/Read-Property.ps1 @@ -1,6 +1,3 @@ -# ------------------------------------------------------------------------------ -# Property parsing function -# ------------------------------------------------------------------------------ function Read-Property { <# .SYNOPSIS diff --git a/Public/Compare-Version.ps1 b/Public/Compare-Version.ps1 index 55206b3..f30aca4 100644 --- a/Public/Compare-Version.ps1 +++ b/Public/Compare-Version.ps1 @@ -22,8 +22,17 @@ function Compare-Version { File name: Compare-Version.ps1 Author: Florian Carrier Creation date: 2019-10-19 - Last modified: 2020-02-10 + Last modified: 2024-09-11 WARNING In case of modified formatting, Compare-Version only checks the semantic versionned part + + .LINK + https://semver.org/ + + .LINK + https://learn.microsoft.com/en-us/dotnet/api/system.version + + .LINK + https://learn.microsoft.com/en-us/dotnet/api/system.version.compareto #> [CmdletBinding ( SupportsShouldProcess = $true @@ -35,10 +44,10 @@ function Compare-Version { HelpMessage = "Version number to test" )] [ValidateNotNullOrEmpty()] - [String] + [System.String] $Version, [Parameter ( - Position = 1, + Position = 2, Mandatory = $true, HelpMessage = "Comparison operator" )] @@ -50,7 +59,7 @@ function Compare-Version { "lt", # Less than "le" # Less than or equal )] - [String] + [System.String] $Operator, [Parameter ( Position = 3, @@ -58,7 +67,7 @@ function Compare-Version { HelpMessage = "Reference version number to check against" )] [ValidateNotNullOrEmpty()] - [String] + [System.String] $Reference, [Parameter ( Position = 4, @@ -69,7 +78,7 @@ function Compare-Version { "modified", "semantic" )] - [String] + [System.String] $Format = "semantic" ) Begin { @@ -79,6 +88,7 @@ function Compare-Version { Process { switch ($Format) { "semantic" { + Write-Log -Type "DEBUG" -Message "Semantic version comparison" # Prepare version numbers for comparison try { $VersionNumber = [System.Version]::Parse($Version) @@ -92,29 +102,34 @@ function Compare-Version { Write-Log -Type "ERROR" -Object "The version number ""$Reference"" does not match $Format numbering" return $false } - # Build comparison command - $Command = """$VersionNumber"" -$Operator ""$ReferenceNumber""" - Write-Log -Type "DEBUG" -Object $Command - # Execute comparison - $Result = Invoke-Expression -Command $Command - # Return comparison result - return $Result + # Compare versions + $Compare = $VersionNumber.CompareTo($ReferenceNumber) + if (($Operator -in ("eq", "ge", "le")) -And ($Compare -eq 0)) { + return $True + } elseif (($Operator -in ("ne", "ge", "gt")) -And ($Compare -eq 1)) { + return $True + } elseif (($Operator -in ("ne", "le", "lt")) -And ($Compare -eq -1)) { + return $True + } else { + return $False + } } "modified" { + Write-Log -Type "DEBUG" -Message "String version comparison" if ($Operator -in ("eq", "ne")) { # Compare strings as-is $VersionNumber = $Version $ReferenceNumber = $Reference } else { # Parse version numbers - $SemanticVersion = Select-String -InputObject $Version -Pattern '(\d+.\d+.\d+)(?=\D*)' | ForEach-Object { $_.Matches.Value } + $SemanticVersion = Select-String -InputObject $Version -Pattern '(\d+.\d+.\d+)(?=\D*)' | ForEach-Object { $PSItem.Matches.Value } try { $VersionNumber = [System.Version]::Parse($SemanticVersion) } catch [FormatException] { Write-Log -Type "ERROR" -Object "The version number ""$Version"" does not match semantic numbering" return $false } - $SemanticReference = Select-String -InputObject $Reference -Pattern '(\d+.\d+.\d+)(?=\D*)' | ForEach-Object { $_.Matches.Value } + $SemanticReference = Select-String -InputObject $Reference -Pattern '(\d+.\d+.\d+)(?=\D*)' | ForEach-Object { $PSItem.Matches.Value } try { $ReferenceNumber = [System.Version]::Parse($SemanticReference) } catch [FormatException] { diff --git a/Public/Confirm-Prompt.ps1 b/Public/Confirm-Prompt.ps1 index 071fdfe..deb91b1 100644 --- a/Public/Confirm-Prompt.ps1 +++ b/Public/Confirm-Prompt.ps1 @@ -1,27 +1,40 @@ function Confirm-Prompt { - [CmdletBinding ()] - Param ( - [Parameter ( - Position = 1, - Mandatory = $true, - HelpMessage = "Prompt message" - )] - [String] - $Prompt - ) - Begin { - $ConfirmPrompt = $Prompt + " ([Y] Yes | [N] No)" - } - Process { - $Answer = Read-Host -Prompt $ConfirmPrompt - switch -RegEx ($Answer) { - # Switch is case insensitive - '\Ayes\Z|\Ay\Z|\A1\Z|\Atrue\Z|\At\Z' { return $true } - '\Ano\Z|\An\Z|\A0\Z|\Afalse\Z|\Af\Z' { return $false } - default { - Write-Log -Type "ERROR" -Object "Unable to process answer. Please enter either [Y] Yes or [N] No" - Confirm-Prompt -Prompt $Prompt - } - } - } + <# + .SYNOPSIS + Prompt user for confirmation + + .DESCRIPTION + Prompt user to confirm agreement to a specified statement + + .NOTES + File name: Confirm-Prompt.ps1 + Author: Florian Carrier + Creation date: 2019-06-14 + Last modified: 2024-09-13 + #> + [CmdletBinding ()] + Param ( + [Parameter ( + Position = 1, + Mandatory = $true, + HelpMessage = "Prompt message" + )] + [String] + $Prompt + ) + Begin { + $ConfirmPrompt = $Prompt + " ([Y] Yes | [N] No)" + } + Process { + $Answer = Read-Host -Prompt $ConfirmPrompt + switch -RegEx ($Answer) { + # Switch is case insensitive + '\Ayes\Z|\Ay\Z|\A1\Z|\Atrue\Z|\At\Z' { return $true } + '\Ano\Z|\An\Z|\A0\Z|\Afalse\Z|\Af\Z' { return $false } + default { + Write-Log -Type "ERROR" -Object "Unable to process answer. Please enter either [Y] Yes or [N] No" + Confirm-Prompt -Prompt $Prompt + } + } + } } diff --git a/Public/Copy-Object.ps1 b/Public/Copy-Object.ps1 index 5c9da65..1266146 100644 --- a/Public/Copy-Object.ps1 +++ b/Public/Copy-Object.ps1 @@ -19,11 +19,14 @@ function Copy-Object { .PARAMETER Exclude The exclude parameter corresponds to the filter to apply to the name of objects *not* to copy. + .PARAMETER Force + The force parameter enable the overwrite of the target object. + .NOTES File name: Copy-Object.ps1 Author: Florian Carrier Creation date: 2021-07-06 - Last modified: 2021-07-08 + Last modified: 2022-08-02 #> [CmdletBinding ( SupportsShouldProcess = $true diff --git a/Public/Get-Object.ps1 b/Public/Get-Object.ps1 index 7fc1657..7207cfc 100644 --- a/Public/Get-Object.ps1 +++ b/Public/Get-Object.ps1 @@ -32,29 +32,34 @@ function Get-Object { .EXAMPLE Get-Object -Path "\path\to\folder" + In this example, Get-Object will return the object "folder". + + .EXAMPLE + Get-Object -Path "\path\to\folder" -ChildItem + In this example, Get-Object will return all the objects (files and folders) listed in the "\path\to\folder" directory. .EXAMPLE - Get-Object -Path "\path\to\folder" -Type "File" + Get-Object -Path "\path\to\folder" -Type "File" -ChildItem In this example, Get-Object will return all the files listed in the "\path\to\folder" directory. .EXAMPLE - Get-Object -Path "\path\to\folder" -Type "Folder" + Get-Object -Path "\path\to\folder" -Type "Folder" -ChildItem In this example, Get-Object will return all the folders listed in the "\path\to\folder" directory. .EXAMPLE - Get-Object -Path "\path\to\folder" -Type "File" -Filter "*.txt" + Get-Object -Path "\path\to\folder" -Type "File" -Filter "*.txt" -ChildItem In this example, Get-Object will return all the text files listed in the "\path\to\folder" directory. .EXAMPLE - Get-Object -Path "\path\to\folder" -Type "File" -Exclude "*.txt" + Get-Object -Path "\path\to\folder" -Type "File" -Exclude "*.txt" -ChildItem In this example, Get-Object will return all the non-text files listed in the "\path\to\folder" directory. @@ -65,7 +70,7 @@ function Get-Object { File name: Get-Object.ps1 Author: Florian Carrier Creation date: 2019-06-14 - Last modified: 2021-07-06 + Last modified: 2022-04-19 #> [CmdletBinding ()] Param ( diff --git a/Public/Get-PowerShellError.ps1 b/Public/Get-PowerShellError.ps1 new file mode 100644 index 0000000..f53586e --- /dev/null +++ b/Public/Get-PowerShellError.ps1 @@ -0,0 +1,68 @@ +function Get-PowerShellError { + <# + .SYNOPSIS + Get latest error + + .DESCRIPTION + Retrieve latest PowerShell error to occur similar to Get-Help in version 7 + + .NOTES + File name: Get-PowerShellError.ps1 + Author: Florian Carrier + Creation date: 2024-09-23 + Last modified: 2024-09-23 + #> + [CmdletBinding ()] + Param () + Begin { + # Get global preference vrariables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + # Log function call + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + } + Process { + # Fetch latest error + $PSError = $PSCmdlet.GetVariableValue('Error') + $LatestErrorRecord = $PSError[0] + # Build error object + $LatestError = [PSCustomObject]@{ + Exception = if ($LatestErrorRecord.Exception) { $LatestErrorRecord.Exception.GetType().FullName } else { "N/A" } + Message = if ($LatestErrorRecord.Exception) { $LatestErrorRecord.Exception.Message } else { $LatestErrorRecord.ToString() } + Data = if ($LatestErrorRecord.Exception) { $LatestErrorRecord.Exception.Data } else { "N/A" } + InnerException = if ($LatestErrorRecord.Exception -and $LatestErrorRecord.Exception.InnerException) { $LatestErrorRecord.Exception.InnerException.Message } else { "N/A" } + TargetSite = if ($LatestErrorRecord.Exception) { $LatestErrorRecord.Exception.TargetSite } else { "N/A" } + StackTrace = if ($LatestErrorRecord.Exception) { $LatestErrorRecord.Exception.StackTrace } else { "N/A" } + HelpLink = if ($LatestErrorRecord.Exception) { $LatestErrorRecord.Exception.HelpLink } else { "N/A" } + Source = if ($LatestErrorRecord.Exception) { $LatestErrorRecord.Exception.Source } else { "N/A" } + HResult = if ($LatestErrorRecord.Exception) { $LatestErrorRecord.Exception.HResult } else { "N/A" } + CategoryInfo = $LatestErrorRecord.CategoryInfo + FullyQualifiedErrorId = $LatestErrorRecord.FullyQualifiedErrorId + ScriptStackTrace = $LatestErrorRecord.ScriptStackTrace + } + # Add invocation information + $InvocationInfo = $LatestErrorRecord.InvocationInfo + if ($InvocationInfo) { + $LatestError | Add-Member -MemberType "NoteProperty" -Name "InvocationInfo" -Value ([PSCustomObject]@{ + MyCommand = $InvocationInfo.MyCommand + BoundParameters = $InvocationInfo.BoundParameters + UnboundArguments = $InvocationInfo.UnboundArguments + ScriptLineNumber = $InvocationInfo.ScriptLineNumber + OffsetInLine = $InvocationInfo.OffsetInLine + HistoryId = $InvocationInfo.HistoryId + ScriptName = $InvocationInfo.ScriptName + Line = $InvocationInfo.Line + PositionMessage = $InvocationInfo.PositionMessage + PSScriptRoot = $InvocationInfo.PSScriptRoot + PSCommandPath = $InvocationInfo.PSCommandPath + InvocationName = $InvocationInfo.InvocationName + PipelineLength = $InvocationInfo.PipelineLength + PipelinePosition = $InvocationInfo.PipelinePosition + ExpectingInput = $InvocationInfo.ExpectingInput + CommandOrigin = $InvocationInfo.CommandOrigin + }) + } + } + End { + return $LatestError + } +} \ No newline at end of file diff --git a/Public/Get-Properties.ps1 b/Public/Get-Properties.ps1 index 174ffa0..5aecfca 100644 --- a/Public/Get-Properties.ps1 +++ b/Public/Get-Properties.ps1 @@ -1,6 +1,3 @@ -# ------------------------------------------------------------------------------ -# Properties setting function -# ------------------------------------------------------------------------------ function Get-Properties { <# .SYNOPSIS @@ -13,15 +10,19 @@ function Get-Properties { The File parameter should be the name of the property file. .PARAMETER Directory - The Directory parameter should be the path to the directory containing the - property file. + The Directory parameter should be the path to the directory containing the property file. .PARAMETER Custom The Custom parameter should be the name of the custom property file. .PARAMETER CustomDirectory - The CustomDirectory parameter should be the path to the directory containing - the custom property file. + The CustomDirectory parameter should be the path to the directory containing the custom property file. + + .PARAMETER Path + The path parameter corresponds to the path to the property file. + + .PARAMETER CustomPath + The custom path parameter corresponds to the path to the custom property file. .OUTPUTS System.Collections.Specialized.OrderedDictionary. Get-Properties returns an @@ -37,15 +38,19 @@ function Get-Properties { default ones with the custom ones. .NOTES - Get-Properties does not currently allow the use of sections to group proper- - ties in custom files + File name: Get-Properties.ps1 + Author: Florian Carrier + Creation date: 2018-11-27 + Last modified: 2024-09-13 + Comment: Get-Properties does not currently allow the use of sections to group properties in custom files #> - [CmdletBinding ()] + [CmdletBinding (DefaultParameterSetName = "File")] Param ( [Parameter ( - Position = 1, - Mandatory = $true, - HelpMessage = "Property file name" + Position = 1, + Mandatory = $true, + ParameterSetName = "File", + HelpMessage = "Property file name" )] [ValidateNotNullOrEmpty ()] [String] @@ -53,6 +58,7 @@ function Get-Properties { [Parameter ( Position = 2, Mandatory = $true, + ParameterSetName = "File", HelpMessage = "Path to the directory containing the property files" )] [ValidateNotNullOrEmpty ()] @@ -61,6 +67,7 @@ function Get-Properties { [Parameter ( Position = 3, Mandatory = $false, + ParameterSetName = "File", HelpMessage = "Custom property file name" )] [String] @@ -68,10 +75,29 @@ function Get-Properties { [Parameter ( Position = 4, Mandatory = $false, + ParameterSetName = "File", HelpMessage = "Path to the directory containing the custom property file" )] [String] $CustomDirectory = $Directory, + [Parameter ( + Position = 1, + Mandatory = $true, + ParameterSetName = "Path", + HelpMessage = "Property file path" + )] + [ValidateNotNullOrEmpty ()] + [String] + $Path, + [Parameter ( + Position = 2, + Mandatory = $false, + ParameterSetName = "Path", + HelpMessage = "Custom property file path" + )] + [ValidateNotNullOrEmpty ()] + [String] + $CustomPath, [Parameter ( Position = 5, Mandatory = $false, @@ -83,29 +109,47 @@ function Get-Properties { HelpMessage = "Define if section headers should be used to group properties or be ignored" )] [Switch] - $Section + $Section, + [Parameter ( + HelpMessage = "Switch to retrieve metadata about properties" + )] + [Switch] + $Metadata ) Begin { # Get global preference variables Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState } Process { - # Check that specified file exists - $Path = Join-Path -Path $Directory -ChildPath $File + # Build paths + if ($PSCmdlet.ParameterSetName -eq "File") { + # Check that specified file exists + $Path = Join-Path -Path $Directory -ChildPath $File + # Check if a custom file is provided + if ($Custom) { + # Make sure said file does exists + $CustomPath = Join-Path -Path $CustomDirectory -ChildPath $Custom + } + } + # Check path if (Test-Path -Path $Path) { # Parse properties with or without section split - $Properties = Read-Properties -Path $Path -Section:$Section + $Properties = Read-Properties -Path $Path -Section:$Section -Metadata:$Metadata # Check if a custom file is provided - if ($Custom) { + if ($CustomPath) { # Make sure said file does exists - $CustomPath = Join-Path -Path $CustomDirectory -ChildPath $Custom if (Test-Path -Path $CustomPath) { # Override default properties with custom ones - $Customs = Read-Properties -Path $CustomPath + $Customs = Read-Properties -Path $CustomPath -Metadata:$Metadata foreach ($Property in $Customs.Keys) { # Override default with custom if (Find-Key -Hashtable $Properties -Key $Property) { - $Properties.$Property = $Customs.$Property + if ($Metadata -eq $true) { + # Update value but retain metadata + $Properties.$Property.Value = $Customs.$Property.Value + } else { + $Properties.$Property = $Customs.$Property + } } else { Write-Log -Type "WARN" -Object "The ""$Property"" property defined in $Custom is unknown" } diff --git a/Public/New-ProcessObject.ps1 b/Public/New-ProcessObject.ps1 new file mode 100644 index 0000000..a7ee2a7 --- /dev/null +++ b/Public/New-ProcessObject.ps1 @@ -0,0 +1,47 @@ +function New-ProcessObject { + <# + .SYNOPSIS + Create new process custom object + + .DESCRIPTION + Create a new PSCustomObject to store all information about a process + + .NOTES + File name: New-ProcessObject.ps1 + Author: Florian Carrier + Creation date: 2024-09-10 + Last modified: 2024-09-12 + #> + [CmdletBinding ()] + Param ( + [Parameter ( + Position = 1, + Mandatory = $true, + HelpMessage = "Name of the process" + )] + [ValidateNotNullOrEmpty ()] + [Alias ("ProcessName")] + [System.String] + $Name + ) + Begin { + # Get global preference vrariables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + # Log function call + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + } + Process { + $Process = [PSCustomObject]@{ + Status = "Started" + Success = $false + ExitCode = 0 + ErrorCount = 0 + ProcessID = $PID + ProcessName = $Name + } + } + End { + Write-Log -Type "DEBUG" -Message ($Process | Format-Table) + return $Process + } +} \ No newline at end of file diff --git a/Public/Ping-Host.ps1 b/Public/Ping-Host.ps1 new file mode 100644 index 0000000..c67c965 --- /dev/null +++ b/Public/Ping-Host.ps1 @@ -0,0 +1,89 @@ +function Ping-Host { + <# + .SYNOPSIS + Ping host + + .DESCRIPTION + Test the connection to a specified host + + .NOTES + File name: Ping-Host.ps1 + Author: Florian Carrier + Creation date: 2022-02-15 + Last modified: 2022-02-15 + + .LINK + https://docs.microsoft.com/en-us/previous-versions/windows/desktop/wmipicmp/win32-pingstatus + #> + [CmdletBinding ()] + Param ( + [Parameter ( + Position = 1, + Mandatory = $true, + HelpMessage = "Hostname or IP address" + )] + [ValidateNotNullOrEmpty ()] + [Alias ("Address")] + [System.String] + $Hostname, + [Parameter ( + Position = 2, + Mandatory = $false, + HelpMessage = "Timeout (in seconds)" + )] + [ValidateNotNullOrEmpty ()] + [System.Int32] + $TimeOut = 1, + [Parameter ( + HelpMessage = "Return detailed status" + )] + [Switch] + $Status + ) + Begin { + # Get global preference vrariables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + # Status codes + $StatusCodes = [Ordered]@{ + [System.UInt32]0 = "Success" + [System.UInt32]11001 = "Buffer Too Small" + [System.UInt32]11002 = "Destination Net Unreachable" + [System.UInt32]11003 = "Destination Host Unreachable" + [System.UInt32]11004 = "Destination Protocol Unreachable" + [System.UInt32]11005 = "Destination Port Unreachable" + [System.UInt32]11006 = "No Resources" + [System.UInt32]11007 = "Bad Option" + [System.UInt32]11008 = "Hardware Error" + [System.UInt32]11009 = "Packet Too Big" + [System.UInt32]11010 = "Request Timed Out" + [System.UInt32]11011 = "Bad Request" + [System.UInt32]11012 = "Bad Route" + [System.UInt32]11013 = "TimeToLive Expired Transit" + [System.UInt32]11014 = "TimeToLive Expired Reassembly" + [System.UInt32]11015 = "Parameter Problem" + [System.UInt32]11016 = "Source Quench" + [System.UInt32]11017 = "Option Too Big" + [System.UInt32]11018 = "Bad Destination" + [System.UInt32]11032 = "Negotiating IPSEC" + [System.UInt32]11050 = "General Failure" + } + # Convert time-out to milliseconds + $TimeOut = $TimeOut * 1000 + } + Process { + # Ping host + $Ping = Get-CimInstance -ClassName "Win32_PingStatus" -Filter "Address='$Hostname' AND Timeout=$TimeOut" + if ($Status) { + # Return status label + if ($null -eq $Ping.StatusCode) { + $Output = "Failure" + } else { + $Output = $StatusCodes.$($Ping.StatusCode) + } + } else { + # Return boolean + $Output = ($Ping.StatusCode -eq 0) + } + return $Output + } +} \ No newline at end of file diff --git a/Public/Remove-Object.ps1 b/Public/Remove-Object.ps1 index 836ddea..a88d4c3 100644 --- a/Public/Remove-Object.ps1 +++ b/Public/Remove-Object.ps1 @@ -18,11 +18,14 @@ function Remove-Object { .PARAMETER Exclude The exclude parameter corresponds to the filter to apply to the name of objects *not* to remove. + .PARAMETER Force + The force parameter enable the deletion of read-only or hidden files. + .NOTES File name: Remove-Object.ps1 Author: Florian Carrier Creation date: 2019-06-14 - Last modified: 2021-09-10 + Last modified: 2022-08-02 #> [CmdletBinding ()] Param ( @@ -62,6 +65,11 @@ function Remove-Object { [ValidateNotNullOrEmpty ()] [System.String[]] $Exclude = $null, + [Parameter ( + HelpMessage = "Switch to force copy" + )] + [Switch] + $Force, [Parameter ( HelpMessage = "Suppress debug messages" )] @@ -92,7 +100,7 @@ function Remove-Object { Write-Log -Type "DEBUG" -Object $Object.FullName } try { - Remove-Item -Path $Object.FullName -Recurse -Force -ErrorVariable "ErrorMessage" -ErrorAction "Stop" + Remove-Item -Path $Object.FullName -Recurse -Force:$Force -ErrorVariable "ErrorMessage" -ErrorAction "Stop" } catch { Write-Log -Type "ERROR" -Message $ErrorMessage } diff --git a/Public/Show-EnvironmentVariables.ps1 b/Public/Show-EnvironmentVariables.ps1 new file mode 100644 index 0000000..c1005a7 --- /dev/null +++ b/Public/Show-EnvironmentVariables.ps1 @@ -0,0 +1,42 @@ +function Show-EnvironmentVariables { + <# + .SYNOPSIS + Show environment variables + + .DESCRIPTION + Lists all available environment variables in a specified scope + + .NOTES + File name: Show-EnvironmentVariables.ps1 + Author: Florian Carrier + Creation date: 2022-01-14 + Last modified: 2022-01-14 + #> + [CmdletBinding ()] + Param ( + [Parameter ( + Position = 1, + Mandatory = $false, + HelpMessage = "Scope" + )] + [ValidateSet( + "Machine", + "Process", + "User" + )] + [System.String] + $Scope + ) + Begin { + # Get global preference vrariables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + } + Process { + if ($PSBoundParameters.ContainsKey("Scope")) { + $EnvironmentVariables = [System.Environment]::GetEnvironmentVariables($Scope) + } else { + $EnvironmentVariables = [System.Environment]::GetEnvironmentVariables() + } + return $EnvironmentVariables + } +} \ No newline at end of file diff --git a/Public/Update-ProcessObject.ps1 b/Public/Update-ProcessObject.ps1 new file mode 100644 index 0000000..4712230 --- /dev/null +++ b/Public/Update-ProcessObject.ps1 @@ -0,0 +1,94 @@ +function Update-ProcessObject { + <# + .SYNOPSIS + Update a process object + + .DESCRIPTION + Update the properties of a specified PSCustomObject holding the information of a process + + .NOTES + File name: Update-ProcessObject.ps1 + Author: Florian Carrier + Creation date: 2024-09-10 + Last modified: 2024-09-12 + #> + [CmdletBinding ()] + Param ( + [Parameter ( + Position = 1, + Mandatory = $true, + HelpMessage = "Process object to update" + )] + [ValidateNotNullOrEmpty ()] + [Alias ("Process")] + [PSCustomObject] + $ProcessObject, + [Parameter ( + Position = 2, + Mandatory = $false, + HelpMessage = "Process status" + )] + [ValidateSet ( + "Cancelled", + "Completed", + "Failed", + "Running", + "Started", + "Stopped" + )] + [System.String] + $Status, + [Parameter ( + Position = 2, + Mandatory = $false, + HelpMessage = "Status of the process" + )] + [ValidateNotNullOrEmpty ()] + [System.Boolean] + $Success, + [Parameter ( + Position = 3, + Mandatory = $false, + HelpMessage = "Exit code of the process" + )] + [ValidateNotNullOrEmpty ()] + [System.Int32] + $ExitCode, + [Parameter ( + Position = 4, + Mandatory = $false, + HelpMessage = "Exit code of the process" + )] + [ValidateNotNullOrEmpty ()] + [System.Int32] + $ErrorCount + ) + Begin { + # Get global preference vrariables + Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState + # Log function call + Write-Log -Type "DEBUG" -Message $MyInvocation.MyCommand.Name + } + Process { + # Update status + if ($PSBoundParameters.ContainsKey("Status")) { + $ProcessObject.Status = $Status + } + # Update success flag + if ($PSBoundParameters.ContainsKey("Success")) { + $ProcessObject.Success = $Success + } + # Update exit code + if ($PSBoundParameters.ContainsKey("ExitCode")) { + $ProcessObject.ExitCode = $ExitCode + } + # Update error count + if ($PSBoundParameters.ContainsKey("ErrorCount")) { + $ProcessObject.ErrorCount += $ErrorCount + } + } + End { + Write-Log -Type "DEBUG" -Message ($ProcessObject | Format-Table) + return $ProcessObject + } +} \ No newline at end of file diff --git a/Public/Write-Log.ps1 b/Public/Write-Log.ps1 index 3d65358..c136738 100644 --- a/Public/Write-Log.ps1 +++ b/Public/Write-Log.ps1 @@ -19,6 +19,7 @@ function Write-Log { - DEBUG: debug message, used to debug scripts; - ERROR: error message, used to provide detail on an issue; - INFO: information, used to convey a message; + - NOTICE: important information, used to highlight key details; - WARN: warning, used to highlight a non-blocking issue. .PARAMETER Object @@ -80,7 +81,7 @@ function Write-Log { File name: Write-Log.ps1 Author: Florian Carrier Creation date: 2018-10-15 - Last modified: 2021-09-02 + Last modified: 2024-09-11 TODO Add locale variable .LINK @@ -98,6 +99,7 @@ function Write-Log { "DEBUG", "ERROR", "INFO", + "NOTICE", "WARN" )] [System.String] @@ -149,6 +151,7 @@ function Write-Log { "CHECK" = "Green" "ERROR" = "Red" "INFO" = "White" + "NOTICE"= "Blue" "WARN" = "Yellow" } # Message object check @@ -184,9 +187,12 @@ function Write-Log { Write-Log -Type "DEBUG" -Object $FilePath $Message | Out-File -FilePath $FilePath -Append -Force } + + } + End { # Stop script if exit code is specified if ($PSBoundParameters.ContainsKey("ExitCode")) { - Stop-Script -ExitCode $ExitCode + Stop-Script -ExitCode $ExitCode } } } diff --git a/README.md b/README.md index 4f1fb09..3fe3d49 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ PowerShell Tool Kit (PSTK) is a library containing a collection of useful PowerS There are two methods of setting up the PowerShell Tool Kit module on your system: -1. Download the PSTK module from the [GitHub repository](https://github.com/Akaizoku/PSTK); -1. Install the PSTK module from the [PowerShell Gallery](https://www.powershellgallery.com/packages/PSTK). +1. Download the PSTK module from the [GitHub repository](https://github.com/Akaizoku/PSTK) and extract it in the `PSModulePath` environment variable location; +2. Install the PSTK module from the [PowerShell Gallery](https://www.powershellgallery.com/packages/PSTK). ```powershell Install-Module -Name "PSTK" -Repository "PSGallery" @@ -30,66 +30,71 @@ Get-Command -Module "PSTK" ``` | CommandType | Name | Version | Source | -| ----------- | --------------------------- | ------: | ------ | -| Function | Compare-Hashtable | 1.2.5 | PSTK | -| Function | Compare-Properties | 1.2.5 | PSTK | -| Function | Compare-Version | 1.2.5 | PSTK | -| Function | Complete-RelativePath | 1.2.5 | PSTK | -| Function | Confirm-Prompt | 1.2.5 | PSTK | -| Function | Convert-FileEncoding | 1.2.5 | PSTK | -| Function | ConvertTo-JavaProperty | 1.2.5 | PSTK | -| Function | ConvertTo-NaturalSort | 1.2.5 | PSTK | -| Function | ConvertTo-PDF | 1.2.5 | PSTK | -| Function | ConvertTo-RegularExpression | 1.2.5 | PSTK | -| Function | Copy-Object | 1.2.5 | PSTK | -| Function | Copy-OrderedHashtable | 1.2.5 | PSTK | -| Function | Expand-CompressedFile | 1.2.5 | PSTK | -| Function | Find-Key | 1.2.5 | PSTK | -| Function | Format-String | 1.2.5 | PSTK | -| Function | Get-CallerPreference | 1.2.5 | PSTK | -| Function | Get-EnvironmentVariable | 1.2.5 | PSTK | -| Function | Get-HTTPStatus | 1.2.5 | PSTK | -| Function | Get-KeyValue | 1.2.5 | PSTK | -| Function | Get-Object | 1.2.5 | PSTK | -| Function | Get-Path | 1.2.5 | PSTK | -| Function | Get-Properties | 1.2.5 | PSTK | -| Function | Get-URI | 1.2.5 | PSTK | -| Function | Import-CSVProperties | 1.2.5 | PSTK | -| Function | Import-Function | 1.2.5 | PSTK | -| Function | Import-Properties | 1.2.5 | PSTK | -| Function | Invoke-OracleCmd | 1.2.5 | PSTK | -| Function | New-DynamicParameter | 1.2.5 | PSTK | -| Function | New-RandomPassword | 1.2.5 | PSTK | -| Function | New-SelfContainedPackage | 1.2.5 | PSTK | -| Function | Out-Hashtable | 1.2.5 | PSTK | -| Function | Protect-WindowsCmdValue | 1.2.5 | PSTK | -| Function | Remove-EnvironmentVariable | 1.2.5 | PSTK | -| Function | Remove-Object | 1.2.5 | PSTK | -| Function | Rename-NumberedFile | 1.2.5 | PSTK | -| Function | Resolve-Array | 1.2.5 | PSTK | -| Function | Resolve-Boolean | 1.2.5 | PSTK | -| Function | Resolve-Tags | 1.2.5 | PSTK | -| Function | Resolve-URI | 1.2.5 | PSTK | -| Function | Select-XMLNode | 1.2.5 | PSTK | -| Function | Set-EnvironmentVariable | 1.2.5 | PSTK | -| Function | Set-RelativePath | 1.2.5 | PSTK | -| Function | Set-Tags | 1.2.5 | PSTK | -| Function | Start-Script | 1.2.5 | PSTK | -| Function | Stop-AllTranscripts | 1.2.5 | PSTK | -| Function | Stop-Script | 1.2.5 | PSTK | -| Function | Sync-EnvironmentVariable | 1.2.5 | PSTK | -| Function | Test-EnvironmentVariable | 1.2.5 | PSTK | -| Function | Test-HTTPStatus | 1.2.5 | PSTK | -| Function | Test-Object | 1.2.5 | PSTK | -| Function | Test-OracleConnection | 1.2.5 | PSTK | -| Function | Test-Service | 1.2.5 | PSTK | -| Function | Test-SQLConnection | 1.2.5 | PSTK | -| Function | Update-File | 1.2.5 | PSTK | -| Function | Wait-WebResource | 1.2.5 | PSTK | -| Function | Write-Checksum | 1.2.5 | PSTK | -| Function | Write-ErrorLog | 1.2.5 | PSTK | -| Function | Write-InsertOrUpdate | 1.2.5 | PSTK | -| Function | Write-Log | 1.2.5 | PSTK | +| :---------- | :-------------------------- | ------: | :----- | +| Function | Compare-Hashtable | 1.2.6 | PSTK | +| Function | Compare-Properties | 1.2.6 | PSTK | +| Function | Compare-Version | 1.2.6 | PSTK | +| Function | Complete-RelativePath | 1.2.6 | PSTK | +| Function | Confirm-Prompt | 1.2.6 | PSTK | +| Function | Convert-FileEncoding | 1.2.6 | PSTK | +| Function | ConvertTo-JavaProperty | 1.2.6 | PSTK | +| Function | ConvertTo-NaturalSort | 1.2.6 | PSTK | +| Function | ConvertTo-PDF | 1.2.6 | PSTK | +| Function | ConvertTo-RegularExpression | 1.2.6 | PSTK | +| Function | Copy-Object | 1.2.6 | PSTK | +| Function | Copy-OrderedHashtable | 1.2.6 | PSTK | +| Function | Expand-CompressedFile | 1.2.6 | PSTK | +| Function | Find-Key | 1.2.6 | PSTK | +| Function | Format-String | 1.2.6 | PSTK | +| Function | Get-CallerPreference | 1.2.6 | PSTK | +| Function | Get-EnvironmentVariable | 1.2.6 | PSTK | +| Function | Get-HTTPStatus | 1.2.6 | PSTK | +| Function | Get-KeyValue | 1.2.6 | PSTK | +| Function | Get-Object | 1.2.6 | PSTK | +| Function | Get-Path | 1.2.6 | PSTK | +| Function | Get-PowerShellError | 1.2.6 | PSTK | +| Function | Get-Properties | 1.2.6 | PSTK | +| Function | Get-URI | 1.2.6 | PSTK | +| Function | Import-CSVProperties | 1.2.6 | PSTK | +| Function | Import-Function | 1.2.6 | PSTK | +| Function | Import-Properties | 1.2.6 | PSTK | +| Function | Invoke-OracleCmd | 1.2.6 | PSTK | +| Function | New-DynamicParameter | 1.2.6 | PSTK | +| Function | New-ProcessObject | 1.2.6 | PSTK | +| Function | New-RandomPassword | 1.2.6 | PSTK | +| Function | New-SelfContainedPackage | 1.2.6 | PSTK | +| Function | Out-Hashtable | 1.2.6 | PSTK | +| Function | Ping-Host | 1.2.6 | PSTK | +| Function | Protect-WindowsCmdValue | 1.2.6 | PSTK | +| Function | Remove-EnvironmentVariable | 1.2.6 | PSTK | +| Function | Remove-Object | 1.2.6 | PSTK | +| Function | Rename-NumberedFile | 1.2.6 | PSTK | +| Function | Resolve-Array | 1.2.6 | PSTK | +| Function | Resolve-Boolean | 1.2.6 | PSTK | +| Function | Resolve-Tags | 1.2.6 | PSTK | +| Function | Resolve-URI | 1.2.6 | PSTK | +| Function | Select-XMLNode | 1.2.6 | PSTK | +| Function | Set-EnvironmentVariable | 1.2.6 | PSTK | +| Function | Set-RelativePath | 1.2.6 | PSTK | +| Function | Set-Tags | 1.2.6 | PSTK | +| Function | Show-EnvironmentVariables | 1.2.6 | PSTK | +| Function | Start-Script | 1.2.6 | PSTK | +| Function | Stop-AllTranscripts | 1.2.6 | PSTK | +| Function | Stop-Script | 1.2.6 | PSTK | +| Function | Sync-EnvironmentVariable | 1.2.6 | PSTK | +| Function | Test-EnvironmentVariable | 1.2.6 | PSTK | +| Function | Test-HTTPStatus | 1.2.6 | PSTK | +| Function | Test-Object | 1.2.6 | PSTK | +| Function | Test-OracleConnection | 1.2.6 | PSTK | +| Function | Test-Service | 1.2.6 | PSTK | +| Function | Test-SQLConnection | 1.2.6 | PSTK | +| Function | Update-File | 1.2.6 | PSTK | +| Function | Update-ProcessObject | 1.2.6 | PSTK | +| Function | Wait-WebResource | 1.2.6 | PSTK | +| Function | Write-Checksum | 1.2.6 | PSTK | +| Function | Write-ErrorLog | 1.2.6 | PSTK | +| Function | Write-InsertOrUpdate | 1.2.6 | PSTK | +| Function | Write-Log | 1.2.6 | PSTK | ## Dependencies