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 |