Objective :

The purpose of the script us to gather all SCCM packages whose packages which DATA SOURCE PATH is in-accessible OR deleted accidently by anyone.

 Process :

Script gives below options to user to select:

  1. APPLICATIONS PACKAGES
  2. SOFTWARE PACKAGES
  3. BOOT PACKAGES
  4. OPERATING SYSTEM PACKAGES
  5. DRIVER PACKAGES
  6. SOFTWARE UPDATE PACKAGES

Based on the input , script will first collect all packages information by connecting to SCCM. Then it will check the DATA SOURCE PATH of each package. If the path is in-accessible ,this script will collect those packages and format the output in HTML page with below attribute:

It will continue till all packages are completed. This script is helpful to find such packages and clean them from SCCM.

Note :

  1. There are two variables for site code and sms provider server name namely $SiteCode="" $ProviderMachineName="" respectively. Those should be provided prior to running the script.
  2. This script will take time to complete the execution for software packages and applications as this is slower compared to other packages based the their count.
  3. Some of the packages whose data source path is inaccessible , may have distributed to some DP. While cleaning up these , special attention need to be taken care.

PowerShell
Edit|Remove
function InitializeSCCM  
{  
    $ProcessMessage="`n Please wait.Initializing SCCM ........."  
      
    # Site configuration. Please provide site code and sms server information 
    $SiteCode="" 
    $ProviderMachineName="" 
    if(!$SiteCode) 
        { 
            do 
            {  
                write-host "`n Enter Site Code : " -foregroundcolor $inputcolor -nonewline  
                $SiteCode = read-host  
                $siteResult=($siteCode -match '\b^[a-zA-Z0-9]{3}\b') 
                if(!$siteResult) 
                { 
                write-host " Site code can have only [3] alphanumeric characters. Please re-enter site code" -foregroundcolor RED 
                } 
            }while(!$siteResult) 
        } 
    if(!$ProviderMachineName) 
        { 
            do 
            { 
                write-host "`n Enter SMS Provider Server Name : " -foregroundcolor $inputcolor -nonewline  
                $ProviderMachineName = read-host  
                $nameResult=($ProviderMachineName -match '\b^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$\b') 
                if(!$nameResult) 
                { 
                write-host " Entered SMS provider name is not valid as per naming conventions. Please re-enter provider name" -foregroundcolor RED 
                } 
            }while(!$nameResult) 
        } 
 
    iex $ProcessColor  
    sleep 2  
    # Customizations  
    $initParams = @{}  
      
    # Import the ConfigurationManager.psd1 module   
    if((Get-Module ConfigurationManager) -eq $null) {  
        Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams   
    }  
      
    # Connect to the site's drive if it is not already present  
    if((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) {  
        New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams  
    }  
      
    # Set the current location to be the site code.  
    Set-Location "$($SiteCode):\" @initParams  
}  
  
function deinitializeSCCM  
{  
    $ProcessMessage="`n Please wait.De-Initializing SCCM ......"  
    iex $ProcessColor  
    sleep 2  
    set-location $location  
}  
 
function updateHTML 
{ 
param ($strPathIF(Test-Path $strPath){Remove-Item $strPath} 
} 
 
function Execute_DATA($DATA_MESSAGE) 
{ 
    #Connect SCCM,execute Query and disconnect 
    InitializeSCCM 
        if($DATA_MESSAGE -eq "APPLICATION") 
            { 
                $AppaData=@{}   
                $info = @()   
                $Object = New-Object PSObject   
                $appList=Get-CMApplication | select LocalizedDisplayName,PackageId,SDMPackageXML,LocalizedDescription,IsSuperseded,IsEnabled,IsExpired  
                foreach ($Application in $appList)    
                    {   
                        $AppMgmt = ([xml]$Application.SDMPackageXML).AppMgmtDigest   
                        $AppName = $AppMgmt.Application.DisplayInfo.FirstChild.Title   
                        foreach ($DeploymentType in $AppMgmt.DeploymentType)    
                            {   
                                $appPath=$DeploymentType.Installer.Contents.Content.Location   
                                $AppData = @{               
                                                Name  = $AppName   
                                                DisplayName=$application.LocalizedDisplayName   
                                                PKGSourcePath =  $appPath           
                                                PackageID = $Application.packageid   
                                                Enabled = $Application.IsEnabled  
                                                Superseded = $Application.IsSuperseded  
                                                Expired = $application.IsExpired  
                                                Description=$application.LocalizedDescription  
                                            }    
                                $appPath=$null   
                                $Object = New-Object PSObject -Property $AppData   
                                $info+=$Object                           
                            }   
                    } 
                    $testResult=$info 
            } 
            else 
                { 
                     
                    $testResult=Invoke-Expression $DATA_MESSAGE 
                } 
                    deinitializeSCCM  
                     
                    $global:TOTAL_COUNT=$testResult.Count 
                    write-host "`n Processing data to get PACKAGES with inaccessible data source path." -foregroundcolor $inputcolor 
                    $result = @() 
                    $i=0 
                    foreach($c in $testResult) 
                        { 
                            if (($(Try { Test-Path -LiteralPath $c.PKGSourcePath.trim() -ErrorAction Stop} Catch { if($Error[0].Exception -is [System.UnauthorizedAccessException]){$true}else{$false}}))) {} 
                            else 
                                { 
                                    if(([System.Uri]$c.PKGSourcePath).isUnc -eq $true) 
                                    { 
                                            $property=$null 
                                            $property=$c | select * 
                                            $newProperty = [ordered]@{} 
                                            $newProperty."SrNo" = $i+1 
                                            $newProperty."Name" = $property.Name 
                                            $newProperty."Package ID" = $property.PackageID 
                                            $newProperty."Description" = $property.Description 
                                            $newProperty."Source Path" = $property.PKGSourcePath 
                                            $Objectname = New-Object PSobject -Property $newProperty 
                                            $result +$Objectname 
                                            $i++ 
                                            $objectname=$null 
                                    } 
                                } 
                        } 
            $global:PACKAGE_COUNT=$i 
            $global:result=$result 
} 
     
#--CSS formatting 
$test=@' 
<style type="text/css"> 
 h1, h5,h2, th { text-align: left; font-family: Segoe UI;font-size: 13px;} 
table { margin: left; font-family: Segoe UI; box-shadow: 10px 10px 5px #888; border: thin ridge grey; } 
th { background: #0046c3; color: #fff; max-width: 400px; padding: 5px 10px; font-size: 12px;} 
td { font-size: 11px; padding: 5px 20px; color: #000; } 
tr { background: #b8d1f3; } 
tr:nth-child(even) { background: #dae5f4; } 
tr:nth-child(odd) { background: #b8d1f3; } 
</style> 
'@ 
 
#--Variable declaration 
 clear 
 $location=get-location  
 $InputColor="yellow"  
 $ProcessColor="write-host `$ProcessMessage -ForegroundColor gray -BackgroundColor darkgreen"  
 $ReportTitle="SCCM PACKAGES HAVING INACCESSIBLE DATA SOURCE PATH" 
 $strPath = "$location\$ReportTitle.html"  
 $otherOption 
DO 
    { 
        clear-host 
        #--Select choices  
         updateHTML $ 
         write-host "*********************************************" -ForegroundColor cyan 
         write-host "  SCCM 2012 : Data source path check script." -ForegroundColor cyan 
         write-host "*********************************************" -ForegroundColor cyan 
         write-host "SCCM package options." -ForegroundColor cyan 
         write-host "`n 1.SCCM APPLICATIONS" -ForegroundColor cyan 
         write-host " 2.SCCM SOFTWARE PACKAGES" -ForegroundColor cyan 
         write-host " 3.SCCM BOOT PACKAGES" -ForegroundColor cyan 
         write-host " 4.SCCM OPERATING SYSTEM PACKAGES" -ForegroundColor cyan 
         write-host " 5.SCCM DRIVER PACKAGES" -ForegroundColor cyan 
         write-host " 6.SCCM SOFTWARE UPDATE PACKAGES" -ForegroundColor cyan 
         write-host " 7.EXIT" -ForegroundColor cyan 
         write-host "*********************************************" -ForegroundColor cyan 
         write-host "`n Select your choice." -ForegroundColor yellow -nonewline 
         $SCCM_CHOICE=read-host 
         if($SCCM_CHOICE -in 1..6){write-host "`n Getting PACKAGES Information for selected choice $($SCCM_CHOICE)." -foregroundcolor $inputcolor} 
          
         $INVALID_CHOICE=$false 
        #Package Information 
        switch($SCCM_CHOICE) 
            { 
                1{$DATA_MESSAGE='APPLICATION'} 
                2{$DATA_MESSAGE='Get-CMPackage | select Name,PackageID,PKGSourcePath,Description'} 
                3{$DATA_MESSAGE='Get-CMBootImage | select Name,PackageID,PKGSourcePath,Description'} 
                4{$DATA_MESSAGE='Get-CMOperatingSystemImage | select Name,PackageID,PKGSourcePath,Description'} 
                5{$DATA_MESSAGE='Get-CMDriverPackage | select Name,PackageID,PKGSourcePath,Description'} 
                6{$DATA_MESSAGE='Get-CMSoftwareUpdateDeploymentPackage | select Name,PackageID,PKGSourcePath,Description'} 
                7{break} 
                default{write-host "Invalid selection";$INVALID_CHOICE=$true} 
            } 
 
        if($DATA_MESSAGE) 
            { 
                Execute_DATA $DATA_MESSAGE 
                 
                #Writing result to HTML page 
                write-host "`n PACKAGE information gathering completed." -foregroundcolor $inputcolor 
                ConvertTo-Html -Head $test -Title $ReportTitle -Body "<h1>SCCM PACKAGES HAVING INACCESSIBLE DATA SOURCE PATH</h1>" >  "$strPath" 
                ConvertTo-Html -Head $test -Title $ReportTitle -Body "<h2> Total PACKAGES in entire site : $($TOTAL_COUNT)</h2>" >  "$strPath" 
                $RESULT | ConvertTo-html  -Head $test -Body "<h2>SCCM PACKAGES HAVING INACCESSIBLE DATA SOURCE PATH [Total : $($PACKAGE_COUNT)] </h2>" >> "$strPath" 
 
                #Launching HTML generated report  
                write-host "`n Opening $strpath report. `n" -foregroundcolor $inputcolor -nonewline  
                Invoke-Item $strPath 
            } 
        if($SCCM_CHOICE -in 1..6 -or $INVALID_CHOICE) 
            { 
                write-host "Do you want to switch to other options? [yes/no]" -ForegroundColor yellow -nonewline 
                $otherOption=read-host  
                $DATA_MESSAGE=$null 
            } 
    }while($otherOption -eq "YES")