Skip to main content

Windows Worklet NET Core SDK Removal

  • December 28, 2023
  • 0 replies
  • 459 views

jack.smith
Forum|alt.badge.img+1

This has been an interesting one I thought I’d share. I’m honestly still very hands on with this one and only run it manually. Meaning I fully expect this to be a journey, not a perfect solution.

Also please note, I’m using the Get-Win32 and Remove-Win32App cmdlets available by using Automox’s amazing WDK https://developer.automox.com/developer-portal/wdk/overview/ (saves me from writing so much code)

 

Another call-out. These worklets will install dotnet-uninstall-tool version 1.6.0 explicitly (update code to use newer versions). Learn more about that at Emanuele Bartolesi blog here https://dev.to/kasuken/removing-old-version-of-net-4052 or just go checkout the latest releases of the Microsoft built tool here https://github.com/dotnet/cli-lab/releases

 

My workflow consists of using two worklets as such:

  1. Update variable versions in BOTH worklets manually based on my own internal needs of what versions need removed (typically get this list from a vulnerability scanner’s output)
  2. Run the NET Core SDK What-If that accomplishes the following:
    • Uses Get-Win32App to find ‘Microsoft .NET Core SDK’​​​​​​​
    • Reports EOL Win32 Apps based on versions variable
    • Looks for dotnet-core-uninstall tool, if not installs version 1.6.0
    • Runs dotnet-core-uninstall list
    • Runs dotnet-core-uninstall whatif -all-but-latest --core (cycles through aspnet-runtime, hosting-bundle, runtime, sdk with output. Marvel at this because figuring out how to pass to the command and still get output was not easy!)
    • Cycle through four directories for EOL versions (even after removal, these directories seem to get left behind. hence the focus)
    • Run dotnet --info
  3. Analyze the output as that helps me understand two very important points:
    • NET Core SDK dependency on Visual Studio (fix that manually before running actual cleanup worklet)
    • What the Cleanup worklet will do
  4. Run the NET Core SDK Removal that accomplishes the following:
    • ​​​​​​​Looks for dotnet-core-uninstall tool, if not installs version 1.6.0
    • Removes EOL Win32 Apps based on versions variable (not always smooth)
    • Runs dotnet-core-uninstall list
    • Runs dotnet-core-uninstall remove -all-but-latest --core (cycles through aspnet-runtime, hosting-bundle, runtime, sdk with output)
    • Cycle through four directories for EOL versions, first archiving each one to a zip file, then if the zip exists, removing the directory.

 

Remediation Code “NET Core SDK What-If”

# Approved Removal
$versions = '1.0.4','2.0.7','2.1.12','2.1.14.28209','2.2.8','3.1.32','3.1.32.31915','5.0.17','5.0.17.31213','5.0.17.31219','5.0.4','5.0.9'

# Shows Win32 SDK Core Apps that are EOL per $versions variable
$apps = Try { Get-Win32App | Where-Object { $_.Name -match 'Microsoft .NET Core SDK' -and $_.Name -notmatch 'Microsoft .NET Core SDK Uninstall Tool'} }catch{exit 0}
foreach ($app in $apps){
    $versions | % {
        IF($app.name -match $_){$eol = "End of Life -- "}
    }
    Write-Output "$eol$($app.name) installed $($app.InstallDate)"
    IF($eol){remove-variable eol}   
}
IF(!$apps){Write-Output "Did not detect any Win32 Apps with Microsoft .NET Core SDK as installed."; Write-Output ""}

