Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3d538ac
`Get-FileVersion`: New command
johlju Dec 12, 2025
b8333de
Merge branch 'main' into fix/move-private-function
johlju Dec 12, 2025
ebcd2ea
Fix error handling in Get-FileProductVersion function to ensure consi…
johlju Dec 12, 2025
e19355f
Refactor Get-FileVersion function to streamline error handling by rem…
johlju Dec 12, 2025
049e97c
Fix context skip condition in Get-FileVersion integration tests for W…
johlju Dec 12, 2025
83b8862
Update error handling in Get-FileVersion integration test for Unix ex…
johlju Dec 12, 2025
aafef32
Update error message for missing DscResource.Test module dependency i…
johlju Dec 12, 2025
4604d9b
Refactor Get-FileVersion tests to remove unnecessary InModuleScope us…
johlju Dec 12, 2025
511f60b
Refactor Get-FileVersion tests to use a localized expected message fo…
johlju Dec 12, 2025
9047c3a
Enhance Get-FileProductVersion function to validate product version f…
johlju Dec 12, 2025
0c6410c
Improve error handling in Get-FileProductVersion by adding ErrorId, C…
johlju Dec 12, 2025
05148c4
Remove unnecessary return statement in Get-FileVersion function for c…
johlju Dec 12, 2025
2c72eca
Fix context skip conditions in Get-FileVersion integration tests for …
johlju Dec 12, 2025
beab9a0
Fix dependency error message and update Get-FileVersion tests to use …
johlju Dec 12, 2025
57cb600
Update documentation and tests to use Get-FileVersion for product ver…
johlju Dec 12, 2025
b2d6548
Enhance error handling in Get-FileProductVersion and add parameter va…
johlju Dec 12, 2025
035c933
Improve error handling in Get-FileProductVersion by throwing a termin…
johlju Dec 12, 2025
31e2bb7
Update documentation for Get-FileProductVersion to clarify input para…
johlju Dec 12, 2025
e6f3289
Refactor Get-FileProductVersion to move product version parsing after…
johlju Dec 12, 2025
7e31010
Refactor error handling to use New-ErrorRecord for consistency across…
johlju Dec 17, 2025
83cfb66
Refactor parameter set validation in Get-FileProductVersion and Get-F…
johlju Dec 17, 2025
8b4b1f0
Fix error message in BeforeDiscovery to correct build task instruction
johlju Dec 17, 2025
bd3e7df
Refactor mock FileInfo creation to use static method for improved cla…
johlju Dec 17, 2025
1d112ba
Update error ID in Assert-RequiredCommandParameter to ARCP0002 for im…
johlju Dec 17, 2025
7c1ad51
Refactor parameter set test cases in Get-FileProductVersion and Get-F…
johlju Dec 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- `Get-FileVersion`
- New public command to return the version information for a file. This command
returns the full `System.Diagnostics.FileVersionInfo` object.

### Changed

- Updated build scripts to Sampler 0.119.0-preview0005.
- `Get-FileProductVersion`
- Changed to use the new `Get-FileVersion` command internally instead of
directly accessing `Get-Item` and `VersionInfo`.

### Fixed

- New-*Exception
Expand All @@ -16,10 +29,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
TurnOffTypeChecking is used [#184](https://github.com/dsccommunity/DscResource.Common/issues/184).
- Fix typo in `Clear-ZeroedEnumPropertyValue` help text. Fixes [#181](https://github.com/dsccommunity/DscResource.Common/issues/181).

### Changed

- Updated build scripts to Sampler 0.119.0-preview0005.

## [0.24.2] - 2025-08-27

### Changed
Expand Down
14 changes: 2 additions & 12 deletions source/Private/Assert-RequiredCommandParameter.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,7 @@ function Assert-RequiredCommandParameter
}

$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
$errorMessage,
'ARCP0001', # cspell: disable-line
[System.Management.Automation.ErrorCategory]::InvalidOperation,
'Command parameters'
)
(New-ErrorRecord -Exception $errorMessage -ErrorId 'ARCP0001' -ErrorCategory ([System.Management.Automation.ErrorCategory]::InvalidOperation) -TargetObject 'Command parameters')
)
}
}
Expand All @@ -123,12 +118,7 @@ function Assert-RequiredCommandParameter
}

$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
$errorMessage,
'ARCP0002', # cspell: disable-line
[System.Management.Automation.ErrorCategory]::InvalidOperation,
'Command parameters'
)
(New-ErrorRecord -Exception $errorMessage -ErrorId 'ARCP0002' -ErrorCategory ([System.Management.Automation.ErrorCategory]::InvalidOperation) -TargetObject 'Command parameters')
)
Comment thread
johlju marked this conversation as resolved.
}

