WinpeOutGridView.psm1

<#
    .NOTES
    --------------------------------------------------------------------------------
     Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.152
     Generated on: 11/24/2019 2:14 PM
     Generated by: Technician 420ƋȠƮ TM
     Organization: Custom Builds Real Solutions
    --------------------------------------------------------------------------------
    .DESCRIPTION
        'PowerShell 7.0.0 Preview 5 and Microsoft.PowerShell.GraphicalTools Module
        Developed by The PowerShell Team over at Microsoft, Is what made me make
        the Permanent switch to PowerShell Core and ditch the desktop version.
        My Module WinpeOutGridView is my first real module i wrote to come up with
        a real solution for what i was un able to find online. This module is servel
        solutions,
        example 1. WinPE Out-GridView to Remove-WindowsDrivers, Remove-WindowsPackages
        Remove-AppxProvisionedPackages, Disable-WindowsFeatures.
        example 2 Needed a way to display progress for AppxProvisionedPackages and
        Remove-WindowsDrivers. Write-Progress ForEach-Object.
        With my module WinpeOutGridView and PowerShell Teams Microsoft.PowerShell.GraphicalTools
        allows the user to select as many packages, drivers, appxprovisionedpackages,
        windowsoptionalfeatures from a list a remove or disable with a few clicks
        and will display a progress bar with total number and current number in progress..'
#>



<#
    ===========================================================================
     Created with: SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.152
     Created on: 11/24/2019 2:11 PM
     Created by: Technician 420ƋȠƮ TM
     Organization: Custom Builds Real Solutions
     Filename: WinpeOutGridView.psm1
    -------------------------------------------------------------------------
     Module Name: WinpeOutGridView
    ===========================================================================
#>


Function Disable-WindowsOptionalFeatures
{
    $scriptblock =
    {
        # -- Place Your Commands Here
        function Select-OptionalFeature
        {
            param
            (
                [Object][Parameter(Mandatory = $true, ValueFromPipeline = $true, HelpMessage = 'Data to process')]
                $InputObject
            )
            process
            {
                "FeatureName = $($InputObject.FeatureName)"
                Get-WindowsOptionalFeature -Path $MountPath |
                Where-Object -Property FeatureName -EQ -Value $OptionalFeature.FeatureName |
                Disable-WindowsOptionalFeature -Path $MountPath -Remove
            }
        }
        $application = New-Object -ComObject Shell.Application
        $MountPath = ($application.BrowseForFolder(0, 'Select a folder', 0)).Self.Path
        Get-WindowsOptionalFeature -Path $MountPath |
        Select-Object -Property FeatureName, State |
        Sort-Object -Property State |
        Export-Csv -Path .\OptionalFeatures.csv
        $Feature = (Import-Csv -Path .\OptionalFeatures.csv)
        $Features = $Feature | Out-GridView -Title 'Select WindowsOptionalFeatures and Disable and Remove.' -PassThru
        
        $OptionalFeatures = $Features
        $CurrentOptionalFeature = 0
        foreach ($OptionalFeature in $OptionalFeatures)
        {
            Write-Progress -Id 1 -Activity 'Disabling and Removing WindowsOptionalFeatures' -PercentComplete (($CurrentOptionalFeature / $OptionalFeatures.Count) * 100) -Status "($($CurrentOptionalFeature + 1)/$($OptionalFeatures.Count)) Current OptionalFeature: $OptionalFeature"
            $CurrentOptionalFeature++
            Start-Sleep -Milliseconds 250
            Write-Progress -Id 2 -Activity 'Disabling and Removing WindowsOptionalFeatures' -Completed
            
            $OptionalFeature | Select-OptionalFeature
        }
    }
    $encoded = [convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptblock))
    & "$env:ComSpec" /c start pwsh -NoExit -EncodedCommand $encoded
}

Function Disable-WindowsOptionalFeaturesOnline
{
    $scriptblock =
    {
        # -- Place Your Commands Here
        function Select-OptionalFeature
        {
            param
            (
                [Object][Parameter(Mandatory = $true, ValueFromPipeline = $true, HelpMessage = 'Data to process')]
                $InputObject
            )
            process
            {
                "FeatureName = $($InputObject.FeatureName)"
                Get-WindowsOptionalFeature -Online |
                Where-Object -Property FeatureName -EQ -Value $OptionalFeature.FeatureName |
                Disable-WindowsOptionalFeature -Online -Remove
            }
        }
        Get-WindowsOptionalFeature -Online |
        Select-Object -Property FeatureName, State |
        Sort-Object -Property State |
        Export-Csv -Path .\OptionalFeatures.csv
        $Feature = (Import-Csv -Path .\OptionalFeatures.csv)
        $Features = $Feature | Out-GridView -Title 'Online Image: Select WindowsOptionalFeatures and Disable and Remove.' -PassThru
        
        $OptionalFeatures = $Features
        $CurrentOptionalFeature = 0
        foreach ($OptionalFeature in $OptionalFeatures)
        {
            Write-Progress -Id 1 -Activity 'Online Image: Disabling and Removing WindowsOptionalFeatures' -PercentComplete (($CurrentOptionalFeature / $OptionalFeatures.Count) * 100) -Status "($($CurrentOptionalFeature + 1)/$($OptionalFeatures.Count)) Current OptionalFeature: $OptionalFeature"
            $CurrentOptionalFeature++
            Start-Sleep -Milliseconds 250
            Write-Progress -Id 2 -Activity 'Online Image: Disabling and Removing WindowsOptionalFeatures' -Completed
            
            $OptionalFeature | Select-OptionalFeature
        }
    }
    $encoded = [convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptblock))
    & "$env:ComSpec" /c start pwsh -NoExit -EncodedCommand $encoded
}

function Get-DiskPartition
{
     <#
 .NOTES
        Partitions can be mapped to their disks using the Win32_DiskDriveToDiskPartition class,
        and drives can be mapped to their partitions via the Win32_LogicalDiskToPartition class.
#>

    
    Get-WmiObject Win32_DiskDrive | ForEach-Object {
        $disk = $_
        $partitions = "ASSOCIATORS OF " +
        "{Win32_DiskDrive.DeviceID='$($disk.DeviceID)'} " +
        "WHERE AssocClass = Win32_DiskDriveToDiskPartition"
        Get-WmiObject -Query $partitions | ForEach-Object {
            $partition = $_
            $drives = "ASSOCIATORS OF " +
            "{Win32_DiskPartition.DeviceID='$($partition.DeviceID)'} " +
            "WHERE AssocClass = Win32_LogicalDiskToPartition"
            Get-WmiObject -Query $drives | ForEach-Object{
                New-Object -TypeName PSCustomObject -Property @{
                    Disk                                     = $disk.DeviceID
                    DiskSize                     = [math]::Round($disk.Size / 1GB, 2)
                    DiskModel                 = $disk.Model
                    Partition                 = $partition.Name
                    RawSize                         = [math]::Round($partition.Size / 1GB, 2)
                    DriveLetter         = $_.DeviceID
                    VolumeName             = $_.VolumeName
                    Size                                     = [math]::Round($_.Size / 1GB, 2)
                    FreeSpace                 = [math]::Round($_.FreeSpace /1gb, 2)
                }
            }
        }
    }
}

function Get-SystemInformation
{
    Get-ComputerInfo -Property ('WindowsBuildLabEx', 'WindowsCurrentVersion', 'WindowsEditionId', 'WindowsProductName', ' WindowsSystemRoot',
        'WindowsVersion', 'BiosBIOSVersion', 'BiosCaption', 'BiosDescription', 'BiosFirmwareType', 'BiosManufacturer', 'BiosName',
        'BiosReleaseDate', 'BiosSerialNumber', 'BiosSMBIOSBIOSVersion', 'BiosSMBIOSMajorVersion', 'BiosSMBIOSPresent', 'BiosSoftwareElementState',
        'BiosStatus', 'BiosSystemBiosMajorVersion', 'BiosVersion', 'CsDNSHostName', 'CsDomain', ' CsDomainRole', 'CsManufacturer', 'CsModel',
        'CsName', 'CsNetworkServerModeEnabled', 'CsNumberOfLogicalProcessors', 'CsNumberOfProcessors', 'CsProcessors', 'CsOEMStringArray',
        'CsPartOfDomain', 'CsPCSystemType', 'CsSystemFamily', 'CsSystemSKUNumber', 'CsSystemType', 'CsWorkgroup', 'OsName', 'OsType',
        'OsOperatingSystemSKU', 'OsVersion', 'OsBuildNumber', 'OsSystemDevice', 'OsSystemDirectory', 'OsSystemDrive', 'OsWindowsDirectory',
        'OsBuildType', 'OsCodeSet', 'OsDataExecutionPreventionAvailable', 'OsDataExecutionPrevention32BitApplications', 'OsDataExecutionPreventionDrivers',
        'OsEncryptionLevel', 'OsArchitecture')
}

Function Remove-AppxProvisionedPackages
{
    $scriptblock =
    {
        # -- Place Your Commands Here
        function Select-AppxProvisonedPackage
        {
            param
            (
                [Object][Parameter(Mandatory = $true, ValueFromPipeline = $true, HelpMessage = 'Data to process')]
                $InputObject
            )
            process
            {
                "PackageName = $($InputObject.PackageName)"
                Get-AppxProvisionedPackage -Path $MountPath |
                Where-Object -Property PackageName -EQ -Value $AppxProvisionedPackage.PackageName |
                Remove-AppxProvisionedPackage -Path $MountPath
            }
        }
        
        $application = New-Object -ComObject Shell.Application
        $MountPath = ($application.BrowseForFolder(0, 'Select a folder', 0)).Self.Path
        Get-AppxProvisionedPackage -Path $MountPath |
        Select-Object -Property PackageName |
        Export-Csv -Path .\Appxprovisioned.csv
        $Appx = (Import-Csv -Path .\AppxProvisioned.csv)
        $AppxPackages = $Appx | Out-GridView -Title 'Offline Image: Select and Remove AppxProvisionedPackages' -PassThru
        
        $AppxProvisionedPackages = $AppxPackages
        $CurrentAppxProvisionedPackage = 0
        foreach ($AppxProvisionedPackage in $AppxProvisionedPackages)
        {
            Write-Progress -Id 1 -Activity 'Offline Image: Removing AppxProvisionedPackages' -PercentComplete (($CurrentAppxProvisionedPackage / $AppxProvisionedPackages.Count) * 100) -Status "($($CurrentAppxProvisionedPackage + 1)/$($AppxProvisionedPackages.Count)) Current AppxProvisionedPackage: $AppxProvisionedPackage"
            $CurrentAppxProvisionedPackage++
            Start-Sleep -Milliseconds 500
            Write-Progress -Id 2 -Activity 'Offline Image: Removing AppxProvisionedPackages' -Completed
            
            $AppxProvisionedPackage | Select-AppxProvisonedPackage
        }
    }
    $encoded = [convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptblock))
    & "$env:ComSpec" /c start pwsh -NoExit -EncodedCommand $encoded
}

Function Remove-AppxProvisionedPackagesOnline
{
    $scriptblock =
    {
        # -- Place Your Commands Here
        function Select-AppxProvisonedPackage
        {
            param
            (
                [Parameter(Mandatory = $true, ValueFromPipeline = $true, HelpMessage = 'Data to process')]
                $InputObject
            )
            process
            {
                "PackageName = $($InputObject.PackageName)"
                Get-AppxProvisionedPackage -Online |
                Where-Property PackageName -EQ -Value $AppxProvisionedPackage.PackageName |
                Remove-AppxProvisionedPackage -Online
            }
        }
        Get-AppxProvisionedPackage -Online |
        Select-Object -Property PackageName |
        Export-Csv -Path .\Appxprovisioned.csv
        $Appx = (Import-Csv -Path .\AppxProvisioned.csv)
        $AppxPackages = $Appx | Out-GridView -Title 'Online Image: Select and Remove AppxProvisionedPackages' -PassThru
        
        $AppxProvisionedPackages = $AppxPackages
        $CurrentAppxProvisionedPackage = 0
        foreach ($AppxProvisionedPackage in $AppxProvisionedPackages)
        {
            Write-Progress -Id 1 -Activity 'Online Image:: Removing AppxProvisionedPackages' -PercentComplete (($CurrentAppxProvisionedPackage / $AppxProvisionedPackages.Count) * 100) -Status "($($CurrentAppxProvisionedPackage + 1)/$($AppxProvisionedPackages.Count)) Current AppxProvisionedPackage: $AppxProvisionedPackage"
            $CurrentAppxProvisionedPackage++
            Start-Sleep -Milliseconds 500
            Write-Progress -Id 2 -Activity 'Online Image:: Removing AppxProvisionedPackages' -Completed
            
            $AppxProvisionedPackage | Select-AppxProvisonedPackage
        }
    }
    $encoded = [convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptblock))
    & "$env:ComSpec" /c start pwsh -NoExit -EncodedCommand $encoded
}

Function Remove-WindowsDrivers
{
    $scriptblock =
    {
        # -- Place Your Commands Here
        function Select-WindowsDrivers
        {
            param
            (
                [Parameter(Mandatory = $true, ValueFromPipeline = $true, HelpMessage = 'Data to process')]
                $InputObject
            )
            process
            {
                "OriginalFileName = $($InputObject.OriginalFileName)"
                Get-WindowsDriver -Path $MountPath |
                Where-Object -Property OriginalFileName -EQ -Value $WindowsDriver.OriginalFileName |
                Remove-WindowsDriver -Path $MountPath
            }
        }
        $application = New-Object -ComObject Shell.Application
        $MountPath = ($application.BrowseForFolder(0, 'Select a folder', 0)).Self.Path
        Get-WindowsDriver -Path $MountPath |
        Select-Object -Property Driver, OriginalFileName, ClassName, ProviderName, BootCritical, Date |
        Export-Csv -Path .\WindowsDrivers.csv
        $Inf = (Import-Csv -Path .\WindowsDrivers.csv)
        $Drivers = $Inf | Out-GridView -Title 'Offline Image: Select and Remove Windows Drivers' -PassThru
        $WindowsDrivers = $Drivers
        $CurrentWindowsDriver = 0
        foreach ($WindowsDriver in $WindowsDrivers)
        {
            Write-Progress -Id 1 -Activity 'Offline Image: Removing WindowsDrivers' -PercentComplete (($CurrentWindowsDriver / $WindowsDrivers.Count) * 100) -Status "($($CurrentWindowsDriver + 1)/$($WindowsDrivers.Count)) Current WindowsDriver: $WindowsDriver"
            $CurrentWindowsDriver++
            Start-Sleep -Milliseconds 500
            Write-Progress -Id 2 -Activity 'Offline Image: Removing WindowsDrivers' -Completed
            $WindowsDriver | Select-WindowsDrivers
        }
    }
    $encoded = [convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptblock))
    & "$env:ComSpec" /c start pwsh -NoExit -EncodedCommand $encoded
}

Function Remove-WindowsPackages
{
    $scriptblock =
    {
        # -- Place Your Commands Here
        function Select-WindowsPackages
        {
            param
            (
                [Object][Parameter(Mandatory = $true, ValueFromPipeline = $true, HelpMessage = 'Data to process')]
                $InputObject
            )
            process
            {
                "PackageName = $($InputObject.PackageName)"
                Get-WindowsPackage -Path $MountPath |
                Where-Object -Property PackageName -EQ -Value $WindowsPackage.PackageName |
                Remove-WindowsPackage -Path $MountPath
            }
        }
        
        $application = New-Object -ComObject Shell.Application
        $MountPath = ($application.BrowseForFolder(0, 'Select a folder', 0)).Self.Path
        Get-WindowsPackage -Path $MountPath |
        Select-Object -Property PackageName |
        Export-Csv -Path .\WindowsPackage.csv
        $Apps = (Import-Csv -Path .\WindowsPackage.csv)
        $Packages = $Apps | Out-GridView -Title 'Offline Image: Select and Remove WindowsPackages' -PassThru
        
        $WindowsPackages = $Packages
        $CurrentWindowsPackage = 0
        foreach ($WindowsPackage in $WindowsPackages)
        {
            Write-Progress -Id 1 -Activity 'Offline Image: Select and Remove WindowsPackages' -PercentComplete (($CurrentWindowsPackage / $WindowsPackages.Count) * 100) -Status "($($CurrentWindowsPackage + 1)/$($WindowsPackages.Count)) Current WindowsPackage: $WindowsPackage"
            $CurrentWindowsPackage++
            Start-Sleep -Milliseconds 250
            Write-Progress -Id 2 -Activity 'Offline Image: Select and Remove WindowsPackages' -Completed
            
            $WindowsPackage | Select-WindowsPackages
        }
    }
    $encoded = [convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptblock))
    & "$env:ComSpec" /c start pwsh -NoExit -EncodedCommand $encoded
}

Function Remove-WindowsPackagesOnline
{
    $scriptblock =
    {
        # -- Place Your Commands Here
        function Select-WindowsPackages
        {
            param
            (
                [Object][Parameter(Mandatory = $true, ValueFromPipeline = $true, HelpMessage = 'Data to process')]
                $InputObject
            )
            process
            {
                "PackageName = $($InputObject.PackageName)"
                Get-WindowsPackage -Online |
                Where-Object -Property PackageName -EQ -Value $WindowsPackage.PackageName |
                Remove-WindowsPackage -Online
            }
        }
        Get-WindowsPackage -Online |
        Select-Object -Property PackageName |
        Export-Csv -Path .\WindowsPackage.csv
        $Apps = (Import-Csv -Path .\WindowsPackage.csv)
        $Packages = $Apps | Out-GridView -Title 'Online Image: Select and Remove WindowsPackages' -PassThru
        
        $WindowsPackages = $Packages
        $CurrentWindowsPackage = 0
        foreach ($WindowsPackage in $WindowsPackages)
        {
            Write-Progress -Id 1 -Activity 'Online Image: Select and Remove WindowsPackages' -PercentComplete (($CurrentWindowsPackage / $WindowsPackages.Count) * 100) -Status "($($CurrentWindowsPackage + 1)/$($WindowsPackages.Count)) Current WindowsPackage: $WindowsPackage"
            $CurrentWindowsPackage++
            Start-Sleep -Milliseconds 250
            Write-Progress -Id 2 -Activity 'Online Image: Select and Remove WindowsPackages' -Completed
            
            $WindowsPackage | Select-WindowsPackages
        }
    }
    $encoded = [convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptblock))
    & "$env:ComSpec" /c start pwsh -NoExit -EncodedCommand $encoded
}

