Skip to content

Instantly share code, notes, and snippets.

@kmhuglen
Created September 14, 2016 13:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kmhuglen/e32d480fd718376bce25b3a2a113be3b to your computer and use it in GitHub Desktop.
Save kmhuglen/e32d480fd718376bce25b3a2a113be3b to your computer and use it in GitHub Desktop.
#Requires -version 2.0
# ***************************************************************************
#
# File: CheckTSPrompt.ps1
#
# Version: 1.3.1 (modified gui)
#
# Author: Jason Scheffelmaer
#
#
# Purpose: Checks selected task sequences to ensure that all packages they
# reference are available on selected distribution points.
#
# This requires PowerShell 2.0 and at least version 1.5
# of SCCM.psm1.
#
# Usage: Run this script. No parameters are required.
# You will be prompted for ConfigMgr Server to connect to,
# Task Sequence to check, and Distribution Point to replicate
# to. You will also be prompted to replicate or not and the end.
#
# $dpExcludeList is a variable to hold all the distribution point
# servers that you wish to exclude from the list or replication.
#
# Version Change:
#
# 1.2: Workaround Issue for New-SCCMPackageDP now calling New-SCCMPackageDP_Custom
# 1.3: Now includes version 1.5 of SCCM.psm1 which has the correct fix in for
# New-SCCMPackageDP to include sitecode. Removed New-SCCMPackageDP_Custom.
#
#
# ------------- DISCLAIMER -------------------------------------------------
# This script code is provided as is with no guarantee or waranty concerning
# the usability or impact on systems and may be used, distributed, and
# modified in any way provided the parties agree and acknowledge the
# Microsoft or Microsoft Partners have neither accountabilty or
# responsibility for results produced by use of this script.
#
# Microsoft will not provide any support through any means.
# ------------- DISCLAIMER -------------------------------------------------
#
# ***************************************************************************
# DP Exclude List so they do not show up in the list
$dpExcludeList = "MYServer01", "MyServer02"
# ----------
# Functions
# ----------
# The CheckPackages function checks each task sequence, finding all the packages
# that it references. It then checks each appropriate DP to make sure that the
# needed packages are available on on those DPs.
function CheckPackages
{
process
{
# Get the list of packages referenced by this task sequence
$tsID = $_.PackageID
Write-Host "Getting a list of packages referenced by Task Sequence $tsID"
$tsReferences = Get-SCCMObject SMS_TaskSequenceReferencesInfo "PackageID='$tsID' and ProgramName='*'"
# Check each package
Write-Host "Checking all packages..."
foreach ($tsPackage in $tsReferences)
{
# Get a list of DPs for this package
$tsPackageID = $tsPackage.ReferencePackageID
#write-host "Checking Package: $tspackageID"
$tsReferenceDPs = Get-SCCMObject SMS_TaskSequenceReferenceDPs "TaskSequenceID='$tsID' and PackageID='$tsPackageID'"
# Check each DP to see if the package is on it
foreach ($dp in $global:SelecteddpList)
{
$dpSiteCode = $dp.SiteCode
$found = $false
foreach ($tsDP in $tsReferenceDPs)
{
if ($tsDP.ServerNALPath -eq $dp.NALPath)
{
#Write-Host "Found package"
$found = $true
break
}
}
if ($found)
{
New-Object PSObject -Property @{SiteCode=$dpSiteCode; PackageID=($tsPackageID); ServerName=($dp.ServerName); ShareName=($dp.ShareName); NALPath=($dp.NALPath); Result="Found"}
}
else
{
# Check to see if this DP is a PXE Service Point, and if so mark as Not Needed.
if ($tsPackage.ReferencePackageType -eq 258 -or (-not $dp.NALPath.Contains("SMSPXEIMAGES$")))
{
Write-Host " $tsPackageID - Package Not Found"
New-Object PSObject -Property @{SiteCode=$dpSiteCode; PackageID=($tsPackageID); ServerName=($dp.ServerName); ShareName=($dp.ShareName); NALPath=($dp.NALPath); Result="Not Found"}
}
else
{
New-Object PSObject -Property @{SiteCode=$dpSiteCode; PackageID=($tsPackageID); ServerName=($dp.ServerName); ShareName=($dp.ShareName); NALPath=($dp.NALPath); Result="Not Needed"}
}
}
}
}
}
}
# The InputTask function prompts for a task sequence PackageID, using an input box.
function InputPrompt
{
[CmdletBinding()]
PARAM
(
[Parameter(Position=1)] $objectText,
[Parameter(Position=2)] $TitleText,
[Parameter(Position=3)] $PromptType
)
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
# New Form
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = $TitleText
$objForm.Size = New-Object System.Drawing.Size(500,405)
$objForm.StartPosition = "CenterScreen"
# Monitor KeyPress Events
$objForm.KeyPreview = $True
$objForm.Add_KeyDown({
if ($_.KeyCode -eq "Enter")
{
If ($checkbox.checked -eq $true)
{$x='All';$objForm.Close()}
Else
{
If ($PromptType -eq 'TS')
{$x=$objListBox.SelectedItem;$objForm.Close()}
ElseIf ($PromptType -eq 'DP')
{$x=$objListBox.SelectedItem;$objForm.Close()}
ElseIf ($PromptType -eq 'Summary')
{$x='Yes';$objForm.Close()}
Else
{$x=$objTextBox.text;$objForm.Close()}
}
}})
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape")
{$x='Cancel';$objForm.Close()}})
# Create OK Button
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(310,10)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Add_Click(
{
If ($checkbox.checked -eq $true)
{$x='All';$objForm.Close()}
Else
{
If ($PromptType -eq 'TS')
{$x=$objListBox.SelectedItem;$objForm.Close()}
ElseIf ($PromptType -eq 'DP')
{$x=$objListBox.SelectedItem;$objForm.Close()}
ElseIf ($PromptType -eq 'Summary')
{$x='Yes';$objForm.Close()}
Else
{$x=$objTextBox.text;$objForm.Close()}
}
}
)
$objForm.Controls.Add($OKButton)
# Create Cancel Button
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(400,10)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.Add_Click({$x='Cancel';$objForm.Close()})
$objForm.Controls.Add($CancelButton)
# Create Label
$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(10,14)
$objLabel.Size = New-Object System.Drawing.Size(160,27)
$objLabel.Text = $TitleText
$objForm.Controls.Add($objLabel)
# Create Texbox
$objTextBox = New-Object System.Windows.Forms.TextBox
$objTextBox.Location = New-Object System.Drawing.Size(170,12)
$objTextBox.Size = New-Object System.Drawing.Size(100,20)
# Create ListBox
$objListBox = New-Object System.Windows.Forms.ListBox
$objListBox.Location = New-Object System.Drawing.Size(10,41)
$objListBox.Size = New-Object System.Drawing.Size(465,100)
$objListBox.Height = 320
# Create Checbkox
$checkbox = New-Object System.Windows.Forms.CheckBox
$checkbox.Location = New-Object System.Drawing.Size(170,1)
$checkbox.Size = New-Object System.Drawing.Size(150,40)
$checkbox.Add_Click({if ($checkbox.Checked -eq $true){$objListBox.enabled = $false}
else {$objListBox.enabled = $true}})
# Add DataGrid View
$dgDataGrid = new-object System.windows.forms.DataGrid
$dgDataGrid.AllowSorting = $True
$dgDataGrid.Location = new-object System.Drawing.Size(10,45)
$dgDataGrid.size = new-object System.Drawing.Size(470,300)
# Check to see if it is a TS or DP or ServerName Prompt
If ($PromptType -eq 'TS')
{
$OKButton.Text = "OK"
$checkbox.text = 'All Task Sequences'
$objForm.Controls.Add($checkbox)
# Fill Listbox
$objectText | ForEach-Object {[void] $objListBox.Items.Add($_.Name)}
$objForm.Controls.Add($objListBox)
}
ElseIf ($PromptType -eq 'DP')
{
$OKButton.Text = "OK"
$checkbox.text = 'All Distribution Points'
$objForm.Controls.Add($checkbox)
# Fill Listbox
$objectText | ForEach-Object {[void] $objListBox.Items.Add($_.Name)}
$objForm.Controls.Add($objListBox)
}
ElseIf ($PromptType -eq 'Summary')
{
$OKButton.Text = "Yes"
$objForm.Controls.Add($dgDataGrid)
$dgDataGrid.DataSource = $Global:logTable
}
Else
{
# Assume Textbox Prompt
$objForm.Controls.Add($objTextBox)
$OKButton.Text = "Connect"
}
$objForm.Topmost = $True
$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
return $x
}
# ----------
# Main logic
# ----------
# Prompt for ConfigMgr Server Name
$ConfigMgr_Server = InputPrompt -TitleText "Enter ConfigMgr Server Name"
If ($ConfigMgr_Server -eq 'Cancel'){Exit}
$scriptStartDate = Get-Date
Write-Host "Script Started at: $scriptStartDate"
# Connect to ConfigMgr
Import-Module SCCM -force
Write-Host "Connecting to CongfigMgr Server $ConfigMgr_Server"
New-SCCMConnection -serverName $ConfigMgr_Server
# Get the list of all DPs to choose from via a menu
Write-Host "Getting a list of all Distribution Points to select from"
$global:dpList = Get-SCCMObject SMS_DistributionPointInfo | where {$dpExcludeList -notcontains $_.ServerName}
# Get the list of all task sequences to choose from via a menu
Write-Host "Getting a list of all Task Sequences to select from"
$TaskSequences = get-SCCMTaskSequencePackage | select-object Name, PackageID | Sort-Object Name
# Prompt for Task Sequence to use when checking packages
$taskSequenceName = InputPrompt -objectText $TaskSequences -TitleText "Select Task Sequence" -PromptType 'TS'
If ($taskSequenceName -eq 'Cancel' -or $taskSequenceName -eq $null)
{
Write-Host "No Task Sequence selected or user selected Cancel, exiting script..."
Exit
}
ElseIf ($taskSequenceName -eq 'All')
{
$SelectedTS = $TaskSequences
}
Else
{
$SelectedTS = $TaskSequences | ? {$_.Name -eq $taskSequenceName}
$SelectedTSID = $SelectedTS.PackageID
}
# Prompt for Distribution Point to check the referenced packages against
$DPNameList = ($global:dpList| Select-Object @{Name="Name"; Expression={$_.ServerName}}, NalPath, SiteCode, SiteName) | Sort-Object Name
$global:DPName = InputPrompt -objectText ($DPNameList | Select-Object Name | Get-Unique -AsString) -TitleText "Select Distribution Point" -PromptType 'DP'
If ($global:DPName -eq 'Cancel' -or $global:DPName -eq $null)
{
Write-Host "No Distribution Point selected or user selected Cancel, exiting script..."
Exit
}
ElseIf ($global:DPName -eq 'All')
{
$global:SelecteddpList = $DPNameList
}
Else
{
$global:SelecteddpList = $DPNameList | ? {$_.Name -eq $global:DPName}
}
# Get the package status for all packages referenced
# by the task sequence selected.
Write-Host "Calling the CheckPackages function"
If ($taskSequenceName -eq 'All')
{
$packageResults = Get-SCCMTaskSequencePackage | CheckPackages
}
Else
{
$packageResults = Get-SCCMTaskSequencePackage -filter "PackageID='$SelectedTSID'"| CheckPackages
}
# Get a list of packages that need to be distributed to DP
$neededPackages = $packageResults | ? {$_.Result -eq 'Not Found'}
# $neededPackages | Format-Table
# If any packages are missing from DPs, add them to those DPs
if ($neededPackages -ne $null)
{
# Fill Missing Packages Tables
$Global:logTable = New-Object System.Data.DataTable
$Global:logTable.TableName = "Missing Packages"
$Global:logTable.Columns.Add("Package");
$Global:logTable.Columns.Add("Status");
$Global:logTable.Columns.Add("NALPath");
$Global:logTable.Columns.Add("SiteCode");
Foreach ($missingPackage in $neededPackages)
{
$Global:logTable.Rows.Add($missingPackage.PackageID,$missingPackage.Result,$missingPackage.NALPath, $missingPackage.SiteCode)
}
$replicate = InputPrompt -TitleText "Found Missing Packages, Replicate?" -PromptType 'Summary'
If ($replicate -eq 'Yes')
{
Write-Host "Distribuing packages to distribution point"
$newDPs = $neededPackages | New-SCCMPackageDP
$newCount = ($newDPs | Measure-Object).Count
Write-Host "$newCount package(s) distributed to distribution point."
}
Else
{
Write-Host "Cancel Selected, will not replicate packages"
}
}
else
{
Write-Host "No packages needed to be distributed."
}
$scriptEndDate = Get-Date
Write-Host "Script finished at: $scriptEndDate"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment