Sunday, July 31, 2016

PowerShell: Manipulate Workstation Software Information via SCCM

During the computer replacement cycle, a typical chore is retrieving the software list from the old computer and ensuring its replacement computer gets said software.  If SCCM packages are involved, there are two sources to check during this process: The local repository and the SCCM assigned repositories.

To help with this process, as well as other similar software management functions, I created a script which collects the existing computers SCCM packages and transfers them to the new computer, views SCCM's list of local software, removes a SCCM package from a computer, edit/update the SCCM list table, and change computer numbers so you can look at another computer without leaving the script.

Now, this script, just like my others, are works in progress.  As such, they might have errors in your environment.  I wanted to share what I have in case it might help others with their daily duties.  Please let me know if you have improvements.

$tagnumber = read-host "Enter Computer Tag"
$computername = $tagnumber.toupper()
$SCCMserver = "DomainSCCMServer01"
$namespace = "root\sms\site_xx1"
$Server = "DomainGCServer01"
$i = 0

#pulling in existing administrative credentials for $admcred variable
if (test-path \\server\share\it_tools\1p.eee){
$name = "domain\admin01"
$password = get-content \\server\share\it_tools\1p.eee|convertto-securestring -key (1..16)
$admcred = new-object system.management.automation.pscredential($name,$password)
}

#Testing if the admin password has expired
$ServerTest = new-psdrive -name test -root \\DomainSCCMServer01\client -credential $admcred -psprovider FileSystem
#Testing if 1p.eee password file exists
$PWTest = test-path \\server\share\it_tools\1p.eee

#if either of the above commands fail, the admin gets prompted to update/add their admin credential
if (($PWTest -ne $true) -or ($ServerTest.name -ne "test")){
$admcred = get-credential -username "domain\adm_youraccount" -message "Update your ADM Password"
$password = $admcred.password|convertfrom-securestring -key (1..16)
$password|out-file \\server\share\it_tools\1p.eee
$password = gc \\server\share\it_tools\1p.eee|convertto-securestring -key (1..16)
$admcred = new-object system.management.automation.pscredential($name,$password)
}
remove-psdrive test


#SCCM
#Getting list of current software collections
#and then filtering out unneeded collections
if (test-connection $SCCMServer){
$xlist = import-csv \\server\share\it_tools\offlist.csv
$CollectionList = gwmi -query "Select * from SMS_Collection" -namespace $namespace -computername $SCCMserver -credential $admcred
$CollectionList = $CollectionList|? {$xlist.name -notcontains $_.name}
foreach ($C in $CollectionList){$i++;$C|add-member -notepropertyname line -notepropertyvalue $i}
}