# Validate Microsoft .NET Core SDK Uninstall Tool as installed
$app = Try { Get-Win32App | Where-Object { $_.Name -match 'Microsoft .NET Core SDK Uninstall Tool' } }catch{exit 0}
IF(!$app){
  Write-Output "Attempting to install Microsoft .NET Core SDK Uninstall Tool (x86)"
  $uri = 'https://github.com/dotnet/cli-lab/releases/download/1.6.0/dotnet-core-uninstall-1.6.0.msi'
  $msi = 'C:\windows\temp\dotnet-core-uninstall-1.6.0.msi'
  IF((Test-Path $msi) -eq $false){
    Write-Output "Downloading $uri"
    Invoke-WebRequest -uri $uri -out $msi  
  }else{
    Write-Output "Found $msi. Starting Install."
  }

  # Install
  Start-Process MsiExec -ArgumentList "/I $msi /qn" -wait

  # Validate Install
  $app = Try { Get-Win32App | Where-Object { $_.Name -match 'Microsoft .NET Core SDK Uninstall Tool' } }catch{exit 0}
  IF(!$app){
    Write-Output "Failed to Install Microsoft .NET Core SDK Uninstall Tool (x86). Giving up."
    exit 0
  }else{
    Write-Output "Installed Microsoft .NET Core SDK Uninstall Tool (x86)"
  }
}

# List the dotnet-core-uninstall list to see what versions can be removed
Write-Output "dotnet-core-uninstall list"
$exe = "C:\Program Files (x86)\dotnet-core-uninstall\dotnet-core-uninstall.exe"
cmd /c $exe list

