Tuesday, February 26, 2019

Remediation of old versions of Visual Studio Isolated Shell

Premier Support for Developers is used in all manner of ways to support your organization's needs. Sometimes we work with IT organizations to help in updating or removing older, out of support versions of our software from production across entire enterprise landscapes. At times this means working with hundreds of thousands of computers.

In some cases it can be a challenge to identify what software is installed and present on machines across customer networks. Today we have one specific example, Visual Studio Isolated Shell. If you're wondering what VS Isolated Shell is, take a quick read through this primer.

Why are old versions of VS Isolated Shell a challenge to upgrade/remove? VS Isolated Shell is just a component of a product, used by Microsoft and other third party vendors, to write software. That being said, if you are like many enterprise customers, you might not have a firm grasp of what products are leveraging this component. 

For Microsoft products the answer is easy, we use VS Shell with SQL Server Management Studio, Visual Studio, just to name a few products. But there are an untold number of vendors that could also be using VS Isolated Shell.


How do you identify what software dependent on Visual Studio Isolated Shell?

At first, it was a challenge to identify consistent methods for identifying dependency on VS Isolated Shell. Some applications will register in the registry, their dependence of VS Isolated Shell. But this is not reliably done by third party vendors as it is not a required step for installation.

After research with our product engineering teams we realized a simple way of identifying what software is dependent on Visual Studio Isolated Shell. During the course of operation, an executable that is dependent on VS Isolated Shell will have a .pkgdef file alongside the executable.

So let's say you have MyCustomApplication.exe, if this application is dependent on VS Isolated Shell there will be a MyCustomApplication.pkgdef file alongside the executable.

With this little tidbit of information, we were able to write a powershell script that iterates through a given folder recursively and identifies executables that are dependent on VS Isolated Shell.

Armed with a list of software that may be outdated or out of support, enterprise customers can more easily identify what software needs to be upgraded or removed based on older versions of VS Isolated Shell.


param ([string]$startDir = ".\", [string]$logFile = ".\pkgdef_match.log", $fileSize=1mb)
function Write-Log
{
param([string]$content)
$formattedContent = "[" + [System.DateTime]::UtcNow.ToString() + "] " + $content
Write-Output $formattedContent
[System.IO.File]::AppendAllText($logfile, $formattedContent + [System.Environment]::NewLine)
}
function Reset-Log
{
#function checks to see if file in question is larger than the paramater specified if it is it will roll a log and delete the oldes log if there are more than x logs.
param([string]$fileName, [int64]$filesize = 1mb , [int] $logcount = 5)
$logRollStatus = $true
if(test-path $filename)
{
$file = Get-ChildItem $filename
if((($file).length) -ige $filesize) #this starts the log roll
{
$fileDir = $file.Directory
$fn = $file.name #this gets the name of the file we started with
$files = Get-ChildItem $filedir | ?{$_.name -like "$fn*"} | Sort-Object lastwritetime
$filefullname = $file.fullname #this gets the fullname of the file we started with
#$logcount +=1 #add one to the count as the base file is one more than the count
for ($i = ($files.count); $i -gt 0; $i--)
{
#[int]$fileNumber = ($f).name.Trim($file.name) #gets the current number of the file we are on
$files = Get-ChildItem $filedir | ?{$_.name -like "$fn*"} | Sort-Object lastwritetime
$operatingFile = $files | ?{($_.name).trim($fn) -eq $i}
if ($operatingfile)
{$operatingFilenumber = ($files | ?{($_.name).trim($fn) -eq $i}).name.trim($fn)}
else
{$operatingFilenumber = $null}
if(($operatingFilenumber -eq $null) -and ($i -ne 1) -and ($i -lt $logcount))
{
$operatingFilenumber = $i
$newfilename = "$filefullname.$operatingFilenumber"
$operatingFile = $files | ?{($_.name).trim($fn) -eq ($i-1)}
write-host "moving to $newfilename"
move-item ($operatingFile.FullName) -Destination $newfilename -Force
}
elseif($i -ge $logcount)
{
if($operatingFilenumber -eq $null)
{
$operatingFilenumber = $i - 1
$operatingFile = $files | ?{($_.name).trim($fn) -eq $operatingFilenumber}
}
write-host "deleting " ($operatingFile.FullName)
remove-item ($operatingFile.FullName) -Force
}
elseif($i -eq 1)
{
$operatingFilenumber = 1
$newfilename = "$filefullname.$operatingFilenumber"
write-host "moving to $newfilename"
move-item $filefullname -Destination $newfilename -Force
}
else
{
$operatingFilenumber = $i +1
$newfilename = "$filefullname.$operatingFilenumber"
$operatingFile = $files | ?{($_.name).trim($fn) -eq ($i-1)}
write-host "moving to $newfilename"
move-item ($operatingFile.FullName) -Destination $newfilename -Force
}
}
}
else
{ $logRollStatus = $false}
}
else
{
$logrollStatus = $false
}
$LogRollStatus
}
$resetResult = Reset-Log -fileName $logFile -filesize $fileSize -logcount 5
Write-Log -content ("Starting Package Def Search in " + $startDir)
Get-ChildItem -Path $startDir -Filter *.pkgdef -Recurse -Depth 100 -File -Name| ForEach-Object {
$file = $_
$exePair = $file
$exePair = $exePair.ToLower().Replace(".pkgdef",".exe")
$exePair = [System.IO.Path]::Combine($startDir, $exePair)
if([System.IO.File]::Exists($exePair)) {
Write-Log -content ("Found Matching EXE: " + $exePair)
}
}
Write-Log -content "Finished Package Def Search."
view raw PkgDefMatch.ps1 hosted with ❤ by GitHub

Collecting and Analyzing Dumps with .Net Core on Linux

Welcome file Over the past 18 years or so of .NET’s life span an entire ecosystem of tools have been developed to assi...