Function Set-ScratchSpace
{
    $scriptblock =
    {
        # -- Place Your Commands Here
        [CmdletBinding()]
        param
        (
            [ValidateSet('C:\PerfLogs', 'C:\WinPE_x64\Mount')]
            [string]$Path = $MountPath
        )
        # -- Windows PE boot.wim Set-ScratchSpace:512
        $Today
        $application = New-Object -ComObject Shell.Application
        $MountPath = ($application.BrowseForFolder(0, 'Select a folder', 0)).Self.Path
        Write-Verbose -Message ' Windows PE boot.wim Set-ScratchSpace:512'
        & "$env:windir\system32\dism.exe" /image:$MountPath /Set-ScratchSpace:512
        Start-Sleep -Seconds 3
    }
    $encoded = [convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptblock))
    & "$env:ComSpec" /c start pwsh -NoExit -EncodedCommand $encoded
}

Function Start-AnalyzeComponentStore
{
    $scriptblock =
    {
        # -- Place Your Commands Here
        [CmdletBinding()]
        param
        (
            [ValidateSet('C:\PerfLogs', 'C:\WinPE_x64\Mount')]
            [string]$Path = $MountPath
        )
        # -- Cleanup-Image /AnalyzeComponentStore Select Path GUI
        $application = New-Object -ComObject Shell.Application
        $MountPath = ($application.BrowseForFolder(0, 'Select a folder', 0)).Self.Path
        & "$env:windir\system32\dism.exe" /image:$MountPath /Cleanup-Image /AnalyzeComponentStore
    }
    $encoded = [convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptblock))
    & "$env:ComSpec" /c start pwsh -NoExit -EncodedCommand $encoded
}

Function Start-ComponentCleanup
{
    $scriptblock =
    {
        param
        (
            [ValidateSet('C:\PerfLogs', 'C:\WinPE_x64\Mount')]
            [string]$Path = $MountPath
        )
        
        # -- Cleanup-Image /StartComponentCleanup Select Path GUI
        $application = New-Object -ComObject Shell.Application
        $MountPath = ($application.BrowseForFolder(0, 'Select a folder', 0)).Self.Path
        & "$env:windir\system32\dism.exe" /image:$MountPath /Cleanup-Image /StartComponentCleanup
    }
    $encoded = [convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptblock))
    & "$env:ComSpec" /c start pwsh -NoExit -EncodedCommand $encoded
}

Function Start-ComponentResetBase
{
    $scriptblock =
    {
        param
        (
            [Parameter(Mandatory = $false)]
            [ValidateSet('C:\PerfLogs', 'C:\WinPE_x64\Mount')]
            [string]$Path = $MountPath
        )
        # -- Cleanup-Image /StartComponentCleanup /ResetBase Select Path GUI
        $application = New-Object -ComObject Shell.Application
        $MountPath = ($application.BrowseForFolder(0, 'Select a folder', 0)).Self.Path
        & "$env:windir\system32\dism.exe" /image:$MountPath /Cleanup-Image /StartComponentCleanup /ResetBase /ScratchDir:D:\Scratch
    }
    $encoded = [convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptblock))
    & "$env:ComSpec" /c start pwsh -NoExit -EncodedCommand $encoded
}


Export-ModuleMember -Function Disable-WindowsOptionalFeatures,
                                                                                Disable-WindowsOptionalFeaturesOnline,
                                                                                Get-DiskPartition,
                                                                                Get-SystemInformation,
                                                                                Remove-AppxProvisionedPackages,
                                                                                Remove-AppxProvisionedPackagesOnline,
                                                                                Remove-WindowsDrivers,
                                                                                Remove-WindowsPackages,
                                                                                Remove-WindowsPackagesOnline,
                                                                                Set-ScratchSpace,
                                                                                Start-AnalyzeComponentStore,
                                                                                Start-ComponentCleanup,
                                                                                Start-ComponentResetBase