Skip to content
Merged
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
2 changes: 1 addition & 1 deletion PSFramework.NuGet/PSFramework.NuGet.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
RootModule = 'PSFramework.NuGet.psm1'

# Version number of this module.
ModuleVersion = '0.9.2'
ModuleVersion = '0.9.11'

# ID used to uniquely identify this module
GUID = 'ad0f2a25-552f-4dd6-bd8e-5ddced2a5d88'
Expand Down
12 changes: 12 additions & 0 deletions PSFramework.NuGet/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## 0.9.11 (2025-05-05)

+ New: Bootstrap script to deploy PSFramework.NuGet to the local computer without requiring Package Management.
+ New: Module automatically deploys the NuGet provider to the user profile on module import, to simplify the PowerShellGet experience
+ Upd: Updated to include PSResourceGet 1.1.0
+ Upd: Get-PSFPowerShellGet - improved result display style
+ Fix: Install-PSFModule - fails to detect already existing version of module and attempts to overwrite
+ Fix: Install-PSFModule - returns unexpected object when successfully installing, but not from the first priority repository
+ Fix: Install-PSFModule - progress bar does not show number of deployments in progress.
+ Fix: Save-PSFModule - fails to detect already existing version of module and attempts to overwrite
+ Fix: Scope: AllUsers - fails to install to AllUsers when no module has been installed there yet.

## 0.9.2 (2025-01-17)

+ Fix: Get-PSFRepository - writes error when searching for a specific repository that only exists in one PSGet version
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
}

[PSCustomObject]@{
PSTypeName = 'PSFramework.NuGet.GetReport'
PSTypeName = 'PSFramework.NuGet.GetReport'
ComputerName = $env:COMPUTERNAME
V2 = ($modules | Where-Object { $_.Version.Major -lt 3 }) -as [bool]
V3 = $modulesV3 -as [bool]
Expand Down
3 changes: 2 additions & 1 deletion PSFramework.NuGet/internal/configurations/configuration.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ Set-PSFConfig -Module 'PSFramework.NuGet' -Name 'Import.IndividualFiles' -Value

Set-PSFConfig -Module 'PSFramework.NuGet' -Name 'Install.AuthenticodeSignature.Check' -Value $false -Initialize -Validation 'bool' -Description 'Whether on installation or download of module its code-signing will be checked first.'
Set-PSFConfig -Module 'PSFramework.NuGet' -Name 'Remoting.DefaultConfiguration' -Value 'Microsoft.PowerShell' -Initialize -Validation string -Description 'The PSSessionConfiguration to use when initializing new PS remoting sessions'
Set-PSFConfig -Module 'PSFramework.NuGet' -Name 'Remoting.Throttling' -Value 5 -Initialize -Validation integerpositive -Description 'Up to how many remote computers to deploy to in parallel.'
Set-PSFConfig -Module 'PSFramework.NuGet' -Name 'Remoting.Throttling' -Value 5 -Initialize -Validation integerpositive -Description 'Up to how many remote computers to deploy to in parallel.'
Set-PSFConfig -Module 'PSFramework.NuGet' -Name 'LocalBootstrap' -Value $true -Initialize -Validation bool -Description 'Whether PSGetV2 gets automatically bootstrapped on module import. This happens by default to improve user experience with an unmodified PowerShell that have never had to deal with PSGet. Also to simplify the experience in an offline environment.'
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,11 @@
$publishCommon.Module = $module.Name
$publishCommon.Version = $version.Name

$testPath = Join-Path -Path $destination.Path -ChildPath "$($module.Name)/$($version.Name)/$($module.DirectoryName).psd1"
$testPath = Join-Path -Path $destination.Path -ChildPath "$($module.Name)/$($version.Name)/$($module.Name).psd1"
$alreadyExists = Test-Path -Path $testPath
if ($alreadyExists -and -not $Force) {
Write-PSFMessage @msgParam -String 'Publish-StagingModule.Skipping.AlreadyExists' -StringValues $module.Name, $version.Name, $destination.Path
New-PublishResult @publishCommon -Success $true -Message 'Module already deployed'
continue
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@

$PSDefaultParameterValues['Write-PSFMessage:ModuleName'] = 'PSFramework.NuGet'
$PSDefaultParameterValues['Write-PSFMessage:FunctionName'] = 'Publish-StagingModule'
$__PSF_Workflow.Data.InProgress[$TargetPath.ComputerName] = $true

#region Functions
function Get-GlobalFailResult {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
if ($Repository.Credential) { $callSpecifics.Credential = $Repository.Credential }

$result = [PSCustomObject]@{
PSTypeName = 'PSFramework.NuGet.DownloadResult'
Success = $false
Error = $null
ModuleName = $Item.Name
Expand Down Expand Up @@ -203,8 +204,8 @@
Write-PSFMessage -String 'Save-StagingModule.SavingV3.Start' -StringValues $Item.Name, $Item.Version, $Repository.Name, $Repository.Type -Target $Item

$callSpecifics = @{
ErrorAction = 'Stop'
Repository = $Repository.Name
ErrorAction = 'Stop'
Repository = $Repository.Name
}
if ((Get-Command Save-PSResource).Parameters.Keys -contains 'AcceptLicense') {
$callSpecifics.AcceptLicense = $true
Expand All @@ -214,6 +215,7 @@
if ($SkipDependency) { $callSpecifics.SkipDependencyCheck = $true }

$result = [PSCustomObject]@{
PSTypeName = 'PSFramework.NuGet.DownloadResult'
Success = $false
Error = $null
ModuleName = $Item.Name
Expand Down Expand Up @@ -282,7 +284,7 @@
}
}
process {
:item foreach ($installItem in $InstallData) {
$null = :item foreach ($installItem in $InstallData) {
$saveResults = foreach ($repository in $Repositories | Set-PSFObjectOrder -Property Priority, '>Type') {
$saveResult = switch ($repository.Type) {
V2 { Save-StagingModuleV2 -Repository $repository -Item $installItem @common }
Expand Down
6 changes: 5 additions & 1 deletion PSFramework.NuGet/internal/moduleScopes/AllUsers.scope.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
return "$([Environment]::GetFolderPath("ProgramFiles"))\WindowsPowerShell\Modules"
}
if ($IsWindows) {
return "$([Environment]::GetFolderPath("ProgramFiles"))\PowerShell\Modules"
$path = "$([Environment]::GetFolderPath("ProgramFiles"))\PowerShell\Modules"
if (-not (Test-Path -Path $path)) {
$null = New-Item -Path $path -ItemType Directory -Force -ErrorAction Ignore
}
return $path
}
'/usr/local/share/powershell/Modules'
}
Expand Down
13 changes: 12 additions & 1 deletion PSFramework.NuGet/internal/scripts/initialize.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,15 @@
Search-PSFPowerShellGet

# Ensure all configured repositories exist, and all unintended repositories are gone
Update-PSFRepository
Update-PSFRepository

# Auto-Bootstrap Local GetV2 on Windows
if (
($PSVersionTable.PSVersion.Major -lt 5 -or $IsWindows) -and
$env:LOCALAPPDATA -and
(-not (Test-Path "$env:LOCALAPPDATA\PackageManagement\ProviderAssemblies\nuget\2.8.5.208\Microsoft.PackageManagement.NuGetProvider.dll")) -and
(Get-PSFConfigValue -FullName 'PSFramework.NuGet.LocalBootstrap')
) {
$null = New-Item -Path "$env:LOCALAPPDATA\PackageManagement\ProviderAssemblies\nuget\2.8.5.208" -ItemType Directory -Force -ErrorAction SilentlyContinue
Copy-Item -Path "$script:ModuleRoot\bin\Microsoft.PackageManagement.NuGetProvider.dll" -Destination "$env:LOCALAPPDATA\PackageManagement\ProviderAssemblies\nuget\2.8.5.208" -ErrorAction SilentlyContinue
}
39 changes: 39 additions & 0 deletions PSFramework.NuGet/xml/PSFramework.NuGet.Format.ps1xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,45 @@
<?xml version="1.0" encoding="utf-16"?>
<Configuration>
<ViewDefinitions>
<!-- PSFramework.NuGet.GetReport -->
<View>
<Name>PSFramework.NuGet.GetReport</Name>
<ViewSelectedBy>
<TypeName>PSFramework.NuGet.GetReport</TypeName>
</ViewSelectedBy>
<TableControl>
<AutoSize/>
<TableHeaders>
<TableColumnHeader/>
<TableColumnHeader/>
<TableColumnHeader/>
<TableColumnHeader/>
<TableColumnHeader/>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>ComputerName</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>V2</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>V3</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>V2CanInstall</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>V2CanPublish</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>

<!-- PSFramework.NuGet.ModuleInfo -->
<View>
<Name>PSFramework.NuGet.ModuleInfo</Name>
Expand Down
101 changes: 101 additions & 0 deletions bootstrap.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<#
.SYNOPSIS
Installs all that is needed to run PSFramework.NuGet without using the PowerShellGet tools.

.DESCRIPTION
Installs all that is needed to run PSFramework.NuGet without using the PowerShellGet tools.

.EXAMPLE
PS C:\> .\bootstrap.ps1

Installs all that is needed to run PSFramework.NuGet without using the PowerShellGet tools.

.EXAMPLE
PS C:\> Iwr https://raw.githubusercontent.com/PowershellFrameworkCollective/PSFramework.NuGet/refs/heads/master/bootstrap.ps1 | iex

This one-liner will download the script into memory and then execute it directly, enabling PowerShell package management on the local computer.
#>
[CmdletBinding()]
param (

)

$ErrorActionPreference = 'Stop'
trap {
Write-Warning "Script failed: $_"
throw $_
}

#region Functions
function Find-GalleryModule {
[CmdletBinding()]
param (
[string[]]
$Name
)

foreach ($moduleName in $Name) {
$page = Invoke-WebRequest "https://www.powershellgallery.com/packages/$moduleName" -UseBasicParsing
$versions = $page.Links | Where-Object href -Match "^/packages/$moduleName/\d+(\.\d+){1,3}$"
foreach ($version in $versions) {
$null = $version.href -match '/(\d+(\.\d+){1,3})$'
Add-Member -InputObject $version -MemberType NoteProperty -Name Version -Value ($matches.1 -as [version]) -Force
}

$latest = $versions | Sort-Object Version -Descending | Select-Object -First 1

[PSCustomObject]@{
Name = $moduleName
Version = $latest.Version
Link = 'https://psg-prod-eastus.azureedge.net/packages/{0}.{1}.nupkg' -f $moduleName.ToLower(), $latest.Version
}
}
}

function Install-GalleryModule {
[CmdletBinding()]
param (
$Module
)

Write-Host "Installing: $($Module.Name) ($($Module.Version))"

trap {
Write-Host " Failed: $_" -ForegroundColor Red -BackgroundColor Black
return
}

# Resolve target path and skip if not needed
$modulePath = $env:PSModulePath -split ';' | Where-Object { $_ -match '\\Documents\\' } | Select-Object -First 1
if (-not $modulePath) { $modulePath = $env:PSModulePath -split ';' | Select-Object -First 1 }
$moduleRoot = Join-Path -Path $modulePath -ChildPath "$($Module.Name)/$($Module.Version)"
if (Test-Path -Path $moduleRoot) {
Write-Host " $($Module.Name) already installed, skipping"
return
}

$ProgressPreference = 'SilentlyContinue'
$staging = New-Item -Path $env:TEMP -Name "PSMS-$(Get-Random)" -ItemType Directory
Invoke-WebRequest -Uri $Module.Link -OutFile "$($staging.FullName)\$($Module.Name).zip" -ErrorAction Stop
Expand-Archive -Path "$($staging.FullName)\$($Module.Name).zip" -DestinationPath $staging.FullName -ErrorAction Stop

# Remove undesired parts
Remove-Item -Path "$($staging.FullName)\$($Module.Name).zip"
Remove-Item -Path "$($staging.FullName)\$($Module.Name).nuspec"
Remove-Item -LiteralPath "$($staging.FullName)\[Content_Types].xml"
Remove-Item -Path "$($staging.FullName)\_rels" -Recurse -Force
Remove-Item -Path "$($staging.FullName)\package" -Recurse -Force

# Deploy to Documents
$null = New-Item -Path $moduleRoot -ItemType Directory -Force
Move-Item -Path "$($staging.FullName)\*" -Destination $moduleRoot -Force -ErrorAction Stop
Write-Host " Successfully completed" -ForegroundColor Green -BackgroundColor Black

Remove-Item -Path $staging -ErrorAction SilentlyContinue -Force -Recurse
}
#endregion Functions

$modules = Find-GalleryModule -Name PSFramework, ConvertToPSD1, PSFramework.NuGet
foreach ($module in $modules) {
Install-GalleryModule -Module $module
}