Correct-PendingContentOnSpecificDP.ps1

  • 14 February 2018
  • Sean Huggans
Description: 

This script will compare what the database knows for packages on a specific Configuration Manager Distribution Point against what is actually in WMI and the Content library on that DP. If variances are found it reports on those in that DPs log file. Optionally, the script can be told to correct the variances it finds as well. This script will correct cases where content shows as distributed (green) in the console, but in the content library explorer shows greyed out and pending.

Usage: Correct-PendingContentonSpecificDP.ps1 -DPName -SiteCode -SiteServer -LogPath -FixBadPackages <$true/$false> -OutPutBadPackages <$true/$false> -FixObsoletePackages <$true/$false> -OutPutObsoletePackages <$true/$false>

Language: 
PowerShell
Usage Type: 
Standalone
Script Source: 
###############################################################################################################
# Correct-PendingContentOnSpecificDP.ps1
#
# This script will compare what the database knows for packages on a specific DP against what is actually in
# WMI and the Content library on that DP.  If variances are found it reports on those in that DPs log
# file.  Optionally, the script can be told to correct the variances it finds as well.
#
# Author: Sean Huggans
# Version: 2018.01.30
###############################################################################################################
 
param (
	$DPName,
	$SiteCode,
	$SiteServer,
	$LogPath,
	$FixBadPackages,
	$OutPutBadPackages,
	$FixObsoletePackages,
    $OutPutObsoletePackages
)
 
function Remove-PackageFromDPWMI ($DPName, $PackageID)
{
	$RemoveResult = Invoke-Command -ComputerName $DPName -ScriptBlock {
		param ($PackageID)
		$Result = $false
		try
		{
			Get-WmiObject -Namespace "ROOT\SCCMDP" -Class SMS_PackagesInContLib -Filter "PackageID = '$PackageID'" -ErrorAction Stop | Remove-WmiObject
			#Remove-WmiObject -Namespace "ROOT\SCCMDP" -Class SMS_PackagesInContLib1 -ErrorAction Stop -Confirm:$false | Where-Object {$_.PackageID -eq $PackageID}
			$Result = $true
		}
		catch
		{
			#nothing
		}
		return $Result
	} -ArgumentList $PackageID
	return $RemoveResult
}
 
function Remove-PackageFromContentLib ($DPName, $PackageID)
{
    Invoke-Command -ComputerName $DPName -ScriptBlock {
        param($PackageID)
        $RemovedINIs = new-object System.Collections.ArrayList
        $StorageVolumes = Get-Volume | Where-Object {(($_.DriveType -eq 'Fixed') -and ($_.DriveLetter))}
        foreach ($StorageVolume in $StorageVolumes) {
            Set-Location "$($StorageVolume.DriveLetter):"
            $ContentLibPath = "$($StorageVolume.DriveLetter):\SCCMContentLib\PkgLib"
            if (test-path -Path $ContentLibPath) {
                $PackageINI = "$($ContentLibPath)\$($PackageID).ini"
                if (Test-Path -path $PackageINI) {
                    try {
                        remove-item -Path $PackageINI -Force -Confirm:$false -ErrorAction Stop
                        $RemovedINIs.Add("$($PackageINI), Sucessfully Removed from PkgLib") | Out-Null
                    } catch {
                        $RemovedINIs.Add("$($PackageINI), Failed to Remove from PkgLib") | Out-Null
                    }
                }
            }
        }
        return $RemovedINIs
    } -ArgumentList $PackageID
}
 
function Invoke-SQL
{
    ########################################
    # Function Provided by Chris Magnuson
    ########################################
	param (
		[string]$dataSource,
		[string]$database,
		[string]$sqlCommand = $(throw "Please specify a query.")
	)
 
	$connectionString = "Data Source=$dataSource; " +
	"Integrated Security=SSPI; " +
	"Initial Catalog=$database"
 
	$connection = new-object system.data.SqlClient.SQLConnection($connectionString)
	$command = new-object system.data.sqlclient.sqlcommand($sqlCommand, $connection)
	$connection.Open()
 
	$adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
	$dataset = New-Object System.Data.DataSet
	$adapter.Fill($dataSet) | Out-Null
 
	$connection.Close()
	$dataSet.Tables
 
}
 
Function Refresh-SpecificDP
{
	###################################
	# Function by Mike Laughlin
	###################################
	param ($packageID,
		$dpName)
	$dpFound = $false
	If ($packageID.Length -ne 8)
	{
		Throw "Invalid package"
	}
	$distPoints = Get-WmiObject -ComputerName $SiteServer -Namespace "root\SMS\Site_$($siteCode)" -Query "Select * From SMS_DistributionPoint WHERE PackageID='$packageID'" -ErrorAction Stop
	ForEach ($dp In $distPoints)
	{
		If ((($dp.ServerNALPath).ToUpper()).Contains($dpName.ToUpper()))
		{
			$dpFound = $true
 
			Try
			{
				$dp.RefreshNow = $true
				$dp.Put() | Out-Null
				return $true
			}
			Catch [Exception]
			{
				return $false
			}
		}
	}
	If ($dpFound -eq $false)
	{
		return $false
	}
}
 