Expand Down
7 changes: 1 addition & 6 deletions source/Public/Assert-ElevatedUser.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,7 @@ function Assert-ElevatedUser
if (-not $isElevated)
{
$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
$ErrorMessage,
'UserNotElevated',
[System.Management.Automation.ErrorCategory]::InvalidOperation,
'Command parameters'
)
(New-ErrorRecord -Exception $ErrorMessage -ErrorId 'UserNotElevated' -ErrorCategory ([System.Management.Automation.ErrorCategory]::InvalidOperation) -TargetObject 'Command parameters')
)
}
}
32 changes: 28 additions & 4 deletions source/Public/Get-FileProductVersion.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
Get-FileProductVersion -Path 'C:\Temp\setup.exe'

Returns the product version of the file setup.exe as a System.Version object.

.INPUTS
None.

.OUTPUTS
`System.Version`

Returns the product version as a System.Version object.
Comment thread
johlju marked this conversation as resolved.
#>
function Get-FileProductVersion
{
Expand All @@ -27,14 +35,30 @@ function Get-FileProductVersion

try
{
$fileItem = Get-Item -Path $Path -ErrorAction 'Stop'

return [System.Version] $fileItem.VersionInfo.ProductVersion
$fileVersionInfo = Get-FileVersion -Path $Path -ErrorAction 'Stop'
}
catch
{
$errorMessage = $script:localizedData.Get_FileProductVersion_GetFileProductVersionError -f $Path, $_.Exception.Message
$exception = New-Exception -Message $errorMessage -ErrorRecord $_

$PSCmdlet.ThrowTerminatingError(
(New-ErrorRecord -Exception $exception -ErrorId 'GFPV0001' -ErrorCategory ([System.Management.Automation.ErrorCategory]::ReadError) -TargetObject $Path) # cSpell: disable-line
)
}

$productVersionString = $fileVersionInfo.ProductVersion

Write-Error -Message $errorMessage
$parsedVersion = $null
if (-not [System.Version]::TryParse($productVersionString, [ref] $parsedVersion))
{
$errorMessage = $script:localizedData.Get_FileProductVersion_InvalidVersionFormat -f $productVersionString, $Path
$exception = New-Exception -Message $errorMessage

$PSCmdlet.ThrowTerminatingError(
(New-ErrorRecord -Exception $exception -ErrorId 'GFPV0002' -ErrorCategory ([System.Management.Automation.ErrorCategory]::InvalidData) -TargetObject $Path) # cSpell: disable-line
)
}
Comment thread
johlju marked this conversation as resolved.
Comment thread
johlju marked this conversation as resolved.

return $parsedVersion
}
67 changes: 67 additions & 0 deletions source/Public/Get-FileVersion.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<#
.SYNOPSIS
Returns the version information for a file.

.DESCRIPTION
Returns the version information for a file including the product version,
file version, and other version-related metadata.

.PARAMETER Path
Specifies the file for which to return the version information.

.EXAMPLE
Get-FileVersion -Path 'E:\setup.exe'

Returns the version information for the file setup.exe.

.EXAMPLE
Get-Item -Path 'E:\setup.exe' | Get-FileVersion

Returns the version information for the file setup.exe using pipeline input.

.EXAMPLE
'E:\setup.exe' | Get-FileVersion

Returns the version information for the file setup.exe using pipeline input.

.INPUTS
System.IO.FileInfo

Accepts a file path via the pipeline.

.INPUTS
System.String

Accepts a string path via the pipeline.

.OUTPUTS
System.Diagnostics.FileVersionInfo

Returns the file version information.
#>
function Get-FileVersion
{
[OutputType([System.Diagnostics.FileVersionInfo])]
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[Alias('FullName')]
[System.IO.FileInfo]
$Path
)

process
{
$file = Get-Item -Path $Path -ErrorAction 'Stop'

if ($file.PSIsContainer)
{
$PSCmdlet.ThrowTerminatingError(
(New-ErrorRecord -Exception ($script:localizedData.Get_FileVersion_PathIsNotFile -f $file.FullName) -ErrorId 'GFV0001' -ErrorCategory ([System.Management.Automation.ErrorCategory]::InvalidArgument) -TargetObject $file.FullName) # cSpell: disable-line
)
}

$file.VersionInfo
}
Comment thread
johlju marked this conversation as resolved.
}
7 changes: 1 addition & 6 deletions source/Public/Get-PSModulePath.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,7 @@ function Get-PSModulePath
if ([System.String]::IsNullOrEmpty($documentsFolder))
{
$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
($script:localizedData.PSModulePath_MissingMyDocumentsPath -f (Get-UserName)),
'MissingMyDocumentsPath',
[System.Management.Automation.ErrorCategory]::ResourceUnavailable,
(Get-UserName)
)
(New-ErrorRecord -Exception ($script:localizedData.PSModulePath_MissingMyDocumentsPath -f (Get-UserName)) -ErrorId 'MissingMyDocumentsPath' -ErrorCategory ([System.Management.Automation.ErrorCategory]::ResourceUnavailable) -TargetObject (Get-UserName))
)
}

Expand Down
2 changes: 1 addition & 1 deletion source/Public/New-ErrorRecord.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
[System.Management.Automation.ErrorCategory]::InvalidOperation,
$null
)
$newException = [System.Exception]::new('New error')
$newException = New-Exception -Message 'New error'
$newErrorRecord = New-ErrorRecord -ErrorRecord $existingErrorRecord -Exception $newException
$newErrorRecord.Exception.Message

Expand Down
6 changes: 5 additions & 1 deletion source/en-US/DscResource.Common.strings.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ ConvertFrom-StringData @'
SearchingForCertificateUsingFilters = Looking for certificate in Store '{0}' using filter '{1}'. (DRC0047)

## Get-FileProductVersion
Get_FileProductVersion_GetFileProductVersionError = Failed to get product version for file '{0}'. Error: {1}
Get_FileProductVersion_GetFileProductVersionError = Failed to get product version for file '{0}'. Error: {1} (GFPV0001)
Get_FileProductVersion_InvalidVersionFormat = The product version '{0}' for file '{1}' is not a valid version string. (GFPV0002)

## Get-FileVersion
Get_FileVersion_PathIsNotFile = The specified path is not a file. (GFV0001)

## Get-PSModulePath
PSModulePath_MissingMyDocumentsPath = The My Documents folder does not exist for user '{0}'. (DRC0048)
Expand Down
112 changes: 112 additions & 0 deletions tests/Integration/Commands/Get-FileVersion.Integration.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')]
param ()

BeforeDiscovery {
try
{
if (-not (Get-Module -Name 'DscResource.Test'))
{
# Assumes dependencies have been resolved, so if this module is not available, run 'noop' task.
if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable))
{
# Redirect all streams to $null, except the error stream (stream 2)
& "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null
}

# If the dependencies have not been resolved, this will throw an error.
Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop'
}
}
catch [System.IO.FileNotFoundException]
{
throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks noop" first to set up the test environment.'
}
Comment thread
johlju marked this conversation as resolved.
}

BeforeAll {
$script:moduleName = 'DscResource.Common'

Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop'
}

Describe 'Get-FileVersion' -Tag 'Integration' {
Context 'When running on Windows' -Skip:(-not $IsWindows) {
Context 'When getting version information from notepad.exe' {
BeforeAll {
$script:notepadPath = Join-Path -Path $env:SystemRoot -ChildPath 'System32\notepad.exe'
}

It 'Should return version information for notepad.exe' {
$result = Get-FileVersion -Path $script:notepadPath -ErrorAction Stop

$result | Should -Not -BeNullOrEmpty
$result | Should -BeOfType [System.Diagnostics.FileVersionInfo]
$result.ProductVersion | Should -Not -BeNullOrEmpty
$result.FileVersion | Should -Not -BeNullOrEmpty
}

It 'Should return version information using pipeline input' {
$result = $script:notepadPath | Get-FileVersion -ErrorAction Stop

$result | Should -Not -BeNullOrEmpty
$result | Should -BeOfType [System.Diagnostics.FileVersionInfo]
$result.ProductVersion | Should -Not -BeNullOrEmpty
}

It 'Should return version information using Get-Item pipeline input' {
$result = Get-Item -Path $script:notepadPath | Get-FileVersion -ErrorAction Stop

$result | Should -Not -BeNullOrEmpty
$result | Should -BeOfType [System.Diagnostics.FileVersionInfo]
$result.ProductVersion | Should -Not -BeNullOrEmpty
}
}

Context 'When getting version information from powershell.exe' {
BeforeAll {
$script:powershellPath = Join-Path -Path $env:SystemRoot -ChildPath 'System32\WindowsPowerShell\v1.0\powershell.exe'
}

It 'Should return version information for powershell.exe' {
$result = Get-FileVersion -Path $script:powershellPath -ErrorAction Stop

$result | Should -Not -BeNullOrEmpty
$result | Should -BeOfType [System.Diagnostics.FileVersionInfo]
$result.ProductVersion | Should -Not -BeNullOrEmpty
$result.FileVersion | Should -Not -BeNullOrEmpty
$result.ProductName | Should -Not -BeNullOrEmpty
}
}

Context 'When passing an invalid path' {
It 'Should throw an error for non-existent file' {
{ Get-FileVersion -Path 'C:\NonExistent\File.exe' -ErrorAction Stop } |
Should -Throw
}
}

Context 'When passing a directory path' {
It 'Should throw the correct error' {
{ Get-FileVersion -Path $env:SystemRoot -ErrorAction Stop } |
Should -Throw
}
}
}

Context 'When running on non-Windows platforms' -Skip:($IsWindows -or $PSVersionTable.PSVersion.Major -lt 6) {
Context 'When getting version information from a shell executable' -Skip:(-not (Test-Path -Path '/bin/bash')) {
BeforeAll {
$script:bashPath = '/bin/bash'
}

It 'Should handle Unix executables appropriately' {
# Unix executables typically don't have version info like Windows executables
# This test verifies the command can be called without error
$result = Get-FileVersion -Path $script:bashPath -ErrorAction 'Stop'

# Result may be null or empty on Unix systems
$result | Should -BeOfType [System.Diagnostics.FileVersionInfo]
}
}
}
}
Loading