Limpieza de firmas del SCCM con Powershell
Hola a todos!
Adjunto un script para limpiar las firmas de antimalware antiguas del SCCM.
<# | |
.SYNOPSIS | |
Perform a clean up of expired and/or supersded Software Updates in all Software Update Groups | |
.DESCRIPTION | |
Use this script if you need to perform a clean up of expired and/or superseded Software Updates from all Software Upgrade Groups in ConfigMgr | |
.PARAMETER SiteServer | |
Site server name with SMS Provider installed | |
.PARAMETER Option | |
Select an option to clean either ExpiredOnly, SupersededOnly or ExpiredSuperseded Software Updates from each Software Update Group | |
.PARAMETER RemoveContent | |
Remove the content for those Software Updates that will be removed from a Software Upgrade Group | |
.PARAMETER ShowProgress | |
Show a progressbar displaying the current operation | |
.EXAMPLE | |
Clean Software Update Groups from expired Software Updates, while showing the current progress and removing downloaded content, on a Primary Site server called 'CM01': | |
.Clean-CMSoftwareUpdateGroups.ps1 -SiteServer CM01 -Option ExpiredOnly -RemoveContent -ShowProgress | |
Clean Software Update Groups from superseded Software Updates, while showing the current progress, on a Primary Site server called 'CM01': | |
.Clean-CMSoftwareUpdateGroups.ps1 -SiteServer CM01 -Option SupersededOnly -ShowProgress | |
Clean Software Update Groups from expired and supersded Software Updates with verbose output, on a Primary Site server called 'CM01': | |
.Clean-CMSoftwareUpdateGroups.ps1 -SiteServer CM01 -Option ExpiredSuperseded -Verbose | |
.NOTES | |
Name: Clean-CMSoftwareUpdateGroups.ps1 | |
Author: Nickolaj Andersen | |
Contact: @NickolajA | |
Created: 2015-12-17 | |
Version: 2.1 | |
#> | |
[CmdletBinding(SupportsShouldProcess=$true)] | |
param( | |
[parameter(Mandatory=$true, HelpMessage="Site server where the SMS Provider is installed")] | |
[ValidateScript({Test-Connection -ComputerName $_ -Count 1 -Quiet})] | |
[ValidateNotNullOrEmpty()] | |
[string]$SiteServer, | |
[parameter(Mandatory=$true, HelpMessage="Select an option to clean either ExpiredOnly, SupersededOnly or ExpiredSuperseded Software Updates from each Software Update Group")] | |
[ValidateNotNullOrEmpty()] | |
[ValidateSet("ExpiredOnly","SupersededOnly","ExpiredSuperseded")] | |
[string]$Option, | |
[parameter(Mandatory=$false, HelpMessage="Remove the content for those Software Updates that will be removed from a Software Upgrade Group")] | |
[ValidateNotNullOrEmpty()] | |
[switch]$RemoveContent, | |
[parameter(Mandatory=$false, HelpMessage="Show a progressbar displaying the current operation")] | |
[ValidateNotNullOrEmpty()] | |
[switch]$ShowProgress | |
) | |
Begin { | |
# Determine SiteCode from WMI | |
try { | |
Write-Verbose "Determining Site Code for Site server: '$($SiteServer)'" | |
$SiteCodeObjects = Get-WmiObject -Namespace "rootSMS" -Class SMS_ProviderLocation -ComputerName $SiteServer -ErrorAction Stop | |
foreach ($SiteCodeObject in $SiteCodeObjects) { | |
if ($SiteCodeObject.ProviderForLocalSite -eq $true) { | |
$SiteCode = $SiteCodeObject.SiteCode | |
Write-Verbose -Message "Site Code: $($SiteCode)" | |
} | |
} | |
} | |
catch [System.UnauthorizedAccessException] { | |
Write-Warning -Message "Access denied" ; break | |
} | |
catch [System.Exception] { | |
Write-Warning -Message "Unable to determine Site Code" ; break | |
} | |
# Temporarily set ErrorActionPreference | |
$ErrorActionPreference = "Stop" | |
# Set ProgressCount | |
if ($PSBoundParameters["ShowProgress"]) { | |
$ProgressCount = 0 | |
} | |
} | |
Process { | |
try { | |
$StartTime = [Diagnostics.Stopwatch]::StartNew() | |
$SUGResults = (Get-WmiObject -Namespace "rootSMSsite_$($SiteCode)" -Class SMS_AuthorizationList -ComputerName $SiteServer -ErrorAction SilentlyContinue | Measure-Object).Count | |
$SUGResults | |
if ($SUGResults -ge 1) { | |
# Get list of removable Software Updates | |
switch ($Option) { | |
"ExpiredOnly" { | |
$Query = "SELECT SU.CI_ID FROM SMS_SoftwareUpdate AS SU JOIN SMS_CIRelation AS CIR ON SU.CI_ID = CIR.ToCIID WHERE CIR.RelationType = 1 AND SU.IsExpired = 1 AND SU.IsSuperseded = 0" | |
} | |
"SupersededOnly" { | |
$Query = "SELECT SU.CI_ID FROM SMS_SoftwareUpdate AS SU JOIN SMS_CIRelation AS CIR ON SU.CI_ID = CIR.ToCIID WHERE CIR.RelationType = 1 AND SU.IsExpired = 0 AND SU.IsSuperseded = 1" | |
} | |
"ExpiredSuperseded" { | |
$Query = "SELECT SU.CI_ID FROM SMS_SoftwareUpdate AS SU JOIN SMS_CIRelation AS CIR ON SU.CI_ID = CIR.ToCIID WHERE CIR.RelationType = 1 AND (SU.IsExpired = 1 OR SU.IsSuperseded = 1)" | |
} | |
} | |
try { | |
$RemovableUpdates = Get-WmiObject -Namespace "rootSMSsite_$($SiteCode)" -Query $Query -ComputerName $SiteServer -ErrorAction Stop | |
$RemovableUpdatesList = New-Object -TypeName System.Collections.ArrayList | |
foreach ($RemovableUpdate in $RemovableUpdates) { | |
$RemovableUpdatesList.Add($RemovableUpdate.CI_ID) | Out-Null | |
} | |
} | |
catch [System.Exception] { | |
Write-Warning -Message "Unable to determine removable Software Updates from selected option" | |
} | |
# Enumerate each Software Update Group | |
$AuthorizationLists = Get-WmiObject -Namespace "rootSMSsite_$($SiteCode)" -Class SMS_AuthorizationList -ComputerName $SiteServer -ErrorAction Stop | |
foreach ($AuthorizationList in $AuthorizationLists) { | |
Write-Verbose -Message "Start processing '$($AuthorizationList.LocalizedDisplayName)'" | |
if ($PSBoundParameters["ShowProgress"]) { | |
$ProgressCount++ | |
} | |
Write-Progress -Activity "Processing Software Updates Groups" -Id 1 -Status "$($ProgressCount) / $($SUGResults)" -CurrentOperation "Current Software Update Group: '$($AuthorizationList.LocalizedDisplayName)'" -PercentComplete (($ProgressCount / $SUGResults) * 100) | |
$AuthorizationList = [wmi]"$($AuthorizationList.__PATH)" | |
$UpdatesCount = $AuthorizationList.Updates.Count | |
$UpdatesList = New-Object -TypeName System.Collections.ArrayList | |
$RemovedUpdatesList = New-Object -TypeName System.Collections.ArrayList | |
# Enumerate each Software Update in current Software Update Group if eligible for removal | |
foreach ($Update in ($AuthorizationList.Updates)) { | |
if ($Update -notin $RemovableUpdatesList) { | |
$UpdatesList.Add($Update) | Out-Null | |
} | |
else { | |
$RemovedUpdatesList.Add($Update) | Out-Null | |
} | |
} | |
# Update Software Update Group updates if count of objects in UpdatesList is less than before | |
if ($UpdatesCount -gt $UpdatesList.Count) { | |
try { | |
if ($PSCmdlet.ShouldProcess("$($AuthorizationList.LocalizedDisplayName)","Clean '$($UpdatesCount - ($UpdatesList.Count))' updates")) { | |
if ($UpdatesList.Count -ge 1) { | |
$AuthorizationList.Updates = $UpdatesList | |
$AuthorizationList.Put() | Out-Null | |
Write-Verbose -Message "Successfully cleaned up $($UpdatesCount - ($UpdatesList.Count)) updates from '$($AuthorizationList.LocalizedDisplayName)'" | |
} | |
else { | |
$AuthorizationList.Updates = @() | |
$AuthorizationList.Put() | Out-Null | |
Write-Verbose -Message "Successfully cleaned up all updates from '$($AuthorizationList.LocalizedDisplayName)'" | |
} | |
} | |
# Remove content for each CI_ID in the RemovedUpdatesList array | |
if ($PSBoundParameters["RemoveContent"]) { | |
try { | |
$DeploymentPackageList = New-Object -TypeName System.Collections.ArrayList | |
foreach ($CI_ID in $RemovedUpdatesList) { | |
Write-Verbose -Message "Collecting content data for CI_ID: $($CI_ID)" | |
$ContentQuery = "SELECT SMS_PackageToContent.ContentID,SMS_PackageToContent.PackageID from SMS_PackageToContent JOIN SMS_CIToContent ON SMS_CIToContent.ContentID = SMS_PackageToContent.ContentID WHERE SMS_CIToContent.CI_ID IN ($($CI_ID))" | |
$ContentData = Get-WmiObject -Namespace "rootSMSsite_$($SiteCode)" -Query $ContentQuery -ComputerName $SiteServer -ErrorAction Stop | |
Write-Verbose -Message "Found '$(($ContentData | Measure-Object).Count)' objects" | |
foreach ($Content in $ContentData) { | |
$ContentID = $Content | Select-Object -ExpandProperty ContentID | |
$PackageID = $Content | Select-Object -ExpandProperty PackageID | |
$DeploymentPackage = [wmi]"$($SiteServer)rootSMSsite_$($SiteCode):SMS_SoftwareUpdatesPackage.PackageID='$($PackageID)'" | |
if ($DeploymentPackage.PackageID -notin $DeploymentPackageList) { | |
$DeploymentPackageList.Add($DeploymentPackage.PackageID) | Out-Null | |
} | |
if ($PSCmdlet.ShouldProcess("$($PackageID)","Remove ContentID '$($ContentID)'")) { | |
Write-Verbose -Message "Attempting to remove ContentID '$($ContentID)' from PackageID '$($PackageID)'" | |
$ReturnValue = $DeploymentPackage.RemoveContent($ContentID, $false) | |
if ($ReturnValue.ReturnValue -eq 0) { | |
Write-Verbose -Message "Successfully removed ContentID '$($ContentID)' from PackageID '$($PackageID)'" | |
} | |
} | |
} | |
} | |
} | |
catch [Exception] { | |
Write-Warning -Message "An error occured when attempting to remove ContentID '$($ContentID)' from '$($PackageID)'" | |
} | |
} | |
} | |
catch [Exception] { | |
Write-Warning -Message "Unable to save changes to '$($AuthorizationList.LocalizedDisplayName)'" ; break | |
} | |
} | |
else { | |
Write-Verbose -Message "No changes detected, will not update '$($AuthorizationList.LocalizedDisplayName)'" | |
} | |
# Refresh content source for all Deployment Packages in the DeploymentPackageList array | |
if (($DeploymentPackageList.Count -ge 1) -and ($PSBoundParameters["RemoveContent"])) { | |
foreach ($DPackageID in $DeploymentPackageList) { | |
if ($PSCmdlet.ShouldProcess("$($DPackageID)","Refresh content source")) { | |
$DPackage = [wmi]"$($SiteServer)rootSMSsite_$($SiteCode):SMS_SoftwareUpdatesPackage.PackageID='$($DPackageID)'" | |
Write-Verbose -Message "Attempting to refresh content source for Deployment Package '$($DPackage.Name)'" | |
$ReturnValue = $DPackage.RefreshPkgSource() | |
if ($ReturnValue.ReturnValue -eq 0) { | |
Write-Verbose -Message "Successfully refreshed content source for Deployment Package '$($DPackage.Name)'" | |
} | |
} | |
} | |
} | |
} | |
} | |
else { | |
Write-Warning -Message "Unable to locate any Software Update Groups" | |
} | |
} | |
catch [Exception] { | |
Write-Error -Message $_.Exception.Message | |
} | |
} | |
End { | |
# Temporarily set ErrorActionPreference | |
$ErrorActionPreference = "Continue" | |
# Complete write progress activity | |
if ($PSBoundParameters["ShowProgress"]) { | |
Write-Progress -Activity "Processing Software Update Groups" -Completed -ErrorAction SilentlyContinue | |
} | |
# Output script exection time | |
$StartTime.Stop() | |
Write-Verbose -Message "Script execution: $($StartTime.Elapsed.Minutes) min and $($StartTime.Elapsed.Seconds) seconds" | |
} |
Guardas el script y lo ejecutas de 2 modos:
Sólo eliminar los expirados, y el otro expirados y los sustituidos. Para ejecutar el script es importante reemplazar la variable SERVIDOR por la de vuestro servidor SCCM
#JUST EXPIRED
.\Clean-CMSoftwareUpdateGroups.ps1 -SiteServer SERVIDOR -Option ExpiredOnly -Verbose -RemoveContent -ShowProgress
#EXPIRED AND SUPERSEDED
.\Clean-CMSoftwareUpdateGroups.ps1 -SiteServer SERVIDOR -Option ExpiredSuperseded -Verbose -RemoveContent -ShowProgress
Hasta pronto!