Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 9 additions & 7 deletions build/commands/Set-TestMetadata.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,17 @@ function Set-TestMetadata {
[string]
$Category,

[ValidateSet('Low', 'Medium', 'High')]
[string]
$ImplementationCost,
[ValidateSet('Low', 'Medium', 'High')]
[string]
$ImplementationCost,

[string[]]
$MinimumLicense,

[string[]]
$MinimumLicense,
[string]
$Pillar,

[string]
$Pillar, [ValidateSet('Low', 'Medium', 'High')]
[ValidateSet('Low', 'Medium', 'High')]
[string]
$RiskLevel,

Expand Down
21 changes: 11 additions & 10 deletions build/common-functions.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function Remove-BuildDirectories {

$binPath = Get-OutputDirectory
if ( Test-Path $binPath ) {
$binPath | Remove-Item -Recurse -Force
$binPath | Remove-Item -Recurse -Force
}

$devRepoLocation = Get-DevRepoDirectory
Expand All @@ -78,7 +78,7 @@ function Register-LocalGallery {
$repoPath = Get-DevRepoDirectory
if ($Path) {
$repoPath = $Path
}
}
if (-not(Test-Path $repoPath)) {
$null = New-Item -Path $repoPath -ItemType Directory
}
Expand All @@ -87,7 +87,7 @@ function Register-LocalGallery {
$null = Register-PSResourceRepository -Name (Get-LocalPSRepoName) -Uri ($repoPath)
}

function Unregister-LocalGallery {
function Unregister-LocalGallery {
$null = Unregister-PSRepository (Get-LocalPSRepoName)
$null = Unregister-PSResourceRepository (Get-LocalPSRepoName)
}
Expand All @@ -101,12 +101,12 @@ function Update-ModuleVersion {
)

$version = Get-ModuleVersion
$v = @{
$v = @{
Major = $version.Major
Minor = $version.Minor
Build = $version.Build
Build = $version.Build
}

if ($Build.IsPresent) {
$v.Build++
}
Expand All @@ -120,7 +120,8 @@ function Update-ModuleVersion {
}

$ver = $v.Major, $v.Minor, $v.Build -Join "."
Update-ModuleManifest -Path (Get-ModuleManifestFile).FullName -ModuleVersion $ver
# Update-ModuleManifest -Path (Get-ModuleManifestFile).FullName -ModuleVersion $ver
Update-Metadata -Path (Get-ModuleManifestFile).FullName -PropertyName ModuleVersion -Value $ver
}

function Create-ModuleFolder {
Expand Down Expand Up @@ -222,16 +223,16 @@ function Get-CustomizationFiles {
$path = Join-Path $path (Get-ConfigValue -Name CustomizationPath)
}
else {
$path = Join-Path $path 'module_legacy'
$path = Join-Path $path 'module_legacy'
$path = Join-Path $path $Module
$path = Join-Path $path $Directory
}
$customizationFileList = @()
$files = Get-ChildItem -Path $path -Filter '*.ps1'
foreach ($file in $files) {
$customizationFileList += $file.FullName
$customizationFileList += $file.FullName
}

$customizationFileList
}

Expand Down
1 change: 1 addition & 0 deletions build/powershell/Install-Prerequisites.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ $modules = @(
"Pester" # Test Framework, runs the tests
"PSScriptAnalyzer" # PowerShell Best Practices analyzer, will be used in tests
'Refactor' # Used to update the metadata for individual test commands
"Metadata" # Used to update psd1 files instead of the broken Update-ModuleManifest command
)

# Automatically add missing dependencies
Expand Down
94 changes: 57 additions & 37 deletions build/powershell/Resolve-PSDependencies.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -54,30 +54,24 @@ if (-not $SkipModuleInstallation.IsPresent)
$moduleManifest = Import-PowerShellDataFile -Path $ModuleManifestPath -ErrorAction Stop
[Microsoft.PowerShell.Commands.ModuleSpecification[]]$requiredModules = $moduleManifest.RequiredModules
[Microsoft.PowerShell.Commands.ModuleSpecification[]]$externalModuleDependencies = $moduleManifest.PrivateData.ExternalModuleDependencies
# [Microsoft.PowerShell.Commands.ModuleSpecification[]]$windowsPowerShellRequiredModules = $moduleManifest.PrivateData.WindowsPowerShellRequiredModules

$requiredModuleToSave = $requiredModules.Where{$_.Name -notin $externalModuleDependencies.Name}
# $requiredModuleToSave += $windowsPowerShellRequiredModules.Where{ $_.Name -notin $requiredModules.Name -and $_.Name -notin $externalModuleDependencies.Name }

if (-not $SkipModuleInstallation.IsPresent)
{
Write-Host -Object "`r`n"
Write-Host -Object 'Resolving dependencies...' -ForegroundColor Green

$saveModuleCmdParams = @{
Path = $OutputPath
}

Write-Host -Object "`r`n"
Write-Host -Object ('Resolving {0} dependencies...' -f $requiredModuleToSave.Count) -ForegroundColor Green

if ($saveModuleCmd = (Get-Command -Name Save-PSResource -ErrorAction Ignore))
{
$saveModuleCmdParams.Add('TrustRepository', $true)
$saveModuleCmdParams.Add('Prerelease', $AllowPrerelease.IsPresent)
Write-Verbose -Message "Saving required modules using Save-PSResource..."
}
elseif ($saveModuleCmd = (Get-Command -Name Save-Module -ErrorAction Ignore))
{
$saveModuleCmdParams.Add('Force', $true)
$saveModuleCmdParams.Add('AllowPrerelease', $AllowPrerelease.IsPresent)
Write-Verbose -Message "Saving required modules using Save-Module..."
}
else
Expand All @@ -89,25 +83,7 @@ if (-not $SkipModuleInstallation.IsPresent)
foreach ($moduleSpec in $requiredModuleToSave)
{
Write-Verbose -Message ("Saving module {0} with version {1}..." -f $moduleSpec.Name, $moduleSpec.Version)
$saveModuleCmdParamsClone = $saveModuleCmdParams.Clone()
$isModulePresent = Get-Module -Name $moduleSpec.Name -ListAvailable -ErrorAction Ignore | Where-Object {
$isValid = $true
if ($moduleSpec.Guid)
{
$isValid = $_.Guid -eq $moduleSpec.Guid
}

if ($moduleSpec.Version)
{
$isValid = $isValid -and $_.Version -ge [Version]$moduleSpec.Version
}
elseif ($moduleSpec.RequiredVersion)
{
$isValid = $isValid -and $_.Version -eq [Version]$moduleSpec.RequiredVersion
}

$isValid
}
$isModulePresent = Get-Module -FullyQualifiedName $moduleSpec -ListAvailable -ErrorAction Ignore

if ($isModulePresent)
{
Expand All @@ -117,26 +93,70 @@ if (-not $SkipModuleInstallation.IsPresent)

try
{
$saveModuleCmdParamsClone['Name'] = $moduleSpec.Name
if ($moduleSpec.Version -and $saveModuleCmd.Name -eq 'Save-Module')
if ($saveModuleCmd.Name -eq 'Save-PSResource')
{
$saveModuleCmdParamsClone['MinimumVersion'] = $moduleSpec.Version
# To Save-PSResource we need to first Find-PSResource to get the latest available in given range.
$findModuleParams = @{
Name = $moduleSpec.Name
ErrorAction = 'Stop'
'Prerelease' = $AllowPrerelease.IsPresent
}

# Find-PSResource uses NuGet version range syntax: https://learn.microsoft.com/en-us/nuget/concepts/package-versioning?tabs=semver20sort#version-ranges
if ($moduleSpec.RequiredVersion) {
# Absolute required version
$findModuleParams['Version'] = '[{0}]' -f $moduleSpec.RequiredVersion
}
elseif ($moduleSpec.MaximumVersion -and $moduleSpec.Version) {
# Minimum and maximum version (exact range) inclusive
$findModuleParams['Version'] = '[{0},{1}]' -f $moduleSpec.Version, $moduleSpec.MaximumVersion
}
elseif ($moduleSpec.MaximumVersion) {
# Maximum version inclusive
$findModuleParams['Version'] = '(,{0}]' -f $moduleSpec.MaximumVersion
}
elseif ($moduleSpec.Version) {
# Minimum version inclusive
$findModuleParams['Version'] = '[{0}, )' -f $moduleSpec.Version
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's inconsistent indentation here - this line has an extra space at the beginning compared to the other similar lines (106-116). Should align with the other conditional branches for consistency.

Suggested change
$findModuleParams['Version'] = '[{0}, )' -f $moduleSpec.Version
$findModuleParams['Version'] = '[{0}, )' -f $moduleSpec.Version

Copilot uses AI. Check for mistakes.
}

# Get the latest version of the module in the range specified in Module Specification.
$latestModuleInRange = Find-PSResource @findModuleParams -ErrorAction Stop | Sort-Object -Property Version -Descending | Select-Object -First 1

$savePSResourceParams = @{
Path = $OutputPath
PassThru = $true
ErrorAction = 'Stop'
TrustRepository = $true
}

$savedModule = ($latestModuleInRange | Save-PSResource @savePSResourceParams).Where({ $_.Name -eq $moduleSpec.Name },1)
Write-Host -Object (' ⬇️ Module {0} v{1} saved successfully.' -f $moduleSpec.Name, $savedModule.Version) -ForegroundColor Green
}
elseif ($moduleSpec.Version -and $saveModuleCmd.Name -eq 'Save-PSResource')
elseif ($saveModuleCmd.Name -eq 'Save-Module')
{
$saveModuleCmdParamsClone['Version'] = '[{0}, ]' -f $moduleSpec.Version
$saveModuleCmdParams = @{
ErrorAction = 'Stop'
Force = $true
Path = $OutputPath
}
if ($AllowPrerelease.IsPresent)
{
$saveModuleCmdParams['AllowPrerelease'] = $true
}

$moduleSpec | &$saveModuleCmd @saveModuleCmdParams
Write-Host -Object (' ⬇️ Module {0} saved successfully.' -f $moduleSpec.Name) -ForegroundColor Green
}

& $saveModuleCmd @saveModuleCmdParamsClone
Write-Host -Object (' ⬇️ Module {0} saved successfully.' -f $moduleSpec.Name) -ForegroundColor Green
}
catch
{
Write-Host -Object (' ❌ Failed to save module {0}: {1}' -f $moduleSpec.Name, $_) -ForegroundColor Red
}
}
}

Write-Host -Object "`r`n"
}
}
else
{
Expand Down
21 changes: 6 additions & 15 deletions build/powershell/Set-Version.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,12 @@ if ( -not (Test-Path $ManifestPath )) {

$previewLabel = if ($preview) { '-preview' } else { '' }

# Save original manifest content before Update-ModuleManifest corrupts
# custom PrivateData keys containing hashtable arrays (it serializes them as type name strings).
$originalManifestContent = Get-Content $ManifestPath -Raw

Update-ModuleManifest -Path $ManifestPath -ModuleVersion $NewVersion -FunctionsToExport $FunctionNames -Prerelease $previewLabel

# Restore WindowsPowerShellRequiredModules that Update-ModuleManifest corrupted
if ($originalManifestContent -match '(?s)(WindowsPowerShellRequiredModules\s*=\s*@\([^)]*\))') {
$originalBlock = $Matches[1]
$updatedContent = Get-Content $ManifestPath -Raw
if ($updatedContent -match '(?s)(WindowsPowerShellRequiredModules\s*=\s*@\([^)]*\))') {
$updatedContent = $updatedContent.Replace($Matches[1], $originalBlock)
Set-Content $ManifestPath -Value $updatedContent -NoNewline
}
}
Write-Debug -Message ('Updating FunctionsToExport...')
Update-Metadata -Path $ManifestPath -PropertyName FunctionsToExport -Value $FunctionNames
Write-Debug -Message ('Updating ModuleVersion...')
Update-Metadata -Path $ManifestPath -PropertyName ModuleVersion -Value $NewVersion
Write-Debug -Message ('Updating Prerelease...')
Update-Metadata -Path $ManifestPath -PropertyName Prerelease -Value $previewLabel
}

$NewVersion += $previewLabel
Expand Down
39 changes: 18 additions & 21 deletions build/powershell/Update-PSModuleManifest.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,17 @@ if (!$SkipRequiredAssembliesDetection -and $ModuleRequiredAssembliesFileInfo) {
}

## Clear Existing RequiredAssemblies, NestedModules, and FileList
if ($paramUpdateModuleManifest.ContainsKey('RequiredAssemblies')) {
if (!$paramUpdateModuleManifest['RequiredAssemblies']) { $paramUpdateModuleManifest.Remove('RequiredAssemblies') }
(Get-Content $ModuleManifestFileInfo.FullName -Raw) -replace "(?s)(#\s*)?RequiredAssemblies\s*=\s*@\([^)]*\)", "# RequiredAssemblies = @()" | Set-Content $ModuleManifestFileInfo.FullName
}
if ($paramUpdateModuleManifest.ContainsKey('NestedModules') -and !$paramUpdateModuleManifest['NestedModules']) {
$paramUpdateModuleManifest.Remove('NestedModules')
(Get-Content $ModuleManifestFileInfo.FullName -Raw) -replace "(?s)(#\s*)?NestedModules\s*=\s*@\([^)]*\)", "# NestedModules = @()" | Set-Content $ModuleManifestFileInfo.FullName
}
if ($paramUpdateModuleManifest.ContainsKey('FileList')) {
(Get-Content $ModuleManifestFileInfo.FullName -Raw) -replace "(?s)(#\s*)?FileList\s*=\s*@\([^)]*\)", "# FileList = @()" | Set-Content $ModuleManifestFileInfo.FullName
}
# if ($paramUpdateModuleManifest.ContainsKey('RequiredAssemblies')) {
# if (!$paramUpdateModuleManifest['RequiredAssemblies']) { $paramUpdateModuleManifest.Remove('RequiredAssemblies') }
# (Get-Content $ModuleManifestFileInfo.FullName -Raw) -replace "(?s)(#\s*)?RequiredAssemblies\s*=\s*@\([^)]*\)", "# RequiredAssemblies = @()" | Set-Content $ModuleManifestFileInfo.FullName
# }
# if ($paramUpdateModuleManifest.ContainsKey('NestedModules') -and !$paramUpdateModuleManifest['NestedModules']) {
# $paramUpdateModuleManifest.Remove('NestedModules')
# (Get-Content $ModuleManifestFileInfo.FullName -Raw) -replace "(?s)(#\s*)?NestedModules\s*=\s*@\([^)]*\)", "# NestedModules = @()" | Set-Content $ModuleManifestFileInfo.FullName
# }
# if ($paramUpdateModuleManifest.ContainsKey('FileList')) {
# (Get-Content $ModuleManifestFileInfo.FullName -Raw) -replace "(?s)(#\s*)?FileList\s*=\s*@\([^)]*\)", "# FileList = @()" | Set-Content $ModuleManifestFileInfo.FullName
# }
Comment on lines +57 to +67
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider removing the commented-out code instead of leaving it in the file. Dead code can cause confusion and reduce maintainability. If the old implementation needs to be referenced, it's available in version control history.

Copilot uses AI. Check for mistakes.

## Install Module Dependencies
foreach ($Module in $ModuleManifest['RequiredModules']) {
Expand All @@ -77,17 +77,14 @@ foreach ($Module in $ModuleManifest['RequiredModules']) {

## Save original manifest content before Update-ModuleManifest corrupts
## custom PrivateData keys containing hashtable arrays (it serializes them as type name strings).
$originalManifestContent = Get-Content $ModuleManifestFileInfo.FullName -Raw

## Update Module Manifest in Module Output Directory
Update-ModuleManifest -Path $ModuleManifestFileInfo.FullName -ErrorAction Stop @paramUpdateModuleManifest

## Restore WindowsPowerShellRequiredModules that Update-ModuleManifest corrupted
if ($originalManifestContent -match '(?s)(WindowsPowerShellRequiredModules\s*=\s*@\([^)]*\))') {
$originalBlock = $Matches[1]
$updatedContent = Get-Content $ModuleManifestFileInfo.FullName -Raw
if ($updatedContent -match '(?s)(WindowsPowerShellRequiredModules\s*=\s*@\([^)]*\))') {
$updatedContent = $updatedContent.Replace($Matches[1], $originalBlock)
Set-Content $ModuleManifestFileInfo.FullName -Value $updatedContent -NoNewline
# Update-ModuleManifest -Path $ModuleManifestFileInfo.FullName -ErrorAction Stop @paramUpdateModuleManifest
foreach ($key in $paramUpdateModuleManifest.Keys) {
if ($paramUpdateModuleManifest[$key]) { # Only update manifest properties that have values
Update-Metadata -Path $ModuleManifestFileInfo.FullName -PropertyName $key -Value $paramUpdateModuleManifest[$key]
}
else {
Write-Debug -Message ('Metadata is empty for {0}, skipping update for this property.' -f $key)
}
}
Loading