mirror of
https://github.com/freedbygrace/Remove-UWPs.git
synced 2026-07-26 11:39:16 +00:00
Add files via upload
This commit is contained in:
@@ -0,0 +1 @@
|
||||
###
|
||||
@@ -0,0 +1 @@
|
||||
###
|
||||
@@ -0,0 +1 @@
|
||||
###
|
||||
Binary file not shown.
@@ -0,0 +1,564 @@
|
||||
$Script:TaskSequenceEnvironment = $null
|
||||
$Script:TaskSequenceProgressUi = $null
|
||||
|
||||
function Confirm-TSEnvironmentSetup()
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Verifies the TSEnvironment Com Object is initiated into an object.
|
||||
|
||||
.DESCRIPTION
|
||||
Verifies the TSEnvironment Com Object is initiated into an object.
|
||||
.INPUTS
|
||||
None
|
||||
.OUTPUTS
|
||||
None
|
||||
|
||||
.NOTE
|
||||
This module can be used statically to initiate the TSEnvironment module, however, simply running one of the commands will initate it for you.
|
||||
#>
|
||||
|
||||
if ($Script:TaskSequenceEnvironment -eq $null)
|
||||
{
|
||||
try
|
||||
{
|
||||
$Script:TaskSequenceEnvironment = New-Object -ComObject Microsoft.SMS.TSEnvironment
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw "Unable to connect to the Task Sequence Environment! Please verify you are in a running Task Sequence Environment.`n`nErrorDetails:`n$_"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Get-TSVariables()
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get all Task Sequence Variable Names
|
||||
|
||||
.DESCRIPTION
|
||||
Returns a string array of all Task Sequence Variable Names (not values).
|
||||
.INPUT
|
||||
None
|
||||
.OUTPUTS
|
||||
String[]
|
||||
.EXAMPLE
|
||||
$arrayOfVariableNames = Get-TSVariables
|
||||
#>
|
||||
Confirm-TSEnvironmentSetup
|
||||
|
||||
$allVar = @()
|
||||
|
||||
foreach ($variable in $Script:TaskSequenceEnvironment.GetVariables())
|
||||
{
|
||||
$allVar += $variable
|
||||
}
|
||||
|
||||
return $allVar
|
||||
}
|
||||
|
||||
function Get-TSValue()
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get a Task Sequence Variables Value
|
||||
|
||||
.DESCRIPTION
|
||||
Obtains the value of a specific Task Sequence Variable.
|
||||
|
||||
.PARAMETER Name
|
||||
Specifies the variable name to resolve.
|
||||
.INPUTS
|
||||
String
|
||||
.OUTPUTS
|
||||
String
|
||||
.EXAMPLE
|
||||
$OsdComputerName = Get-TSValue -Name "OSDComputerName"
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $Name
|
||||
)
|
||||
|
||||
Confirm-TSEnvironmentSetup
|
||||
|
||||
return $Script:TaskSequenceEnvironment.Value($Name)
|
||||
}
|
||||
|
||||
function Set-TSVariable()
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Set or Create a Task Sequence Variables Value
|
||||
|
||||
.DESCRIPTION
|
||||
Sets or Creates a Task Sequence Variables Value.
|
||||
Will return a boolean value indicating success or failure.
|
||||
|
||||
.PARAMETER Name
|
||||
Specifies the variable name to set or create.
|
||||
.PARAMETER Value
|
||||
Specifies the variable value
|
||||
.INPUTS
|
||||
- Name: String
|
||||
- Value: System.Boolean
|
||||
.OUTPUTS
|
||||
System.Boolean
|
||||
.EXAMPLE
|
||||
Sets the OSDComputerName task sequence variable to "MyComputer123"
|
||||
$didSet = Set-TSVariable -Name "OSDComputerName" -Value "MyComputer123"
|
||||
.EXAMPLE
|
||||
Creates a new Task Sequence Variable, and sets its value
|
||||
$didSet = Set-TSVariable -Name "MyNewVar" -Value 'MyNewVarsValue"
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $Name,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $Value
|
||||
)
|
||||
|
||||
Confirm-TSEnvironmentSetup
|
||||
|
||||
try
|
||||
{
|
||||
$Script:TaskSequenceEnvironment.Value($Name) = $Value
|
||||
return $true
|
||||
}
|
||||
catch
|
||||
{
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Get-TSAllValues()
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Gets all Task Sequence Variables and Values
|
||||
|
||||
.DESCRIPTION
|
||||
Gets all Task Sequence Variables with their associated values.
|
||||
.INPUTS
|
||||
None
|
||||
.OUTPUTS
|
||||
System.Object
|
||||
.EXAMPLE
|
||||
$TSVariableObject = Get-TSAllValues
|
||||
#>
|
||||
Confirm-TSEnvironmentSetup
|
||||
|
||||
$Values = New-Object -TypeName System.Object
|
||||
|
||||
foreach ($Variable in $Script:TaskSequenceEnvironment.GetVariables())
|
||||
{
|
||||
$Values | Add-Member -MemberType NoteProperty -Name $Variable -Value "$($Script:TaskSequenceEnvironment.Value($Variable))"
|
||||
}
|
||||
|
||||
return $Values
|
||||
}
|
||||
|
||||
function Confirm-TSProgressUISetup()
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Verifies the TSProgresUI Com Object is initiated into an object.
|
||||
|
||||
.DESCRIPTION
|
||||
Verifies the TSProgresUI Com Object is initiated into an object.
|
||||
.INPUTS
|
||||
None
|
||||
.OUTPUTS
|
||||
None
|
||||
|
||||
.NOTE
|
||||
This module can be used statically but is intended to be used by other functions.
|
||||
#>
|
||||
if ($Script:TaskSequenceProgressUi -eq $null)
|
||||
{
|
||||
try
|
||||
{
|
||||
$Script:TaskSequenceProgressUi = New-Object -ComObject Microsoft.SMS.TSProgressUI
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw "Unable to connect to the Task Sequence Progress UI! Please verify you are in a running Task Sequence Environment. Please note: TSProgressUI cannot be loaded during a prestart command.`n`nErrorDetails:`n$_"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Show-TSActionProgress()
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Shows task sequence secondary progress of a specific step
|
||||
|
||||
.DESCRIPTION
|
||||
Adds a second progress bar to the existing Task Sequence Progress UI.
|
||||
This progress bar can be updated to allow for a real-time progress of
|
||||
a specific task sequence sub-step.
|
||||
The Step and Max Step parameters are calculated when passed. This allows
|
||||
you to have a "max steps" of 400, and update the step parameter. 100%
|
||||
would be achieved when step is 400 and max step is 400. The percentages
|
||||
are calculated behind the scenes by the Com Object.
|
||||
|
||||
.PARAMETER Message
|
||||
The message to display the progress
|
||||
.PARAMETER Step
|
||||
Integer indicating current step
|
||||
.PARAMETER MaxStep
|
||||
Integer indicating 100%. A number other than 100 can be used.
|
||||
.INPUTS
|
||||
- Message: String
|
||||
- Step: Long
|
||||
- MaxStep: Long
|
||||
.OUTPUTS
|
||||
None
|
||||
.EXAMPLE
|
||||
Set's "Custom Step 1" at 30 percent complete
|
||||
Show-TSActionProgress -Message "Running Custom Step 1" -Step 100 -MaxStep 300
|
||||
|
||||
.EXAMPLE
|
||||
Set's "Custom Step 1" at 50 percent complete
|
||||
Show-TSActionProgress -Message "Running Custom Step 1" -Step 150 -MaxStep 300
|
||||
.EXAMPLE
|
||||
Set's "Custom Step 1" at 100 percent complete
|
||||
Show-TSActionProgress -Message "Running Custom Step 1" -Step 300 -MaxStep 300
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $Message,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[long] $Step,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[long] $MaxStep
|
||||
)
|
||||
|
||||
Confirm-TSProgressUISetup
|
||||
Confirm-TSEnvironmentSetup
|
||||
|
||||
$Script:TaskSequenceProgressUi.ShowActionProgress(`
|
||||
$Script:TaskSequenceEnvironment.Value("_SMSTSOrgName"),`
|
||||
$Script:TaskSequenceEnvironment.Value("_SMSTSPackageName"),`
|
||||
$Script:TaskSequenceEnvironment.Value("_SMSTSCustomProgressDialogMessage"),`
|
||||
$Script:TaskSequenceEnvironment.Value("_SMSTSCurrentActionName"),`
|
||||
[Convert]::ToUInt32($Script:TaskSequenceEnvironment.Value("_SMSTSNextInstructionPointer")),`
|
||||
[Convert]::ToUInt32($Script:TaskSequenceEnvironment.Value("_SMSTSInstructionTableSize")),`
|
||||
$Message,`
|
||||
$Step,`
|
||||
$MaxStep)
|
||||
}
|
||||
|
||||
function Close-TSProgressDialog()
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Hides the Task Sequence Progress Dialog
|
||||
|
||||
.DESCRIPTION
|
||||
Hides the Task Sequence Progress Dialog
|
||||
|
||||
.INPUTS
|
||||
None
|
||||
.OUTPUTS
|
||||
None
|
||||
.EXAMPLE
|
||||
Close-TSProgressDialog
|
||||
#>
|
||||
Confirm-TSProgressUISetup
|
||||
|
||||
$Script:TaskSequenceProgressUi.CloseProgressDialog()
|
||||
}
|
||||
|
||||
function Show-TSProgress()
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Shows task sequence progress of a specific step
|
||||
|
||||
.DESCRIPTION
|
||||
Manipulates the Task Sequence progress UI; top progress bar only.
|
||||
This progress bar can be updated to allow for a real-time progress of
|
||||
a specific task sequence step.
|
||||
The Step and Max Step parameters are calculated when passed. This allows
|
||||
you to have a "max steps" of 400, and update the step parameter. 100%
|
||||
would be achieved when step is 400 and max step is 400. The percentages
|
||||
are calculated behind the scenes by the Com Object.
|
||||
|
||||
.PARAMETER CurrentAction
|
||||
Step Title. Modifies the "Running action: " Message
|
||||
.PARAMETER Step
|
||||
Integer indicating current step
|
||||
.PARAMETER MaxStep
|
||||
Integer indicating 100%. A number other than 100 can be used.
|
||||
.INPUTS
|
||||
- CurrentAction: String
|
||||
- Step: Long
|
||||
- MaxStep: Long
|
||||
.OUTPUTS
|
||||
None
|
||||
.EXAMPLE
|
||||
Set's "Custom Step 1" at 30 percent complete
|
||||
Show-TSProgress -CurrentAction "Running Custom Step 1" -Step 100 -MaxStep 300
|
||||
|
||||
.EXAMPLE
|
||||
Set's "Custom Step 1" at 50 percent complete
|
||||
Show-TSProgress -CurrentAction "Running Custom Step 1" -Step 150 -MaxStep 300
|
||||
.EXAMPLE
|
||||
Set's "Custom Step 1" at 100 percent complete
|
||||
Show-TSProgress -CurrentAction "Running Custom Step 1" -Step 300 -MaxStep 300
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $CurrentAction,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[long] $Step,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[long] $MaxStep
|
||||
)
|
||||
|
||||
Confirm-TSProgressUISetup
|
||||
Confirm-TSEnvironmentSetup
|
||||
|
||||
$Script:TaskSequenceProgressUi.ShowTSProgress(`
|
||||
$Script:TaskSequenceEnvironment.Value("_SMSTSOrgName"), `
|
||||
$Script:TaskSequenceEnvironment.Value("_SMSTSPackageName"), `
|
||||
$Script:TaskSequenceEnvironment.Value("_SMSTSCustomProgressDialogMessage"), `
|
||||
$CurrentAction, `
|
||||
$Step, `
|
||||
$MaxStep)
|
||||
}
|
||||
|
||||
function Show-TSErrorDialog()
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Shows the Task Sequence Error Dialog
|
||||
|
||||
.DESCRIPTION
|
||||
Shows a task sequence error dialog allowing for custom failure pages.
|
||||
|
||||
.PARAMETER OrganizationName
|
||||
Name of your Organization
|
||||
.PARAMETER CustomTitle
|
||||
Custom Error Title
|
||||
.PARAMETER ErrorMessage
|
||||
Message details of the error
|
||||
.PARAMETER ErrorCode
|
||||
Error Code the Task sequence will exit with
|
||||
.PARAMETER TimeoutInSeconds
|
||||
Timout for the Reboot Prompt
|
||||
.PARAMETER ForceReboot
|
||||
Indicates whether a reboot will be forced or not
|
||||
.INPUTS
|
||||
- OrganizationName: String
|
||||
- CustomTitle: String
|
||||
- ErrorMessage: String
|
||||
- ErrorCode: Long
|
||||
- TimeoutInSeconds: Long
|
||||
- ForceReboot: System.Boolean
|
||||
.OUTPUTS
|
||||
None
|
||||
.EXAMPLE
|
||||
Sets an Error but does not force a reboot
|
||||
Show-TSErrorDialog -OrganizationName "My Organization" -CustomTitle "An Error occured during the things" -ErrorMessage "That thing you tried...it didnt work" -ErrorCode 123456 -TimeoutInSeconds 90 -ForceReboot $false
|
||||
|
||||
.EXAMPLE
|
||||
Sets an Error and forces a reboot
|
||||
Show-TSErrorDialog -OrganizationName "My Organization" -CustomTitle "An Error occured during the things" -ErrorMessage "He's dead Jim!" -ErrorCode 123456 -TimeoutInSeconds 90 -ForceReboot $true
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $OrganizationName,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $CustomTitle,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $ErrorMessage,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[long] $ErrorCode,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[long] $TimeoutInSeconds,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[bool] $ForceReboot
|
||||
)
|
||||
|
||||
Confirm-TSProgressUISetup
|
||||
Confirm-TSEnvironmentSetup
|
||||
|
||||
if ($ForceReboot)
|
||||
{
|
||||
$Script:TaskSequenceProgressUi.ShowErrorDialog($OrganizationName, $Script:TaskSequenceEnvironment.Value("_SMSTSPackageName"), $CustomTitle, $ErrorMessage, $ErrorCode, $TimeoutInSeconds, 1)
|
||||
}
|
||||
else
|
||||
{
|
||||
$Script:TaskSequenceProgressUi.ShowErrorDialog($OrganizationName, $Script:TaskSequenceEnvironment.Value("_SMSTSPackageName"), $CustomTitle, $ErrorMessage, $ErrorCode, $TimeoutInSeconds, 0)
|
||||
}
|
||||
}
|
||||
|
||||
function Show-TSMessage()
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Shows a Windows Forms Message Box
|
||||
|
||||
.DESCRIPTION
|
||||
Shows a Windows Forms Message Box, but does not return the response.
|
||||
This will halt any current operations while the prompt is shown.
|
||||
|
||||
.PARAMETER Message
|
||||
Message to be displayed
|
||||
.PARAMETER Title
|
||||
Title of the message box
|
||||
.PARAMETER Type
|
||||
Button Style for the MessageBox
|
||||
0 = OK
|
||||
1 = OK, Cancel
|
||||
2 = Abort, Retry, Ignore
|
||||
3 = Yes, No, Cancel
|
||||
4 = Yes, No
|
||||
5 = Retry, Cancel
|
||||
6 = Cancel, Try Again, Continue
|
||||
.INPUTS
|
||||
- Message: String
|
||||
- Title: String
|
||||
- Type: Long
|
||||
.OUTPUTS
|
||||
None
|
||||
.EXAMPLE
|
||||
Sets an Error but does not force a reboot
|
||||
Show-TSErrorDialog -OrganizationName "My Organization" -CustomTitle "An Error occured during the things" -ErrorMessage "That thing you tried...it didnt work" -ErrorCode 123456 -TimeoutInSeconds 90 -ForceReboot $false
|
||||
|
||||
.EXAMPLE
|
||||
Sets an Error and forces a reboot
|
||||
Show-TSErrorDialog -OrganizationName "My Organization" -CustomTitle "An Error occured during the things" -ErrorMessage "He's dead Jim!" -ErrorCode 123456 -TimeoutInSeconds 90 -ForceReboot $true
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $Message,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $Title,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[ValidateRange(0,6)]
|
||||
[long] $Type
|
||||
)
|
||||
|
||||
Confirm-TSProgressUISetup
|
||||
|
||||
$Script:TaskSequenceProgressUi.ShowMessage($Message, $Title, $Type)
|
||||
}
|
||||
|
||||
function Show-TSRebootDialog()
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Shows the Reboot Dialog
|
||||
|
||||
.DESCRIPTION
|
||||
Shows the Task Sequence "System Restart" Dialog. This allows you
|
||||
to trigger custom Task Sequence Reboot Messages.
|
||||
|
||||
.PARAMETER OrganizationName
|
||||
Name of your Organization
|
||||
.PARAMETER CustomTitle
|
||||
Custom Title for the Reboot Dialog
|
||||
.PARAMETER Message
|
||||
Detailed Message regarding the reboot
|
||||
.PARAMETER TimeoutInSeconds
|
||||
Timout before the system reboots
|
||||
.INPUTS
|
||||
- OrganizationName: String
|
||||
- CustomTitle: String
|
||||
- Message: String
|
||||
- TimeoutInSeconds: Long
|
||||
.OUTPUTS
|
||||
None
|
||||
.EXAMPLE
|
||||
Show's a Reboot Dialog
|
||||
Show-TSRebootDialog -OrganizationName "My Organization" -CustomTitle "I need a reboot!" -Message "I need to reboot to complete something..." -TimeoutInSeconds 90
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $OrganizationName,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $CustomTitle,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $Message,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[long] $TimeoutInSeconds
|
||||
)
|
||||
|
||||
Confirm-TSProgressUISetup
|
||||
Confirm-TSEnvironmentSetup
|
||||
|
||||
$Script:TaskSequenceProgressUi.ShowRebootDialog($OrganizationName, $Script:TaskSequenceEnvironment.Value("_SMSTSPackageName"), $CustomTitle, $Message, $TimeoutInSeconds)
|
||||
}
|
||||
|
||||
function Show-TSSwapMediaDialog()
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Shows Task Sequence Swap Media Dialog.
|
||||
|
||||
.DESCRIPTION
|
||||
Shows Task Sequence Swap Media Dialog.
|
||||
|
||||
.PARAMETER TaskSequenceName
|
||||
Name of the Task Sequence
|
||||
.PARAMETER MediaNumber
|
||||
Media Number to insert
|
||||
.INPUTS
|
||||
- TaskSequenceName: String
|
||||
- CustomTitle: Long
|
||||
.OUTPUTS
|
||||
None
|
||||
.EXAMPLE
|
||||
Prompts to insert media #2 for the Task Sequence "My Task Sequence"
|
||||
Show-TSSwapMediaDialog -TaskSequenceName "My Task Sequence" -MediaNumber 2
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string] $TaskSequenceName,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[long] $MediaNumber
|
||||
)
|
||||
|
||||
Confirm-TSProgressUISetup
|
||||
|
||||
$Script:TaskSequenceProgressUi.ShowSwapMediaDialog($TaskSequenceName, $MediaNumber)
|
||||
}
|
||||
|
||||
#Encode a plain text string to a Base64 string
|
||||
Function ConvertTo-Base64
|
||||
{
|
||||
[CmdletBinding(SupportsShouldProcess=$False)]
|
||||
Param
|
||||
(
|
||||
[Parameter(Mandatory=$True, ValueFromPipeline=$True)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]$String
|
||||
)
|
||||
|
||||
$EncodedString = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($String))
|
||||
Write-Verbose -Message "$($NewLine)`"$($String)`" has been converted to the following Base64 encoded string `"$($EncodedString)`"$($NewLine)"
|
||||
|
||||
Return $EncodedString
|
||||
}
|
||||
|
||||
#Decode a Base64 string to a plain text string
|
||||
Function ConvertFrom-Base64
|
||||
{
|
||||
[CmdletBinding(SupportsShouldProcess=$False)]
|
||||
Param
|
||||
(
|
||||
[Parameter(Mandatory=$True, ValueFromPipeline=$True)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[ValidatePattern('^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$')]
|
||||
[String]$String
|
||||
)
|
||||
|
||||
$DecodedString = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($String))
|
||||
Write-Verbose -Message "$($NewLine)`"$($String)`" has been converted from the following Base64 encoded string `"$($DecodedString)`"$($NewLine)"
|
||||
|
||||
Return $DecodedString
|
||||
}
|
||||
+325
@@ -0,0 +1,325 @@
|
||||
#Requires -Version 3
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Removes an app package (.appx) from a Windows image using a regular expression that can be modified from the command line without changing the script code.
|
||||
|
||||
.DESCRIPTION
|
||||
Slightly more detailed description of what your function does
|
||||
|
||||
.PARAMETER ImagePath
|
||||
The directory path to the mounted windows image or the drive letter of a windows image that has been expanded onto a disk while in WindowsPE.
|
||||
|
||||
.PARAMETER PackagesToRemove
|
||||
A valid regular expression that matches the DisplayName(s) of the universal windows applications you wish to deprovision.
|
||||
|
||||
.PARAMETER LogDir
|
||||
A valid folder path. If the folder does not exist, it will be created. This parameter can also be specified by the alias "LogPath".
|
||||
|
||||
.PARAMETER ContinueOnError
|
||||
Ignore failures.
|
||||
|
||||
.EXAMPLE
|
||||
powershell.exe -ExecutionPolicy Bypass -NoProfile -NoLogo -File "%FolderPathContainingScript%\%ScriptName%.ps1" -ImagePath "%OSDisk%\\" -PackagesToRemove '.*Xbox.*|.*Alarms.*|.*Bing.*|.*Skype.*|.*Communi.*'
|
||||
|
||||
.NOTES
|
||||
Any useful tidbits
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/powershell/module/dism/remove-appxprovisionedpackage?view=win10-ps#:~:text=The%20Remove%2DAppxProvisionedPackage%20cmdlet%20removes,removed%20from%20existing%20user%20accounts.
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
Param
|
||||
(
|
||||
[Parameter(Mandatory=$False)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[ValidateScript({($_ -imatch '^[a-zA-Z][\:]\\{1,}$') -or ($_ -imatch '^[a-zA-Z][\:]\\.*?[^\\]$')})]
|
||||
[System.IO.DirectoryInfo]$ImagePath,
|
||||
|
||||
[Parameter(Mandatory=$False)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Regex]$PackagesToRemove = '.*Xbox.*|.*Alarms.*|.*Bing.*|.*Skype.*|.*Communi.*|.*Zune.*|.*Solit.*|.*Games.*|.*3D.*|.*Camera.*|.*Phone.*|.*Soundrec.*|.*Xboxapp.*|.*Feedback.*|.*Message.*|.*Messaging.*|.*Gethelp.*|.*Mobile.*|.*Mixed.*|.*Microsoft\.MicrosoftOfficeHub.*|.*OneNote.*|.*Microsoft\.People.*|.*Windows.*Defender.*|.*Movies.*|.*Microsoft\.ZuneMusic.*|.*Microsoft\.Windows\.HolographicFirstRun.*|.*Microsoft\.Oneconnect.*|.*Microsoft\.WindowsStore.*|.*Microsoft\.Getstarted.*|.*Microsoft\.MSPaint.*|.*Microsoft\.ZuneVideo.*|.*Microsoft\.PPIProjection.*|.*Microsoft\.WindowsMaps.*',
|
||||
|
||||
[Parameter(Mandatory=$False)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[ValidateScript({($_ -imatch '^[a-zA-Z][\:]\\.*?[^\\]$') -or ($_ -imatch "^\\(?:\\[^<>:`"/\\|?*]+)+$")})]
|
||||
[Alias('LogPath')]
|
||||
[System.IO.DirectoryInfo]$LogDir,
|
||||
|
||||
[Parameter(Mandatory=$False)]
|
||||
[Switch]$ContinueOnError
|
||||
)
|
||||
|
||||
#Define Default Action Preferences
|
||||
$Script:DebugPreference = 'SilentlyContinue'
|
||||
$Script:ErrorActionPreference = 'Stop'
|
||||
$Script:VerbosePreference = 'SilentlyContinue'
|
||||
$Script:WarningPreference = 'Continue'
|
||||
$Script:ConfirmPreference = 'None'
|
||||
|
||||
#Load WMI Classes
|
||||
$Baseboard = Get-WmiObject -Namespace "root\CIMv2" -Class "Win32_Baseboard" -Property * | Select-Object -Property *
|
||||
$Bios = Get-WmiObject -Namespace "root\CIMv2" -Class "Win32_Bios" -Property * | Select-Object -Property *
|
||||
$ComputerSystem = Get-WmiObject -Namespace "root\CIMv2" -Class "Win32_ComputerSystem" -Property * | Select-Object -Property *
|
||||
$OperatingSystem = Get-WmiObject -Namespace "root\CIMv2" -Class "Win32_OperatingSystem" -Property * | Select-Object -Property *
|
||||
|
||||
#Retrieve property values
|
||||
$OSArchitecture = $($OperatingSystem.OSArchitecture).Replace("-bit", "").Replace("32", "86").Insert(0,"x").ToUpper()
|
||||
|
||||
#Define variable(s)
|
||||
$DateTimeLogFormat = 'dddd, MMMM dd, yyyy hh:mm:ss tt' ###Monday, January 01, 2019 10:15:34 AM###
|
||||
[ScriptBlock]$GetCurrentDateTimeLogFormat = {(Get-Date).ToString($DateTimeLogFormat)}
|
||||
$DateTimeFileFormat = 'yyyyMMdd_hhmmsstt' ###20190403_115354AM###
|
||||
[ScriptBlock]$GetCurrentDateTimeFileFormat = {(Get-Date).ToString($DateTimeFileFormat)}
|
||||
[System.IO.FileInfo]$ScriptPath = "$($MyInvocation.MyCommand.Definition)"
|
||||
[System.IO.DirectoryInfo]$ScriptDirectory = "$($ScriptPath.Directory.FullName)"
|
||||
[System.IO.DirectoryInfo]$FunctionsDirectory = "$($ScriptDirectory.FullName)\Functions"
|
||||
[System.IO.DirectoryInfo]$ModulesDirectory = "$($ScriptDirectory.FullName)\Modules"
|
||||
[System.IO.DirectoryInfo]$ToolsDirectory = "$($ScriptDirectory.FullName)\Tools"
|
||||
[System.IO.DirectoryInfo]$ToolsDirectory_OSAll = "$($ToolsDirectory.FullName)\All"
|
||||
[System.IO.DirectoryInfo]$ToolsDirectory_OSArchSpecific = "$($ToolsDirectory.FullName)\$($OSArchitecture)"
|
||||
$IsWindowsPE = Test-Path -Path 'HKLM:\SYSTEM\ControlSet001\Control\MiniNT' -ErrorAction SilentlyContinue
|
||||
|
||||
#Log task sequence variables if debug mode is enabled within the task sequence
|
||||
Try
|
||||
{
|
||||
[System.__ComObject]$TSEnvironment = New-Object -ComObject "Microsoft.SMS.TSEnvironment"
|
||||
|
||||
If ($TSEnvironment -ine $Null)
|
||||
{
|
||||
$IsRunningTaskSequence = $True
|
||||
}
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$IsRunningTaskSequence = $False
|
||||
}
|
||||
|
||||
#Determine the default logging path if the parameter is not specified and is not assigned a default value
|
||||
If (($PSBoundParameters.ContainsKey('LogDir') -eq $False) -and ($LogDir -ieq $Null))
|
||||
{
|
||||
If ($IsRunningTaskSequence -eq $True)
|
||||
{
|
||||
[String]$_SMSTSLogPath = "$($TSEnvironment.Value('_SMSTSLogPath'))"
|
||||
|
||||
If ([String]::IsNullOrEmpty($_SMSTSLogPath) -eq $False)
|
||||
{
|
||||
[System.IO.DirectoryInfo]$TSLogDirectory = "$($_SMSTSLogPath)"
|
||||
}
|
||||
Else
|
||||
{
|
||||
[System.IO.DirectoryInfo]$TSLogDirectory = "$($Env:Windir)\Temp\SMSTSLog"
|
||||
}
|
||||
|
||||
[System.IO.DirectoryInfo]$LogDir = "$($TSLogDirectory.FullName)\$($ScriptPath.BaseName)"
|
||||
}
|
||||
ElseIf ($IsRunningTaskSequence -eq $False)
|
||||
{
|
||||
[System.IO.DirectoryInfo]$LogDir = "$($Env:Windir)\Logs\Software\$($ScriptPath.BaseName)"
|
||||
}
|
||||
}
|
||||
|
||||
#Start transcripting (Logging)
|
||||
Try
|
||||
{
|
||||
[System.IO.FileInfo]$ScriptLogPath = "$($LogDir.FullName)\$($ScriptPath.BaseName)_$($GetCurrentDateTimeFileFormat.Invoke()).log"
|
||||
If ($ScriptLogPath.Directory.Exists -eq $False) {[Void][System.IO.Directory]::CreateDirectory($ScriptLogPath.Directory.FullName)}
|
||||
Start-Transcript -Path "$($ScriptLogPath.FullName)" -IncludeInvocationHeader -Force -Verbose
|
||||
}
|
||||
Catch
|
||||
{
|
||||
If ([String]::IsNullOrEmpty($_.Exception.Message)) {$ExceptionMessage = "$($_.Exception.Errors.Message)"} Else {$ExceptionMessage = "$($_.Exception.Message)"}
|
||||
|
||||
$ErrorMessage = "[Error Message: $($ExceptionMessage)][ScriptName: $($_.InvocationInfo.ScriptName)][Line Number: $($_.InvocationInfo.ScriptLineNumber)][Line Position: $($_.InvocationInfo.OffsetInLine)][Code: $($_.InvocationInfo.Line.Trim())]"
|
||||
Write-Error -Message "$($ErrorMessage)"
|
||||
}
|
||||
|
||||
#Log any useful information
|
||||
$LogMessage = "IsWindowsPE = $($IsWindowsPE.ToString())"
|
||||
Write-Verbose -Message "$($LogMessage)" -Verbose
|
||||
|
||||
$LogMessage = "Script Path = $($ScriptPath.FullName)"
|
||||
Write-Verbose -Message "$($LogMessage)" -Verbose
|
||||
|
||||
$LogMessage = "Packages To Remove = $($PackagesToRemove.ToString())"
|
||||
Write-Verbose -Message "$($LogMessage)" -Verbose
|
||||
|
||||
$DirectoryVariables = Get-Variable | Where-Object {($_.Value -ine $Null) -and (($_.Value -is [System.IO.DirectoryInfo]) -or ($_.Value -is [System.IO.DirectoryInfo[]]))}
|
||||
|
||||
ForEach ($DirectoryVariable In $DirectoryVariables)
|
||||
{
|
||||
$LogMessage = "$($DirectoryVariable.Name) = $($DirectoryVariable.Value.FullName -Join ', ')"
|
||||
Write-Verbose -Message "$($LogMessage)" -Verbose
|
||||
}
|
||||
|
||||
#region Import Dependency Modules
|
||||
$Modules = Get-Module -Name "$($ModulesDirectory.FullName)\*" -ListAvailable -ErrorAction Stop
|
||||
|
||||
$ModuleGroups = $Modules | Group-Object -Property @('Name')
|
||||
|
||||
ForEach ($ModuleGroup In $ModuleGroups)
|
||||
{
|
||||
$LatestModuleVersion = $ModuleGroup.Group | Sort-Object -Property @('Version') -Descending | Select-Object -First 1
|
||||
|
||||
If ($LatestModuleVersion -ine $Null)
|
||||
{
|
||||
$LogMessage = "Attempting to import dependency powershell module `"$($LatestModuleVersion.Name) [Version: $($LatestModuleVersion.Version.ToString())]`". Please Wait..."
|
||||
Write-Verbose -Message "$($LogMessage)" -Verbose
|
||||
Import-Module -Name "$($LatestModuleVersion.Path)" -Global -DisableNameChecking -Force -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Dot Source Dependency Scripts
|
||||
#Dot source any additional script(s) from the functions directory. This will provide flexibility to add additional functions without adding complexity to the main script and to maintain function consistency.
|
||||
Try
|
||||
{
|
||||
If ($FunctionsDirectory.Exists -eq $True)
|
||||
{
|
||||
[String[]]$AdditionalFunctionsFilter = "*.ps1"
|
||||
|
||||
$AdditionalFunctionsToImport = Get-ChildItem -Path "$($FunctionsDirectory.FullName)" -Include ($AdditionalFunctionsFilter) -Recurse -Force | Where-Object {($_ -is [System.IO.FileInfo])}
|
||||
|
||||
$AdditionalFunctionsToImportCount = $AdditionalFunctionsToImport | Measure-Object | Select-Object -ExpandProperty Count
|
||||
|
||||
If ($AdditionalFunctionsToImportCount -gt 0)
|
||||
{
|
||||
ForEach ($AdditionalFunctionToImport In $AdditionalFunctionsToImport)
|
||||
{
|
||||
Try
|
||||
{
|
||||
$LogMessage = "Attempting to dot source dependency script `"$($AdditionalFunctionToImport.Name)`". Please Wait...`r`n`r`nScript Path: `"$($AdditionalFunctionToImport.FullName)`""
|
||||
Write-Verbose -Message "$($LogMessage)" -Verbose
|
||||
|
||||
. "$($AdditionalFunctionToImport.FullName)"
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$ErrorMessage = "[Error Message: $($_.Exception.Message)]`r`n`r`n[ScriptName: $($_.InvocationInfo.ScriptName)]`r`n[Line Number: $($_.InvocationInfo.ScriptLineNumber)]`r`n[Line Position: $($_.InvocationInfo.OffsetInLine)]`r`n[Code: $($_.InvocationInfo.Line.Trim())]"
|
||||
Write-Error -Message "$($ErrorMessage)" -Verbose
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Catch
|
||||
{
|
||||
$ErrorMessage = "[Error Message: $($_.Exception.Message)]`r`n`r`n[ScriptName: $($_.InvocationInfo.ScriptName)]`r`n[Line Number: $($_.InvocationInfo.ScriptLineNumber)]`r`n[Line Position: $($_.InvocationInfo.OffsetInLine)]`r`n[Code: $($_.InvocationInfo.Line.Trim())]"
|
||||
Write-Error -Message "$($ErrorMessage)" -Verbose
|
||||
}
|
||||
#endregion
|
||||
|
||||
#Perform script action(s)
|
||||
Try
|
||||
{
|
||||
#Tasks defined within this block will only execute if a task sequence is running
|
||||
If (($IsRunningTaskSequence -eq $True))
|
||||
{
|
||||
If (($PSBoundParameters.ContainsKey('ImagePath') -eq $False) -and ($ImagePath -eq $Null))
|
||||
{
|
||||
[System.IO.DirectoryInfo]$ImagePath = "$($TSEnvironment.Value('OSDisk'))\"
|
||||
}
|
||||
}
|
||||
|
||||
#Tasks defined here will execute whether only if a task sequence is not running
|
||||
If ($IsRunningTaskSequence -eq $False)
|
||||
{
|
||||
$WarningMessage = "There is no task sequence running.`r`n"
|
||||
Write-Warning -Message "$($WarningMessage)" -Verbose
|
||||
}
|
||||
#Remove Metro Application(s)
|
||||
If ($ImagePath -ine $Null)
|
||||
{
|
||||
$LogMessage = "ImagePath = $($ImagePath.FullName)"
|
||||
Write-Verbose -Message "$($LogMessage)" -Verbose
|
||||
|
||||
$AppXProvisionedPackages = (Get-AppxProvisionedPackage -Path "$($ImagePath.FullName)" | Select-Object * | Sort-Object DisplayName)
|
||||
|
||||
$AppXProvisionedPackagesToRemove = $AppXProvisionedPackages | Where-Object {($_.DisplayName -imatch $PackagesToRemove.ToString())}
|
||||
|
||||
$AppXProvisionedPackagesToRemoveCount = $AppXProvisionedPackagesToRemove | Measure-Object | Select-Object -ExpandProperty Count
|
||||
|
||||
$LogMessage = "Found $($AppXProvisionedPackagesToRemoveCount.ToString()) Appx provisioned package(s) to remove."
|
||||
Write-Verbose -Message "$($LogMessage)" -Verbose
|
||||
|
||||
$Counter = 1
|
||||
|
||||
ForEach ($AppXProvisionedPackageToRemove In $AppXProvisionedPackagesToRemove)
|
||||
{
|
||||
Try
|
||||
{
|
||||
[Int]$ProgressID = 1
|
||||
[String]$ActivityMessage = "Remove-AppxProvisionedPackage $($AppXProvisionedPackageToRemove.DisplayName) [Version: $($AppXProvisionedPackageToRemove.Version)]"
|
||||
[String]$StatusMessage = "Attempting to remove $($AppXProvisionedPackageToRemove.DisplayName) $($AppXProvisionedPackageToRemove.Version) ($($Counter.ToString()) of $($AppXProvisionedPackagesToRemoveCount.ToString()))"
|
||||
[Int]$PercentComplete = (($Counter / $AppXProvisionedPackagesToRemoveCount) * 100)
|
||||
|
||||
$LogMessage = "$($StatusMessage). Please Wait..."
|
||||
Write-Verbose -Message "$($LogMessage)" -Verbose
|
||||
|
||||
Write-Progress -ID ($ProgressID) -Activity ($ActivityMessage) -Status ($StatusMessage) -PercentComplete ($PercentComplete)
|
||||
|
||||
[System.IO.FileInfo]$AppXProvisionedPackageToRemoveLogPath = "$($LogDir.FullName)\Remove-AppxProvisionedPackage\$($AppXProvisionedPackageToRemove.DisplayName).log"
|
||||
|
||||
If ($AppXProvisionedPackageToRemoveLogPath.Directory.Exists -eq $False) {$Null = [System.IO.Directory]::CreateDirectory($AppXProvisionedPackageToRemoveLogPath.Directory.FullName)}
|
||||
|
||||
$LogMessage = "Log Path = `"$($AppXProvisionedPackageToRemoveLogPath.FullName)`""
|
||||
Write-Verbose -Message "$($LogMessage)" -Verbose
|
||||
|
||||
$RemoveAppXProvisionedPackage = Remove-AppxProvisionedPackage -PackageName "$($AppXProvisionedPackageToRemove.PackageName)" -Path "$($ImagePath.FullName)" -LogPath "$($AppXProvisionedPackageToRemoveLogPath.FullName)" -LogLevel 'Errors' -Verbose
|
||||
|
||||
If ($? -eq $True)
|
||||
{
|
||||
$LogMessage = "Removal of the `"$($AppXProvisionedPackageToRemove.DisplayName)`" AppX provisioned package was successful!"
|
||||
Write-Verbose -Message "$($LogMessage)" -Verbose
|
||||
}
|
||||
ElseIf ($? -eq $False)
|
||||
{
|
||||
$LogMessage = "Removal of the `"$($AppXProvisionedPackageToRemove.DisplayName)`" AppX provisioned package was unsuccessful!"
|
||||
Write-Error -Message "$($LogMessage)" -Verbose
|
||||
}
|
||||
}
|
||||
Catch
|
||||
{
|
||||
If ([String]::IsNullOrEmpty($_.Exception.Message)) {$ExceptionMessage = "$($_.Exception.Errors.Message)"} Else {$ExceptionMessage = "$($_.Exception.Message)"}
|
||||
|
||||
$ErrorMessage = "[Error Message: $($ExceptionMessage)][ScriptName: $($_.InvocationInfo.ScriptName)][Line Number: $($_.InvocationInfo.ScriptLineNumber)][Line Position: $($_.InvocationInfo.OffsetInLine)][Code: $($_.InvocationInfo.Line.Trim())]"
|
||||
Write-Error -Message "$($ErrorMessage)" -Verbose
|
||||
}
|
||||
|
||||
$Counter++
|
||||
}
|
||||
}
|
||||
Else
|
||||
{
|
||||
$ErrorMessage = "[Error Message: A valid image path was either not specified or contains an invalid value.]"
|
||||
Throw "$($ErrorMessage)"
|
||||
}
|
||||
|
||||
#Stop transcripting (Logging)
|
||||
Try
|
||||
{
|
||||
Stop-Transcript -Verbose
|
||||
}
|
||||
Catch
|
||||
{
|
||||
If ([String]::IsNullOrEmpty($_.Exception.Message)) {$ExceptionMessage = "$($_.Exception.Errors.Message)"} Else {$ExceptionMessage = "$($_.Exception.Message)"}
|
||||
|
||||
$ErrorMessage = "[Error Message: $($ExceptionMessage)][ScriptName: $($_.InvocationInfo.ScriptName)][Line Number: $($_.InvocationInfo.ScriptLineNumber)][Line Position: $($_.InvocationInfo.OffsetInLine)][Code: $($_.InvocationInfo.Line.Trim())]"
|
||||
Write-Error -Message "$($ErrorMessage)"
|
||||
}
|
||||
}
|
||||
Catch
|
||||
{
|
||||
If ([String]::IsNullOrEmpty($_.Exception.Message)) {$ExceptionMessage = "$($_.Exception.Errors.Message -Join "`r`n`r`n")"} Else {$ExceptionMessage = "$($_.Exception.Message)"}
|
||||
|
||||
$ErrorMessage = "[Error Message: $($ExceptionMessage)]`r`n`r`n[ScriptName: $($_.InvocationInfo.ScriptName)]`r`n[Line Number: $($_.InvocationInfo.ScriptLineNumber)]`r`n[Line Position: $($_.InvocationInfo.OffsetInLine)]`r`n[Code: $($_.InvocationInfo.Line.Trim())]`r`n"
|
||||
Write-Error -Message "$($ErrorMessage)"
|
||||
|
||||
Stop-Transcript -Verbose
|
||||
|
||||
If ($ContinueOnError.IsPresent -eq $False)
|
||||
{
|
||||
[System.Environment]::Exit(50)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
###
|
||||
@@ -0,0 +1 @@
|
||||
###
|
||||
Reference in New Issue
Block a user