functions/Repository/Update-PSFRepository.ps1
function Update-PSFRepository { <# .SYNOPSIS Executes configured repository settings. .DESCRIPTION Executes configured repository settings. Using configuration settings - for example applied per GPO or configuration file - it is possible to define intended repositories. The configuration settings must be named as 'PSFramework.NuGet.Repositories.<Repository Name>.<Setting>' Available settings: - Uri: Url or filesystem path to the repository. Used for both install and publish. - Priority: Priority of a PowerShell Repository. Numeric value, determines repository precedence. - Type: What kind of PowerShellGet version to apply the configuration to. Details on the options below. Defaults to 'Any'. - Trusted: Whether the repository should be trusted. Can be set to 0, 1, $false or $true. Defaults to $true. - Present: Whether the repository should exist at all. Can be set to 0, 1, $false or $true. Defaults to $true. Allows creating delete orders. Does not differentiate between V2 & V3 - Proxy: Link to the proxy to use. Property only available when creating a new repository, not for updating an existing one. Supported "Type" settings to handle different PowerShellGet versions: - Any: Will register as V3 if available, otherwise V2. Will not update to V3 if already on V2. - Update: Will register under highest version available, upgrading from older versions if already available on old versions - All: Will register on ALL available versions - V2: Will only register on V2. V3 - if present and configured - will be unregistered. - V2Preferred: Will only register on V2. If V2 does not exist, existing V3 repositories will be allowed. - V3: Will only register on V3. If V2 is present, it will be unregistered, irrespective of whether V3 is available. .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Update-PSFRepository Executes configured repository settings, creating, updating and deleting repositories as defined. #> [CmdletBinding(SupportsShouldProcess = $true)] Param ( ) begin { #region Functions function Compare-Repository { [CmdletBinding()] param ( $Actual, $Configured ) $supportedTypes = 'Any', 'Update', 'All', 'V2', 'V2Preferred', 'V3' foreach ($configuredRepo in $Configured) { # Incomplete configurations are processed in a limited manner, as not enough information is present to create or delete $isIncomplete = -not $configuredRepo.Type -or -not $configuredRepo.Uri if (-not $isIncomplete -and $configuredRepo.Type -notin $supportedTypes) { Write-PSFMessage -Level Warning -String 'Update-PSFRepository.Error.InvalidType' -StringValues $configuredRepo.Type, ($supportedTypes -join ', ') continue } $matching = $Actual | Where-Object Name -EQ $configuredRepo._Name # An incomplete configuration can only be used to modify an existing repository, so skip if nothing matches if ($isIncomplete -and -not $matching) { continue } if (-not $isIncomplete) { $shouldExist = -not ($configuredRepo.PSObject.Properties.Name -contains 'Present' -and -not $configuredRepo.Present) $mayBeV2 = $configuredRepo.Type -in 'Any', 'Update', 'All', 'V2', 'V2Preferred' if ('Update' -eq $configuredRepo.Type -and $script:psget.V3) { $mayBeV2 = $false } $mustBeV2 = $configuredRepo.Type -in 'All', 'V2' $mayBeV3 = $configuredRepo.Type -in 'Any', 'Update', 'All', 'V3', 'V2Preferred' if ('V2Preferred' -eq $configuredRepo.Type -and $script:psget.V2) { $mayBeV3 = $false } $mustBeV3 = $configuredRepo.Type -in 'Update', 'All', 'V3' # Case: Should not exist and does not if (-not $shouldExist -and -not $matching) { continue } #region Deletion foreach ($matchingRepo in $matching) { if ( # Should exist $shouldExist -and ( $matchingRepo.Type -eq 'V2' -and $mayBeV2 -or $matchingRepo.Type -eq 'V3' -and $mayBeV3 ) ) { continue } [PSCustomObject]@{ Type = 'Delete' Configured = $configuredRepo Actual = $matchingRepo Changes = @{ } } } if (-not $shouldExist) { continue } #endregion Deletion #region Creation # Case: Should exist but does not if ($shouldExist -and -not $matching) { [PSCustomObject]@{ Type = 'Create' Configured = $configuredRepo Actual = $null Changes = @{ } } continue } # Case: Must exist on V2 but does not if ($mustBeV2 -and $matching.Type -notcontains 'V2' -and $script:psget.V2) { [PSCustomObject]@{ Type = 'Create' Configured = $configuredRepo Actual = $matching Changes = @{ } } } # Case: Must exist on V3 but does not if ($mustBeV3 -and $matching.Type -notcontains 'V3' -and $script:psget.V3) { [PSCustomObject]@{ Type = 'Create' Configured = $configuredRepo Actual = $matching Changes = @{ } } } # If there is no matching, existing repository, there is no need to update if (-not $matching) { continue } #endregion Creation } #region Update foreach ($matchingRepo in $matching) { $intendedUri = $configuredRepo.Uri if ('V2' -eq $matchingRepo.Type) { $intendedUri = $intendedUri -replace 'v3/index.json$', 'v2' } $trusted = $configuredRepo.Trusted -as [int] if ($null -eq $trusted -and $configuredRepo.Trusted -in 'True', 'False') { $trusted = $configuredRepo.Trusted -eq 'True' } if ($null -eq $trusted) { $trusted = $true } $changes = @{ } if (-not $isIncomplete -and $matchingRepo.Uri -ne $intendedUri) { $changes.Uri = $intendedUri } if ($matchingRepo.Trusted -ne $trusted) { $changes.Trusted = $trusted -as [bool] } if ( $configuredRepo.Priority -and $matchingRepo.Type -ne 'V2' -and $matchingRepo.Priority -ne $configuredRepo.Priority ) { $changes.Priority = $configuredRepo.Priority } if ($changes.Count -eq 0) { continue } [PSCustomObject]@{ Type = 'Update' Configured = $configuredRepo Actual = $matchingRepo Changes = $changes } } #endregion Update } } function New-Repository { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param ( $Change ) $registerV2 = $script:psget.V2 $registerV3 = $script:psget.V3 if ($Change.Actual.Type -contains 'V3') { $registerV3 = $false } if ($Change.Actual.Type -contains 'V2') { $registerV2 = $false } # If any already exists, we obviously want to create the other and need not process types again if (-not $Change.Actual) { switch ($Change.Configured.Type) { 'Any' { if ($registerV3) { $registerV2 = $false } } 'Update' { if ($registerV3) { $registerV2 = $false } } 'V2' { $registerV3 = $false } 'V2Preferrred' { $registerV3 = $false } 'V3' { $registerV2 = $false } } } $trusted = $Change.Configured.Trusted -as [int] if ($null -eq $trusted -and $Change.Configured.Trusted -in 'True', 'False') { $trusted = $Change.Configured.Trusted -eq 'True' } if ($null -eq $trusted) { $trusted = $true } if ($registerV2) { $uri = $Change.Configured.Uri -replace 'v3/index.json$', 'v2' $param = @{ Name = $Change.Configured._Name SourceLocation = $uri PublishLocation = $uri ErrorAction = 'Stop' } if ($trusted) { $param.InstallationPolicy = 'Trusted' } if ($Change.Configured.Proxy) { $param.Proxy = $Change.Configured.Proxy } try { Register-PSRepository @param } catch { Write-PSFMessage -Level Warning -String 'Update-PSFRepository.Register.Failed' -StringValues V2, $param.Name, $uri -ErrorRecord $_ } } if ($registerV3) { $param = @{ Name = $Change.Configured._Name Uri = $Change.Configured.Uri Trusted = $trusted ErrorAction = 'Stop' } if ($null -ne $Change.Configured.Priority) { $param.Priority = $Change.Configured.Priority } if ($Change.Configured.Proxy) { $param.Proxy = $Change.Configured.Proxy } try { Register-PSResourceRepository @param } catch { Write-PSFMessage -Level Warning -String 'Update-PSFRepository.Register.Failed' -StringValues V3, $param.Name, $param.Uri -ErrorRecord $_ } } } function Remove-Repository { [CmdletBinding(SupportsShouldProcess = $true)] param ( $Change ) switch ($Change.Actual.Type) { 'V2' { Invoke-PSFProtectedCommand -ActionString 'Update-PSFRepository.Repository.Unregister' -ActionStringValues $change.Actual.Type, $Change.Actual.Name -ScriptBlock { Unregister-PSRepository -Name $change.Actual.Name -ErrorAction Stop } -Target $change.Actual.Name -PSCmdlet $PSCmdlet -EnableException $false } 'V3' { Invoke-PSFProtectedCommand -ActionString 'Update-PSFRepository.Repository.Unregister' -ActionStringValues $change.Actual.Type, $Change.Actual.Name -ScriptBlock { Unregister-PSResourceRepository -Name $change.Actual.Name -ErrorAction Stop } -Target $change.Actual.Name -PSCmdlet $PSCmdlet -EnableException $false } } } function Set-Repository { [CmdletBinding(SupportsShouldProcess = $true)] param ( $Change ) $param = @{ Name = $change.Actual.Name } switch ($Change.Actual.Type) { 'V2' { if ($Change.Changes.Uri) { $param.SourceLocation = $Change.Changes.Uri $param.PublishLocation = $Change.Changes.Uri } if ($Change.Changes.Keys -contains 'Trusted') { if ($Change.Changes.Trusted) { $param.InstallationPolicy = 'Trusted' } else { $param.InstallationPolicy = 'Untrusted' } } Invoke-PSFProtectedCommand -ActionString 'Update-PSFRepository.Repository.Update' -ActionStringValues $change.Actual.Type, $Change.Actual.Name, ($param.Keys -join ',') -ScriptBlock { Set-PSRepository @param -ErrorAction Stop } -Target $change.Actual.Name -PSCmdlet $PSCmdlet -EnableException $false } 'V3' { if ($Change.Changes.Uri) { $param.Uri = $Change.Changes.Uri } if ($Change.Changes.Keys -contains 'Priority') { $param.Priority = $Change.Changes.Priority } if ($Change.Changes.Keys -contains 'Trusted') { $param.Trusted = $Change.Changes.Trusted } Invoke-PSFProtectedCommand -ActionString 'Update-PSFRepository.Repository.Update' -ActionStringValues $change.Actual.Type, $Change.Actual.Name, ($param.Keys -join ',') -ScriptBlock { Set-PSResourceRepository @param -ErrorAction Stop } -Target $change.Actual.Name -PSCmdlet $PSCmdlet -EnableException $false } } } #endregion Functions } process { $repositories = Get-PSFRepository $configuredRepositories = Select-PSFConfig -FullName PSFramework.NuGet.Repositories.* -Depth 3 $changes = Compare-Repository -Actual $repositories -Configured $configuredRepositories foreach ($change in $changes) { switch ($change.Type) { 'Create' { New-Repository -Change $change } 'Delete' { Remove-Repository -Change $change } 'Update' { Set-Repository -Change $change } } } } } |