do{
#SCCM Collection Query
$CurrentApps = Get-WmiObject -Namespace $namespace -Class SMS_fullcollectionmembership -ComputerName $SCCMServer -filter "Name = '$computername'" -credential $admcred

#Applying current computer software list to complete software list
$InstalledSoftwareList = $CollectionList|? {$CurrentApps.collectionID -contains $_.collectionID}

#Querying SCCM for main user of selected computer
$users = gwmi -computername $sccmserver -namespace $namespace -class sms_usermachinerelationship -filter "resourcename = '$computername'"
$userlist = $users|% {get-aduser $_.uniqueusername.split('\')[1]|select givenname,surname,name}

write-host "Available SCCM Software Packages" -f white
$collectionlist|? {$InstalledSoftwareList.name -notcontains $_.name}|format-table line,name -autosize -hidetableheaders
write-host ("Current SCCM Packages for " + $computername + ":") -f white
$InstalledSoftwareList|format-table line,name -hidetableheaders -autosize

#Adds the following if a software from the collection has been added to the install list
if ($newsoftware){
write-host "Software to be added" -f yellow
$newsoftware|format-table line,name -hidetableheaders -autosize
}

#Shows users of selected computer
write-host "User Profiles on $computername" -f white
$userlist|format-table -autosize -hidetableheaders

#Menu
write-host "Enter " -nonewline;write-host "line number" -f white -nonewline;write-host " to add SCCM software to $computername"
write-host "Enter " -nonewline;write-host "LOCAL" -f white -nonewline;write-host " to view local software on $computername"
write-host "Enter " -nonewline;write-host "REMOVE" -f white -nonewline;write-host " to remove SCCM software from $computername"
write-host "Enter " -nonewline;write-host "EDIT" -f white -nonewline;write-host " to update your SCCM Package Filter"
write-host "Enter " -nonewline;write-host "TRANSFER" -f white -nonewline;write-host " to add $computername software to another computer"
write-host "Enter " -nonewline;write-host "CHANGE" -f white -nonewline;write-host " to change computer"
if ($transfername){
write-host ($transfername + " SCCM App List:")
$installedapps.name}

write-host "Enter " -nonewline;write-host "DONE" -f white -nonewline;write-host " to add software and finish script"
$addpackages = read-host "(Line number, Local, Remove, Edit, Transfer, Change, or Done)"

## CHANGE ##
if ($addpackages -eq "change"){
$tagnumber = read-host "Enter Computer Tag"
$computername = $tagnumber.toupper()
}

## LOCAL ##
if ($addpackages -eq "local"){
$i = 0
$localxlist = import-csv \\server\share\it_tools\offlocalsoftwarelist.csv
$oldcomputerlocalsoftware = gwmi -computername $sccmserver -namespace $namespace -Query ("select InstalledLocation, ProductVersion, ProductName from SMS_R_System join SMS_G_SYSTEM_Installed_Software on SMS_R_System.ResourceID = SMS_G_SYSTEM_Installed_Software.ResourceID where SMS_R_SYSTEM.Name= ""$($computername)"" ") -credential $admcred
$oldcomputerlocalsoftware = $oldcomputerlocalsoftware|? {$localxlist.productname -notcontains $_.productname -and $localxlist.productversion -notcontains $_.productversion}
foreach ($C in $oldcomputerlocalsoftware){$i++;$C|add-member -notepropertyname line -notepropertyvalue $i}

do{
#local software menu.  It also has a filter to exclude unwanted software from its list
write-host "`nLocal software found on $SCCMOldComputer"
$oldcomputerlocalsoftware|format-table line,productname,productversion -hidetableheaders -autosize
if ($removesoftware){write-host "Will be added to local filter list:" -f green}
if ($removesoftware){$removesoftware|format-table -hidetableheaders -autosize}
write-host "Enter " -nonewline;write-host "line number" -f white -nonewline;write-host " to update local software exclusion filter"
write-host "Enter " -nonewline;write-host "Return" -f white -nonewline;write-host " if list is correct"
$addtolxlist = read-host "(Line number or Return)"
if ($addtolxlist -ne "return"){
[array]$removesoftware += $oldcomputerlocalsoftware|? line -eq $addtolxlist|select productname,productversion
$oldcomputerlocalsoftware = $oldcomputerlocalsoftware|? {$removesoftware.productname -notcontains $_.productname -and $removesoftware.productversion -notcontains $_.productversion}
}
} while ($addtolxlist -ne "return")
if ($removesoftware){
$localxlist = $localxlist|select ProductName,ProductVersion
$localxlist += $removesoftware|select ProductName,ProductVersion
$localxlist|export-csv \\server\share\it_tools\offlocalsoftwarelist.csv
$removesoftware = $nul
}

}

## REMOVE ##
if ($addpackages -eq "remove"){

do{
#cls
write-host "SCCM Software already installed on $computername" -f white
$InstalledSoftwareList|format-table line,name -hidetableheaders

if ($removesoftware){
write-host "Software to be removed" -f yellow
$removesoftware|format-table line,name -hidetableheaders
}

write-host "Enter " -nonewline;write-host "line number" -f white -nonewline;write-host " to remove SCCM software from $computername"
write-host "Enter " -nonewline;write-host "REMOVE" -f white -nonewline;write-host " if satisfied with removal list"
$removepackages = read-host "(Line number or Remove)"

if ($removepackages -ne "remove"){
[array]$removesoftware += $collectionlist|? line -eq $removepackages
}

} while ($removepackages -ne "Remove")

if ($removesoftware){
foreach ($r in $removesoftware){
$ID = $r.collectionID
$Collection = gwmi -class SMS_Collection -namespace $namespace -computername $SCCMserver -credential $admcred|? CollectionID -eq $ID
$ruleclass = gwmi -namespace $namespace -class "SMS_CollectionRuleDirect" -computername $SCCMserver -list -credential $admcred
$RemoveComputer = gwmi -ComputerName $SCCMServer -Namespace $Namespace -Class "SMS_R_System" -Filter "Name = '$($computername)'" -credential $admcred
$DelRule = $RuleClass.CreateInstance()     
$DelRule.RuleName = $($RemoveComputer.name)
$DelRule.ResourceClassName = "SMS_R_System" 
$DelRule.ResourceID = $($RemoveComputer.resourceid)
$Collection.DeleteMemberShipRule($DelRule)
$Collection.requestrefresh()
}
}

## EDIT ##
if ($addpackages -eq "edit"){
do{
write-host "Current SCCM Package Filter" -f white
$CollectionList|format-table line,name -hidetableheaders -autosize
if ($updatexlist){write-host "Will be added to filter:" -f green}
if ($updatexlist){$updatexlist|format-table -hidetableheaders -autosize}
write-host "Enter " -nonewline;write-host "line number" -f white -nonewline;write-host " to remove from list"
write-host "Enter " -nonewline;write-host "Update" -f white -nonewline;write-host " to execute filter update"
$addtoxlist = read-host "(Line number or Update)"
if ($addtoxlist -ne "update"){
[array]$remove += $CollectionList|? line -eq $addtoxlist|select name,collectionID
[array]$UpdateXList = $CollectionList|? line -eq $addtoxlist|select line,name
}
} while ($addtoxlist -ne "update")
#saving updated collectionlist

if ($remove){
$xlist = $xlist|select Name,CollectionID
$xlist += $remove|select Name,CollectionID
$xlist = $xlist|sort CollectionID -unique
$xlist|export-csv \\server\share\it_tools\offlist.csv
write-host "Filter updated" -f green}
}
}

## TRANSFER ##
if ($addpackages -eq "transfer"){
$transfercomputer = read-host "Transfer to Tag Number"
$transfername = $transfercomputer.toupper()
foreach ($c in $InstalledSoftwareList){
$ID = $c.collectionID
$Collection = gwmi -class SMS_Collection -namespace $namespace -computername $SCCMserver -credential $admcred|? CollectionID -eq $ID
$ruleclass = gwmi -namespace $namespace -class "SMS_CollectionRuleDirect" -computername $SCCMserver -list -credential $admcred
$AddComputer = gwmi -ComputerName $SCCMServer -Namespace $Namespace -Class "SMS_R_System" -Filter "Name = '$($transfername)'" -credential $admcred
$NewRule = $RuleClass.CreateInstance()     
$NewRule.RuleName = $($AddComputer.name)
$NewRule.ResourceClassName = "SMS_R_System" 
$NewRule.ResourceID = $($AddComputer.resourceid)
$Collection.AddMembershipRules($newrule)
$Collection.requestrefresh()
}
$CheckApps = Get-WmiObject -Namespace $namespace -Class SMS_fullcollectionmembership -ComputerName $SCCMServer -filter "Name = '$transfername'" -credential $admcred
$InstalledApps = $CollectionList|? {$CheckApps.collectionID -contains $_.collectionID}
}

if (($addpackages -ne "done") -and ($addpackages -ne "edit") -and ($addpackages -ne "transfer")){
[array]$newsoftware += $collectionlist|? line -eq $addpackages
}
} until ($addpackages -eq "done")


#Added packages will get processed after DONE has been entered
if ($newsoftware){
foreach ($c in $newsoftware){
$ID = $c.collectionID
$Collection = gwmi -class SMS_Collection -namespace $namespace -computername $SCCMserver -credential $admcred|? CollectionID -eq $ID
$ruleclass = gwmi -namespace $namespace -class "SMS_CollectionRuleDirect" -computername $SCCMserver -list -credential $admcred
$AddComputer = gwmi -ComputerName $SCCMServer -Namespace $Namespace -Class "SMS_R_System" -Filter "Name = '$($computername)'" -credential $admcred
$NewRule = $RuleClass.CreateInstance()     
$NewRule.RuleName = $($AddComputer.name)
$NewRule.ResourceClassName = "SMS_R_System" 
$NewRule.ResourceID = $($AddComputer.resourceid)
$Collection.AddMembershipRules($newrule)
$Collection.requestrefresh()
$CheckApps = Get-WmiObject -Namespace $namespace -Class SMS_fullcollectionmembership -ComputerName $SCCMServer -filter "Name = '$computername'" -credential $admcred
$InstalledApps = $CollectionList|? {$CheckApps.collectionID -contains $_.collectionID}
$AddedApps = $Installedapps|? {$InstalledSoftwareList.collectionID -notcontains $_.collectionID}
[array]$apps = $Addedapps.name
write-host ("This software has been added to $Computername successfully: ")
($Installedapps|? {$InstalledSoftwareList.collectionID -notcontains $_.collectionID}).name
}
}