if (($DPName -ne $null) -and ($SiteCode -ne $null) -and ($SiteServer -ne $null))
{
 
	#Default these parameters if not provided
	if ($LogPath -eq $NULL)
	{
		$LogPath = "C:\Temp\Maintenance"
	}
	if ($OutPutBadPackages -eq $null)
	{
		$OutPutBadPackages = $false
	}
	if ($FixBadPackages -eq $NULL)
	{
		$FixBadPackages = $false
	}
	else
	{
		switch ($FixBadPackages)
		{
			"True" {
				$FixBadPackages = $true
			}
			"False" {
				$FixBadPackages = $false
			}
			"Yes" {
				$FixBadPackages = $true
			}
			"No" {
				$FixBadPackages = $false
			}
			default
			{
				$FixBadPackages = $false
			}
		}
	}
    if ($OutPutBadPackages -eq $null) {
        $OutPutBadPackages = $false
    }
	if ($FixObsoletePackages -eq $NULL)
	{
		$FixObsoletePackages = $false
	}
	else
	{
		switch ($FixObsoletePackages)
		{
			"True" {
				$FixObsoletePackages = $true
			}
			"False" {
				$FixObsoletePackages = $false
			}
			"Yes" {
				$FixObsoletePackages = $true
			}
			"No" {
				$FixObsoletePackages = $false
			}
			default
			{
				$FixObsoletePackages = $false
			}
		}
	}
    if ($OutPutObsoletePackages -eq $null) {
        $OutPutObsoletePackages = $false
    }
 
	$LogFile = "PendingContentFix-$($DPName).log"
 
 
	new-item -ItemType Directory -Path $LogPath -force -Confirm:$false -ErrorAction SilentlyContinue | out-null
 
	Write-Host "Script is running, progress can be monitored via the log at $($LogPath)\$($LogFile).  Once you run this script, do not run it against the same DP until distribution has finished."
    "[ $(Get-Date -Format 'yyyy.MM.dd hh:mm:ss') ] Script Started" | Out-File "$($LogPath)\$($LogFile)" -Append
	"Running comparisons on DP '$($DPName)'..." | Out-File "$($LogPath)\$($LogFile)" -Append
	[array]$AllPackages = Invoke-SQL -dataSource $SiteServer -database "CM_$($SiteCode)" -sqlCommand "select * from pkgstatus where pkgserver like '%$($DPName)%';"
	[array]$TotalPackages = $AllPackages.ID
	"Total Packages: $($TotalPackages.Count)" | Out-File "$($LogPath)\$($LogFile)" -Append
 
	[array]$PackagesInLib = Invoke-Command -ComputerName $DPName -ScriptBlock {
		$FilteredList = New-Object System.Collections.ArrayList
		try
		{
			[array]$PKGsInLib = $(Get-ChildItem -Path "C:\SCCMContentLib\PkgLib" -ErrorAction Stop | Where-Object { $_.Extension -eq ".ini" }).Name
		}
		catch
		{
			[array]$PKGsInLib = $(Get-ChildItem -Path "D:\SCCMContentLib\PkgLib" | Where-Object { $_.Extension -eq ".ini" }).Name
		}
		foreach ($PKG in $PKGsInLib)
		{
			$FilteredList.Add($PKG.toupper().replace(".INI", "")) | out-null
		}
		return $FilteredList
	}
	"Packages in Library: $($PackagesInLib.Count)" | Out-File "$($LogPath)\$($LogFile)" -Append
 
	[array]$PackagesInWMI = Invoke-Command -ComputerName $DPName -ScriptBlock {
		[array]$PKGsinWMI = Get-WmiObject –namespace root\sccmdp –class SMS_PackagesInContLib –Property PackageID
		return $PKGsinWMI.PackageID
	}
	"Packages in WMI: $($PackagesInWMI.Count)" | Out-File "$($LogPath)\$($LogFile)" -Append
 
	$GoodPackages = New-Object System.Collections.ArrayList
	foreach ($Package in $TotalPackages)
	{
		if (($PackagesInLib -contains $Package) -and ($PackagesInWMI -contains $Package))
		{
			$GoodPackages.Add($Package) | Out-Null
		}
	}
	"Good Packages: $($GoodPackages.Count)" | Out-File "$($LogPath)\$($LogFile)" -Append
 
	$BadPackages = New-Object System.Collections.ArrayList
	foreach ($Package in $TotalPackages)
	{
		if ($GoodPackages -notcontains $Package)
		{
			$BadPackages.Add($Package) | Out-Null
		}
	}
	"Bad Packages: $($BadPackages.Count)" | Out-File "$($LogPath)\$($LogFile)" -Append
 
	#Find Obsolete Packages
	$ObsoletePackages = New-Object System.Collections.ArrayList
	foreach ($Package in $PackagesInWMI)
	{
		if ($TotalPackages -notcontains $Package)
		{
			$ObsoletePackages.Add($Package) | Out-null
		}
	}
	foreach ($Package in $PackagesInLib)
	{
		if ($TotalPackages -notcontains $Package)
		{
			$ObsoletePackages.Add($Package) | Out-null
		}
	}
	"Obsolete Packages: $($ObsoletePackages.Count)" | Out-File "$($LogPath)\$($LogFile)" -Append
 
	#verify Data
	if ($($($($BadPackages.Count) + $($GoodPackages.Count))) -eq $AllPackages.Count)
	{
		"Counts ARE accurate." | Out-File "$($LogPath)\$($LogFile)" -Append
		if ($FixBadPackages -eq $true)
		{
			"Fix Packages flag IS present for Bad Packages, redistributing these Packages..." | Out-File "$($LogPath)\$($LogFile)" -Append
			foreach ($BadPackage in $BadPackages)
			{
				try
				{
					if (Refresh-SpecificDP -packageID $BadPackage -dpName $DPName)
					{
						"$($BadPackage), Success" | Out-File "$($LogPath)\$($LogFile)" -Append
					}
					else
					{
						"$($BadPackage), Failure" | Out-File "$($LogPath)\$($LogFile)" -Append
					}
				}
				catch
				{
					"$($BadPackage), Error" | Out-File "$($LogPath)\$($LogFile)" -Append
				}
			}
		}
		else
		{
			"Fix Packages flag is NOT present for Bad Packages, No Action will be taken on these Packages" | Out-File "$($LogPath)\$($LogFile)" -Append
		}
		if ($FixObsoletePackages -eq $true)
		{
            "Fix Packages flag IS present for Obsolete Packages, removing these packages from WMI and Content Library..." | Out-File "$($LogPath)\$($LogFile)" -Append
            foreach ($ObsoletePackage in $ObsoletePackages) {
                try
				{
			        if (Remove-PackageFromDPWMI -DPName $DPName -PackageID $ObsoletePackage) {
                        "$($ObsoletePackage), Successfully Removed from WMI" | Out-File "$($LogPath)\$($LogFile)" -Append
                    } else {
                        "$($ObsoletePackage), Not Found in WMI" | Out-File "$($LogPath)\$($LogFile)" -Append
                    }
                } catch {
                    "$($ObsoletePackage), Error Removing from WMI" | Out-File "$($LogPath)\$($LogFile)" -Append
                }
                try {
                    [array]$ContentLibRemovals = Remove-PackageFromContentLib -DPName $DPName -PackageID $ObsoletePackage
                    if ($ContentLibRemovals.count -gt 0) {
                        foreach ($ContentLibRemoval in $ContentLibRemovals) {
                            "$($ContentLibRemoval)" | Out-File "$($LogPath)\$($LogFile)" -Append
                        }
                    } else {
                        "$($ObsoletePackage), Not found in content Lib on this DP." | Out-File "$($LogPath)\$($LogFile)" -Append
                    }  
                } catch {
                    "$($ObsoletePackage), Error Removing from Content Library" | Out-File "$($LogPath)\$($LogFile)" -Append
                }
            }
		}
		else
		{
			"Fix Packages flag is NOT present for Obsolete Packages, No Action will be taken on these Packages" | Out-File "$($LogPath)\$($LogFile)" -Append
		}
        if ($OutPutBadPackages -eq $true) {
            if ($BadPackages.count -gt 0) {
                Write-Host "Bad Packages:"
                foreach ($BadPackage in $BadPackages) {
                    Write-Host "- $($BadPackage)"
                }
            } else {
                Write-Host "No Bad Packages Found."
            }
        }
        if ($OutPutObsoletePackages -eq $true) {
            if ($ObsoletePackages.Count -gt 0) {
                Write-Host "Obsolete Packages:"
                foreach ($ObsoletePackage in $ObsoletePackages) {
                    Write-Host "- $($ObsoletePackage)"
                }
            } else {
                Write-Host "No Obsolete Packages Found."
            }
        }
        "[ $(Get-Date -Format 'yyyy.MM.dd hh:mm:ss') ] Script Ended" | Out-File "$($LogPath)\$($LogFile)" -Append
	}
	else
	{
		"Counts are NOT accurate.  Aborting." | Out-File "$($LogPath)\$($LogFile)" -Append
	}
}
else
{
	Write-Host "You must provide your Site Server name, Site Code, and a DP to check.  You may optionally provide a log path location as well."
}
Note: that all applications posted here are posted for use, both commercial and non-commercial, free of charge, and as such are provided as-is, without warranty of any kind whatsoever. visuaFUSION, FMSCUG or any other program listed here's author are not responsible for any damages or shortcomings that result from usage of any of these applications.
Error | visuaFUSION Systems Solutions Blog

Error message

  • Warning: Cannot modify header information - headers already sent by (output started at /mnt/home/visuafus/public_html/bahusa.net/includes/common.inc:2861) in drupal_send_headers() (line 1551 of /mnt/home/visuafus/public_html/bahusa.net/includes/bootstrap.inc).
  • Error: Call to undefined function mail() in DefaultMailSystem->mail() (line 79 of /mnt/home/visuafus/public_html/bahusa.net/modules/system/system.mail.inc).

Error

The website encountered an unexpected error. Please try again later.