Write-Output ""
Write-Output "Running what-if mode on dotnet-core-uninstall.exe cleanup tool:"
Function Start-DotnetCoreUninstall ($core){
    $exe = "C:\Program Files (x86)\dotnet-core-uninstall\dotnet-core-uninstall.exe"
    $obj = New-Object System.Diagnostics.ProcessStartInfo
    $obj.FileName = "cmd.exe"
    $obj.RedirectStandardError = $true
    $obj.RedirectStandardOutput = $true
    $obj.UseShellExecute = $false
    $obj.Arguments = "/c echo y | `"$exe`" whatif --all-but-latest --$core"
    $p = New-Object System.Diagnostics.Process
    $p.StartInfo = $obj
    $p.Start() | Out-Null
    $p.WaitForExit()
    $p.StandardOutput.ReadToEnd()
    $p.StandardError.ReadToEnd()
}
Write-Output "Cleanup aspnet-runtime:"
Start-DotnetCoreUninstall aspnet-runtime
Write-Output "Cleanup hosting-bundle:"
Start-DotnetCoreUninstall hosting-bundle
Write-Output "Cleanup runtime:"
Start-DotnetCoreUninstall runtime
Write-Output "Cleanup sdk:"
Start-DotnetCoreUninstall sdk


Write-Output ""
Write-Output "Manual Directory Cleanup"

$dirs = 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\',
'C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\',
'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\',
'C:\Program Files (x86)\dotnet\shared\Microsoft.AspNetCore.App\'
$paths = Get-ChildItem $dirs -Directory -ErrorAction SilentlyContinue
foreach ($path in $paths){
    $versions | % {
        IF($path.FullName -match $_){
            $i++   
        }
    }
    IF($i -gt 0){
        Write-Output "EOL Path: $($path.FullName)"
    }else{
        Write-Output "Path: $($path.FullName)"
    }
    IF($i){Remove-Variable i}
}

Write-Output ""
Write-Output "dotnet --info"
dotnet --info
Write-Output ""

Remediation Code “NET Core SDK Removal”

# Approved Removal
$versions = '1.0.4','2.0.7','2.1.12','2.1.14.28209','2.2.8','3.1.32','3.1.32.31915','3.1.426','5.0.17','5.0.17.31213','5.0.17.31219','5.0.4','5.0.9'

# Validate Microsoft .NET Core SDK Uninstall Tool as installed
$app = Try { Get-Win32App | Where-Object { $_.Name -match 'Microsoft .NET Core SDK Uninstall Tool' } }catch{exit 0}
IF(!$app){
  Write-Output "Attempting to install Microsoft .NET Core SDK Uninstall Tool (x86)"
  $uri = 'https://github.com/dotnet/cli-lab/releases/download/1.6.0/dotnet-core-uninstall-1.6.0.msi'
  $msi = 'C:\windows\temp\dotnet-core-uninstall-1.6.0.msi'
  IF((Test-Path $msi) -eq $false){
    Write-Output "Downloading $uri"
    Invoke-WebRequest -uri $uri -out $msi  
  }else{
    Write-Output "Found $msi. Starting Install."
  }

  # Install
  Start-Process MsiExec -ArgumentList "/I $msi /qn" -wait

  # Validate Install
  $app = Try { Get-Win32App | Where-Object { $_.Name -match 'Microsoft .NET Core SDK Uninstall Tool' } }catch{exit 0}
  IF(!$app){
    Write-Output "Failed to Install Microsoft .NET Core SDK Uninstall Tool (x86). Giving up."
    exit 0
  }else{
    Write-Output "Installed Microsoft .NET Core SDK Uninstall Tool (x86)"
  }
}

# Remove Win32 SDK Core Apps
$apps = Try { Get-Win32App | Where-Object { $_.Name -match 'Microsoft .NET Core SDK' -and $_.Name -notmatch 'Microsoft .NET Core SDK Uninstall Tool'} }catch{exit 0}
foreach ($app in $apps){
    $versions | % {
        IF($app.name -match $_){$i++}
    }
    IF($i -gt 0){
      Write-Output "Removing $($app.name) installed $($app.InstallDate)"
      Get-Win32App | Where-Object { $_.Name -eq "$($app.name)" } | Remove-Win32App -AdditionalArgs '/qn'
    }
    IF($i){remove-variable i}   
}

# Remove all but latest ASP.NET versions
Write-Output "dotnet-core-uninstall list"
$exe = "C:\Program Files (x86)\dotnet-core-uninstall\dotnet-core-uninstall.exe"
cmd /c $exe list
Write-Output ""

Function Start-DotnetCoreUninstall ($core){
    $exe = "C:\Program Files (x86)\dotnet-core-uninstall\dotnet-core-uninstall.exe"
    $obj = New-Object System.Diagnostics.ProcessStartInfo
    $obj.FileName = "cmd.exe"
    $obj.RedirectStandardError = $true
    $obj.RedirectStandardOutput = $true
    $obj.UseShellExecute = $false
    $obj.Arguments = "/c echo y | `"$exe`" remove --all-but-latest --$core --force"
    $p = New-Object System.Diagnostics.Process
    $p.StartInfo = $obj
    $p.Start() | Out-Null
    $p.WaitForExit()
    $p.StandardOutput.ReadToEnd()
    $p.StandardError.ReadToEnd()
}
Write-Output "Cleanup aspnet-runtime:"
Start-DotnetCoreUninstall aspnet-runtime
Write-Output "Cleanup hosting-bundle:"
Start-DotnetCoreUninstall hosting-bundle
Write-Output "Cleanup runtime:"
Start-DotnetCoreUninstall runtime
Write-Output "Cleanup sdk:"
Start-DotnetCoreUninstall sdk

write-output ""
write-output "List dotnet-core-uninstall"
cmd /c $exe list

Write-Output ""
Write-Output "Manual Directory Cleanup:"

$dirs = 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\',
'C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\',
'C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\',
'C:\Program Files (x86)\dotnet\shared\Microsoft.AspNetCore.App\'
$paths = Get-ChildItem $dirs -Directory -ErrorAction SilentlyContinue
foreach ($path in $paths){
    $versions | % {
        IF($path.FullName -match $_){
            $i++
        }
    }
    IF($i -gt 0){
       Write-Output "Cleanup $($path.FullName)"
        # Backup
        Compress-Archive -Path $path.FullName -DestinationPath "$($path.FullName).zip"

        # Remove
        IF(Test-Path "$($path.FullName).zip") {
            Remove-Item $path.FullName -Recurse -force
        }else{
            Write-Output "Cleanup Stopped. Failed to archive $($path.FullName)"
        }
    }else{
        Write-Output "No action on path: $($path.FullName)"
    }
    IF($i){Remove-Variable i}
}

 

0 replies

Be the first to reply!

Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings