Skip to content

Instantly share code, notes, and snippets.

@dancing-groot
Last active May 20, 2026 17:41
Show Gist options
  • Select an option

  • Save dancing-groot/b0521f8152b2aabc6876db7ea1cc922e to your computer and use it in GitHub Desktop.

Select an option

Save dancing-groot/b0521f8152b2aabc6876db7ea1cc922e to your computer and use it in GitHub Desktop.
Update-RequireModules
function Update-RequireModules
{
<#
.SYNOPSIS
Checks repository pre-requisites and install/update the modules needed for the script using PSResouceGet
.LINK
https://gist.github.com/dancing-groot/b0521f8152b2aabc6876db7ea1cc922e
.NOTES
Version: 2026.05.20
Author: @dancing-groot
Notes: Create PSResourceGet profile directory before invoking any PSResourceGet cmdlet.
When running as NT AUTHORITY\SYSTEM (e.g. a ConfigMgr Task Sequence), the
LOCALAPPDATA path has never been initialised. PSResourceGet cmdlets that expose
dynamic parameters (Set-PSResourceRepository) call GetDynamicParameters() during
PowerShell's parameter-binding phase before any try/catch can fire and throw
GetDynamicParametersException if PSResourceRepository.xml is missing.
Use Register-PSResourceRepository (which creates the XML) instead of
Set-PSResourceRepository (which requires the XML to already exist) when first
registering PSGallery.
#>
[cmdletBinding()]
param
(
[Parameter(Mandatory, ValueFromPipeline, ValueFromPipelinebyPropertyName)]
[string[]]$Module
)
begin
{
if ($PSBoundParameters['Debug']) { $DebugPreference = 'Continue' }
if ($PSBoundParameters['Verbose']) { $VerbosePreference = 'Continue' }
## Update PowerShellGet Pre-Requisites
# Force TLS 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
# NuGet Package Provider
try
{
Get-PackageProvider -Name NuGet -Debug:$false -ErrorAction Stop | Out-Null
}
catch
{
try
{
Install-PackageProvider -Name NuGet -Force -ErrorAction Stop
}
catch
{
if ($adtSession) { Write-ADTLogEntry -Message "Could not install Package Provider NuGet" -Severity Warning }
else { Write-Host "Could not install Package Provider NuGet" -ForegroundColor Red }
}
}
# PowerShellGet Module
try
{
Get-Module -Name PowerShellGet -Debug:$false -ErrorAction Stop | Out-Null
}
catch
{
try
{
Install-Module PowerShellGet -AllowClobber -Scope AllUsers -Force -Confirm:$false -ErrorAction Stop
}
catch
{
Install-Module PowerShellGet -AllowClobber -Scope CurrentUser -Force -Confirm:$false
}
}
# Guard: create the PSResourceGet profile directory for the running user before invoking
# any PSResourceGet cmdlet. Under NT AUTHORITY\SYSTEM, LOCALAPPDATA resolves to a path
# that is never pre-populated, causing GetDynamicParametersException on cmdlets such as
# Set-PSResourceRepository that read PSResourceRepository.xml during parameter binding.
$PSResourceGetDir = Join-Path -Path $env:LOCALAPPDATA -ChildPath 'PSResourceGet'
if (-not (Test-Path -LiteralPath $PSResourceGetDir -PathType Container))
{
if ($adtSession) { Write-ADTLogEntry -Message "Creating PSResourceGet directory for current user profile: $PSResourceGetDir" }
else { Write-Debug "Creating PSResourceGet directory for current user profile: $PSResourceGetDir" }
New-Item -Path $PSResourceGetDir -ItemType Directory -Force | Out-Null
}
# Set PSGallery Repository to v2 if needed
try
{
Get-PSResourceRepository -Name PSGallery -Debug:$false -ErrorAction Stop | Out-Null
}
catch
{
if ($adtSession) { Write-ADTLogEntry -Message "PSGallery not found. Installing PSResourceGet module." }
else { Write-Debug "PSGallery not found. Installing PSResourceGet module." }
try
{
Install-Module -Name Microsoft.PowerShell.PSResourceGet -Scope AllUsers -Force -ErrorAction Stop
}
catch
{
Install-Module -Name Microsoft.PowerShell.PSResourceGet -Scope CurrentUser -Force
}
Import-Module -Name Microsoft.PowerShell.PSResourceGet -Force
# Re-check: installing/importing the module may have initialised the repository store
# with PSGallery already present. Only register if it is still absent.
if (-not (Get-PSResourceRepository -Name PSGallery -Debug:$false -ErrorAction SilentlyContinue))
{
if ($adtSession) { Write-ADTLogEntry -Message "Registering PSGallery as a trusted v2 repository" }
else { Write-Verbose "Registering PSGallery as a trusted v2 repository" }
Register-PSResourceRepository -PSGallery -Trusted
}
}
# Trust PowerShell Gallery. Set-PSResourceRepository is safe here because PSResourceRepository.xml
# is guaranteed to exist by this point (either it was already present, or Register-PSResourceRepository
# created it in the catch block above).
if (Get-PSResourceRepository -Debug:$false | Where-Object { $_.Name -eq "PSGallery" -and $_.Trusted -eq $false })
{
if ($adtSession) { Write-ADTLogEntry -Message "Trusting the Repository 'PSGallery'" }
else { Write-Verbose "Trusting the Repository 'PSGallery'" }
Set-PSResourceRepository -Name "PSGallery" -Trusted
}
try
{
if ($adtSession) { Write-ADTLogEntry -Message "Package Provider: NuGet $((Get-PackageProvider -Name NuGet -Debug:$false -ErrorAction Stop).Version)" }
else { Write-Debug "Package Provider: NuGet $((Get-PackageProvider -Name NuGet -Debug:$false -ErrorAction Stop).Version)" }
}
catch
{
if ($adtSession) { Write-ADTLogEntry -Message "Could not retrieve version for Package Provider NuGet" -Severity Error }
else { Write-Debug "Could not retrieve version for Package Provider NuGet" }
}
if ($adtSession)
{
Write-ADTLogEntry -Message "Module: PowerShellGet $((Get-Module -Name PowerShellGet -Debug:$false).Version)"
Write-ADTLogEntry -Message "Module: PSResourceGet $((Get-Module -Name Microsoft.PowerShell.PSResourceGet -Debug:$false).Version)"
Write-ADTLogEntry -Message "Resource Repository: PSGallery $((Get-PSResourceRepository -Name PSGallery -Debug:$false).ApiVersion)"
}
else
{
Write-Debug "Module: PowerShellGet $((Get-Module -Name PowerShellGet -Debug:$false).Version)"
Write-Debug "Module: PSResourceGet $((Get-Module -Name Microsoft.PowerShell.PSResourceGet -Debug:$false).Version)"
Write-Debug "Resource Repository: PSGallery $((Get-PSResourceRepository -Name PSGallery -Debug:$false).ApiVersion)"
}
}
process
{
if (-not (Get-PSResource -Name $Module -Debug:$false -ErrorAction SilentlyContinue))
{
try
{
Install-PSResource -Name $Module -Debug:$false -Scope AllUsers -ErrorAction Stop
}
catch
{
Install-PSResource -Name $Module -Debug:$false -Scope CurrentUser
}
if ($adtSession) { Write-ADTLogEntry -Message "Module '$Module' Installed" }
else { Write-Verbose "Module '$Module' Installed" }
}
else
{
try
{
Update-PSResource $Module -Scope AllUsers -Debug:$false -ErrorAction Stop
}
catch
{
Update-PSResource $Module -Scope CurrentUser -Debug:$false
}
if ($adtSession) { Write-ADTLogEntry -Message "Module '$Module' Updated" }
else { Write-Verbose "Module '$Module' Updated" }
}
if ($adtSession) { Write-ADTLogEntry -Message "Module: $Module $((Get-Module -Name $Module -Debug:$false).Version)" }
else { Write-Debug "Module: $Module $((Get-Module -Name $Module -Debug:$false).Version)" }
}
} # Update-RequireModules
"Az.Accounts", "Az.KeyVault" | Update-RequireModules
@dancing-groot

Copy link
Copy Markdown
Author

[2026.05.15]

  • Improved error handling when running as SYSTEM
  • Allow the function to silently fail to allow the script to continue - if the module can't be loaded/updated, handle it outside of the function as it's script specific

@dancing-groot

Copy link
Copy Markdown
Author

[2026.05.20]

  • Fixed argument entered twice
  • Cleaned up script
  • Write to PSADT log if present

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment