Private/WinGet/New-WinGetRemediationScriptContent.ps1
|
function New-WinGetRemediationScriptContent { param( [Parameter(Mandatory)] [string[]]$PackageIdentifiers, [Parameter(Mandatory)] [ValidateSet('system', 'user')] [string]$Scope, [Parameter(Mandatory)] [ValidateSet('Detection', 'Remediation')] [string]$ScriptType ) $escapedPackageIdentifiers = @( $PackageIdentifiers | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Sort-Object -Unique | ForEach-Object { "'{0}'" -f (($_ -replace "'", "''")) } ) $allowListLiteral = if ($escapedPackageIdentifiers.Count -gt 0) { "@({0})" -f ($escapedPackageIdentifiers -join ', ') } else { '@()' } $wingetScope = if ($Scope -eq 'system') { 'machine' } else { 'user' } $scopeLabel = if ($Scope -eq 'system') { 'System' } else { 'User' } $logOperation = if ($ScriptType -eq 'Detection') { 'Detect' } else { 'Remediate' } $bootstrapFragment = Get-WinGetBootstrapScriptFragment -LogFunctionName 'Write-RemediationLog' -BootstrapMessage 'Bootstrapping WinGet for proactive remediation.' $scriptSuffix = if ($ScriptType -eq 'Detection') { @" `$pendingUpgrades = [System.Collections.Generic.List[string]]::new() foreach (`$packageIdentifier in `$packageIdentifiers) { `$escapedPackageIdentifier = [regex]::Escape(`$packageIdentifier) if (`$upgradeOutput -match `$escapedPackageIdentifier) { Write-RemediationLog -Message "Upgrade available for `$packageIdentifier." `$pendingUpgrades.Add(`$packageIdentifier) } } if (`$pendingUpgrades.Count -gt 0) { Write-RemediationLog -Message "Pending upgrades: `$(`$pendingUpgrades -join ', ')" exit 1 } Write-RemediationLog -Message 'No upgrades needed.' exit 0 "@ } else { @" `$completedUpgrades = [System.Collections.Generic.List[string]]::new() `$failedUpgrades = [System.Collections.Generic.List[string]]::new() foreach (`$packageIdentifier in `$packageIdentifiers) { `$escapedPackageIdentifier = [regex]::Escape(`$packageIdentifier) if (`$upgradeOutput -notmatch `$escapedPackageIdentifier) { continue } Write-RemediationLog -Message "Upgrade available for `$packageIdentifier. Starting remediation." & `$wingetPath upgrade --id "`$packageIdentifier" --exact --silent --force --scope `$scope --accept-package-agreements --accept-source-agreements 2>&1 | Out-String | ForEach-Object { if (-not [string]::IsNullOrWhiteSpace(`$_)) { Write-RemediationLog -Message `$_ } } `$exitCode = `$LASTEXITCODE if (`$exitCode -eq 0 -or `$exitCode -eq -1978335189) { `$completedUpgrades.Add(`$packageIdentifier) Write-RemediationLog -Message "Upgrade completed for `$packageIdentifier with exit code `$exitCode." } else { `$failedUpgrades.Add("`$packageIdentifier (`$exitCode)") Write-RemediationLog -Message "Upgrade failed for `$packageIdentifier with exit code `$exitCode." -Level 'WARN' } } if (`$failedUpgrades.Count -gt 0) { Write-RemediationLog -Message "Failed upgrades: `$(`$failedUpgrades -join ', ')" -Level 'ERROR' exit 1 } if (`$completedUpgrades.Count -gt 0) { Write-RemediationLog -Message "Completed upgrades: `$(`$completedUpgrades -join ', ')" } else { Write-RemediationLog -Message 'No upgrades were applicable during remediation.' } exit 0 "@ } return @" `$ErrorActionPreference = 'Stop' `$packageIdentifiers = $allowListLiteral `$scope = '$wingetScope' `$scopeLabel = '$scopeLabel' function Get-IntuneManagementExtensionLogDirectory { [CmdletBinding()] param() `$programDataPath = if (-not [string]::IsNullOrWhiteSpace(`$env:ProgramData)) { `$env:ProgramData } else { 'C:\ProgramData' } `$logDirectory = Join-Path -Path `$programDataPath -ChildPath 'Microsoft\IntuneManagementExtension\Logs' if (-not (Test-Path -Path `$logDirectory)) { `$null = New-Item -Path `$logDirectory -ItemType Directory -Force } return `$logDirectory } function Write-RemediationLog { [CmdletBinding()] param( [Parameter(Mandatory)] [string]`$Message, [Parameter()] [ValidateSet('INFO', 'WARN', 'ERROR')] [string]`$Level = 'INFO' ) `$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss.fff' `$entry = "[`$timestamp] [`$Level] `$Message" Add-Content -Path `$script:logPath -Value `$entry Write-Output `$entry } `$logDirectory = Get-IntuneManagementExtensionLogDirectory `$script:logPath = Join-Path -Path `$logDirectory -ChildPath "IntuneHydrationKit-WinGet-Remediation-$scopeLabel-$logOperation.log" Write-RemediationLog -Message "Starting WinGet proactive remediation $ScriptType for `$scopeLabel scope." Write-RemediationLog -Message "Allowlist contains `$(`$packageIdentifiers.Count) package identifier(s)." $bootstrapFragment `$wingetPath = Get-WinGetExecutablePath Write-RemediationLog -Message "Resolved winget executable: `$wingetPath" `$upgradeOutput = & `$wingetPath upgrade --scope `$scope --accept-source-agreements 2>&1 | Out-String Write-RemediationLog -Message "Upgrade scan completed for `$scopeLabel scope." "@ + [Environment]::NewLine + $scriptSuffix } |