winutil/functions/private/Invoke-MicroWin-Helper.ps1
CodingWonders 70f3ed541f
Fixed Ventoy drive copy typo and began conversion of DISM commands into DISM cmdlets (#1727)
* Fixed Ventoy drive copy typo

* DISM cmdlet Update (Part 1)

Began replacing basic DISM commands with cmdlets from the DISM module.

This change only affects the mount, unmount, and export operations. All other operations still use DISM

---------

Co-authored-by: Chris Titus <contact@christitus.com>
2024-03-28 10:50:49 -05:00

657 lines
23 KiB
PowerShell

function Invoke-MicroWin-Helper {
<#
.SYNOPSIS
checking unit tests
.PARAMETER Name
no parameters
.EXAMPLE
placeholder
#>
}
function Test-CompatibleImage() {
<#
.SYNOPSIS
Checks the version of a Windows image and determines whether or not it is compatible with a specific feature depending on a desired version
.PARAMETER Name
imgVersion - The version of the Windows image
desiredVersion - The version to compare the image version with
#>
param
(
[Parameter(Mandatory = $true, Position=0)] [string] $imgVersion,
[Parameter(Mandatory = $true, Position=1)] [Version] $desiredVersion
)
try {
$version = [Version]$imgVersion
return $version -ge $desiredVersion
} catch {
return $False
}
}
function Remove-Features([switch] $dumpFeatures = $false, [switch] $keepDefender = $false) {
<#
.SYNOPSIS
Removes certain features from ISO image
.PARAMETER Name
dumpFeatures - Dumps all features found in the ISO into a file called allfeaturesdump.txt. This file can be examined and used to decide what to remove.
keepDefender - Should Defender be removed from the ISO?
.EXAMPLE
Remove-Features -keepDefender:$false
#>
$appxlist = dism /English /image:$scratchDir /Get-Features | Select-String -Pattern "Feature Name : " -CaseSensitive -SimpleMatch
$appxlist = $appxlist -split "Feature Name : " | Where-Object {$_}
if ($dumpFeatures)
{
$appxlist > allfeaturesdump.txt
}
$appxlist = $appxlist | Where-Object {
$_ -NotLike "*Printing*" -AND
$_ -NotLike "*TelnetClient*" -AND
$_ -NotLike "*PowerShell*" -AND
$_ -NotLike "*NetFx*"
}
if ($keepDefender) { $appxlist = $appxlist | Where-Object { $_ -NotLike "*Defender*" }}
foreach($feature in $appxlist)
{
$status = "Removing feature $feature"
Write-Progress -Activity "Removing features" -Status $status -PercentComplete ($counter++/$appxlist.Count*100)
Write-Debug "Removing feature $feature"
# dism /image:$scratchDir /Disable-Feature /FeatureName:$feature /Remove /NoRestart > $null
}
Write-Progress -Activity "Removing features" -Status "Ready" -Completed
}
function Remove-Packages
{
$appxlist = dism /English /Image:$scratchDir /Get-Packages | Select-String -Pattern "Package Identity : " -CaseSensitive -SimpleMatch
$appxlist = $appxlist -split "Package Identity : " | Where-Object {$_}
$appxlist = $appxlist | Where-Object {
$_ -NotLike "*ApplicationModel*" -AND
$_ -NotLike "*indows-Client-LanguagePack*" -AND
$_ -NotLike "*LanguageFeatures-Basic*" -AND
$_ -NotLike "*Package_for_ServicingStack*" -AND
$_ -NotLike "*.NET*" -AND
$_ -NotLike "*Store*" -AND
$_ -NotLike "*VCLibs*" -AND
$_ -NotLike "*AAD.BrokerPlugin",
$_ -NotLike "*LockApp*" -AND
$_ -NotLike "*Notepad*" -AND
$_ -NotLike "*immersivecontrolpanel*" -AND
$_ -NotLike "*ContentDeliveryManager*" -AND
$_ -NotLike "*PinningConfirMationDialog*" -AND
$_ -NotLike "*SecHealthUI*" -AND
$_ -NotLike "*SecureAssessmentBrowser*" -AND
$_ -NotLike "*PrintDialog*" -AND
$_ -NotLike "*AssignedAccessLockApp*" -AND
$_ -NotLike "*OOBENetworkConnectionFlow*" -AND
$_ -NotLike "*Apprep.ChxApp*" -AND
$_ -NotLike "*CBS*" -AND
$_ -NotLike "*OOBENetworkCaptivePortal*" -AND
$_ -NotLike "*PeopleExperienceHost*" -AND
$_ -NotLike "*ParentalControls*" -AND
$_ -NotLike "*Win32WebViewHost*" -AND
$_ -NotLike "*InputApp*" -AND
$_ -NotLike "*AccountsControl*" -AND
$_ -NotLike "*AsyncTextService*" -AND
$_ -NotLike "*CapturePicker*" -AND
$_ -NotLike "*CredDialogHost*" -AND
$_ -NotLike "*BioEnrollMent*" -AND
$_ -NotLike "*ShellExperienceHost*" -AND
$_ -NotLike "*DesktopAppInstaller*" -AND
$_ -NotLike "*WebMediaExtensions*" -AND
$_ -NotLike "*WMIC*" -AND
$_ -NotLike "*UI.XaML*"
}
foreach ($appx in $appxlist)
{
$status = "Removing $appx"
Write-Progress -Activity "Removing Apps" -Status $status -PercentComplete ($counter++/$appxlist.Count*100)
dism /English /image:$scratchDir /Remove-Package /PackageName:$appx /NoRestart
}
Write-Progress -Activity "Removing Apps" -Status "Ready" -Completed
}
function Remove-ProvisionedPackages([switch] $keepSecurity = $false)
{
<#
.SYNOPSIS
Removes AppX packages from a Windows image during MicroWin processing
.PARAMETER Name
keepSecurity - Boolean that determines whether to keep "Microsoft.SecHealthUI" (Windows Security) in the Windows image
.EXAMPLE
Remove-ProvisionedPackages -keepSecurity:$false
#>
$appxProvisionedPackages = Get-AppxProvisionedPackage -Path "$($scratchDir)" | Where-Object {
$_.PackageName -NotLike "*AppInstaller*" -AND
$_.PackageName -NotLike "*Store*" -and
$_.PackageName -NotLike "*dism*" -and
$_.PackageName -NotLike "*Foundation*" -and
$_.PackageName -NotLike "*FodMetadata*" -and
$_.PackageName -NotLike "*LanguageFeatures*" -and
$_.PackageName -NotLike "*Notepad*" -and
$_.PackageName -NotLike "*Printing*" -and
$_.PackageName -NotLike "*Wifi*" -and
$_.PackageName -NotLike "*Foundation*"
}
if ($?)
{
if ($keepSecurity) { $appxProvisionedPackages = $appxProvisionedPackages | Where-Object { $_.PackageName -NotLike "*SecHealthUI*" }}
$counter = 0
foreach ($appx in $appxProvisionedPackages)
{
$status = "Removing Provisioned $($appx.PackageName)"
Write-Progress -Activity "Removing Provisioned Apps" -Status $status -PercentComplete ($counter++/$appxProvisionedPackages.Count*100)
dism /English /image:$scratchDir /Remove-ProvisionedAppxPackage /PackageName:$($appx.PackageName) /NoRestart
}
Write-Progress -Activity "Removing Provisioned Apps" -Status "Ready" -Completed
}
else
{
Write-Host "Could not get Provisioned App information. Skipping process..."
}
}
function Copy-ToUSB([string] $fileToCopy)
{
foreach ($volume in Get-Volume) {
if ($volume -and $volume.FileSystemLabel -ieq "ventoy") {
$destinationPath = "$($volume.DriveLetter):\"
#Copy-Item -Path $fileToCopy -Destination $destinationPath -Force
# Get the total size of the file
$totalSize = (Get-Item $fileToCopy).length
Copy-Item -Path $fileToCopy -Destination $destinationPath -Verbose -Force -Recurse -Container -PassThru |
ForEach-Object {
# Calculate the percentage completed
$completed = ($_.BytesTransferred / $totalSize) * 100
# Display the progress bar
Write-Progress -Activity "Copying File" -Status "Progress" -PercentComplete $completed -CurrentOperation ("{0:N2} MB / {1:N2} MB" -f ($_.BytesTransferred / 1MB), ($totalSize / 1MB))
}
Write-Host "File copied to Ventoy drive $($volume.DriveLetter)"
return
}
}
Write-Host "Ventoy USB Key is not inserted"
}
function Remove-FileOrDirectory([string] $pathToDelete, [string] $mask = "", [switch] $Directory = $false)
{
if(([string]::IsNullOrEmpty($pathToDelete))) { return }
if (-not (Test-Path -Path "$($pathToDelete)")) { return }
$yesNo = Get-LocalizedYesNo
Write-Host "[INFO] In Your local takeown expects '$($yesNo[0])' as a Yes answer."
# Specify the path to the directory
# $directoryPath = "$($scratchDir)\Windows\System32\LogFiles\WMI\RtBackup"
# takeown /a /r /d $yesNo[0] /f "$($directoryPath)" > $null
# icacls "$($directoryPath)" /q /c /t /reset > $null
# icacls $directoryPath /setowner "*S-1-5-32-544"
# icacls $directoryPath /grant "*S-1-5-32-544:(OI)(CI)F" /t /c /q
# Remove-Item -Path $directoryPath -Recurse -Force
# # Grant full control to BUILTIN\Administrators using icacls
# $directoryPath = "$($scratchDir)\Windows\System32\WebThreatDefSvc"
# takeown /a /r /d $yesNo[0] /f "$($directoryPath)" > $null
# icacls "$($directoryPath)" /q /c /t /reset > $null
# icacls $directoryPath /setowner "*S-1-5-32-544"
# icacls $directoryPath /grant "*S-1-5-32-544:(OI)(CI)F" /t /c /q
# Remove-Item -Path $directoryPath -Recurse -Force
$itemsToDelete = [System.Collections.ArrayList]::new()
if ($mask -eq "")
{
Write-Debug "Adding $($pathToDelete) to array."
[void]$itemsToDelete.Add($pathToDelete)
}
else
{
Write-Debug "Adding $($pathToDelete) to array and mask is $($mask)"
if ($Directory) { $itemsToDelete = Get-ChildItem $pathToDelete -Include $mask -Recurse -Directory }
else { $itemsToDelete = Get-ChildItem $pathToDelete -Include $mask -Recurse }
}
foreach($itemToDelete in $itemsToDelete)
{
$status = "Deleting $($itemToDelete)"
Write-Progress -Activity "Removing Items" -Status $status -PercentComplete ($counter++/$itemsToDelete.Count*100)
if (Test-Path -Path "$($itemToDelete)" -PathType Container)
{
$status = "Deleting directory: $($itemToDelete)"
takeown /r /d $yesNo[0] /a /f "$($itemToDelete)"
icacls "$($itemToDelete)" /q /c /t /reset
icacls $itemToDelete /setowner "*S-1-5-32-544"
icacls $itemToDelete /grant "*S-1-5-32-544:(OI)(CI)F" /t /c /q
Remove-Item -Force -Recurse "$($itemToDelete)"
}
elseif (Test-Path -Path "$($itemToDelete)" -PathType Leaf)
{
$status = "Deleting file: $($itemToDelete)"
takeown /a /f "$($itemToDelete)"
icacls "$($itemToDelete)" /q /c /t /reset
icacls "$($itemToDelete)" /setowner "*S-1-5-32-544"
icacls "$($itemToDelete)" /grant "*S-1-5-32-544:(OI)(CI)F" /t /c /q
Remove-Item -Force "$($itemToDelete)"
}
}
Write-Progress -Activity "Removing Items" -Status "Ready" -Completed
}
function New-Unattend {
# later if we wont to remove even more bloat EU requires MS to remove everything from English(world)
# Below is an example how to do it we probably should create a drop down with common locals
# <settings pass="specialize">
# <!-- Specify English (World) locale -->
# <component name="Microsoft-Windows-International-Core" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
# <SetupUILanguage>
# <UILanguage>en-US</UILanguage>
# </SetupUILanguage>
# <InputLocale>en-US</InputLocale>
# <SystemLocale>en-US</SystemLocale>
# <UILanguage>en-US</UILanguage>
# <UserLocale>en-US</UserLocale>
# </component>
# </settings>
# <settings pass="oobeSystem">
# <!-- Specify English (World) locale -->
# <component name="Microsoft-Windows-International-Core" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
# <InputLocale>en-US</InputLocale>
# <SystemLocale>en-US</SystemLocale>
# <UILanguage>en-US</UILanguage>
# <UserLocale>en-US</UserLocale>
# </component>
# </settings>
# using here string to embedd unattend
# <RunSynchronousCommand wcm:action="add">
# <Order>1</Order>
# <Path>net user administrator /active:yes</Path>
# </RunSynchronousCommand>
# this section doesn't work in win10/????
# <settings pass="specialize">
# <component name="Microsoft-Windows-SQMApi" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
# <CEIPEnabled>0</CEIPEnabled>
# </component>
# <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
# <ConfigureChatAutoInstall>false</ConfigureChatAutoInstall>
# </component>
# </settings>
$unattend = @'
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend"
xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<#REPLACEME#>
<settings pass="auditUser">
<component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RunSynchronous>
<RunSynchronousCommand wcm:action="add">
<Order>1</Order>
<CommandLine>CMD /C echo LAU GG&gt;C:\Windows\LogAuditUser.txt</CommandLine>
<Description>StartMenu</Description>
</RunSynchronousCommand>
</RunSynchronous>
</component>
</settings>
<settings pass="oobeSystem">
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<OOBE>
<HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
<SkipUserOOBE>false</SkipUserOOBE>
<SkipMachineOOBE>false</SkipMachineOOBE>
<HideOnlineAccountScreens>true</HideOnlineAccountScreens>
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
<HideEULAPage>true</HideEULAPage>
<ProtectYourPC>3</ProtectYourPC>
</OOBE>
<FirstLogonCommands>
<SynchronousCommand wcm:action="add">
<Order>1</Order>
<CommandLine>cmd.exe /c echo 23&gt;c:\windows\csup.txt</CommandLine>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<Order>2</Order>
<CommandLine>CMD /C echo GG&gt;C:\Windows\LogOobeSystem.txt</CommandLine>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<Order>3</Order>
<CommandLine>powershell -ExecutionPolicy Bypass -File c:\windows\FirstStartup.ps1</CommandLine>
</SynchronousCommand>
</FirstLogonCommands>
</component>
</settings>
</unattend>
'@
$specPass = @'
<settings pass="specialize">
<component name="Microsoft-Windows-SQMApi" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CEIPEnabled>0</CEIPEnabled>
</component>
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ConfigureChatAutoInstall>false</ConfigureChatAutoInstall>
</component>
</settings>
'@
if ((Test-CompatibleImage $imgVersion $([System.Version]::new(10,0,22000,1))) -eq $false)
{
# Replace the placeholder text with an empty string to make it valid for Windows 10 Setup
$unattend = $unattend.Replace("<#REPLACEME#>", "").Trim()
}
else
{
# Replace the placeholder text with the Specialize pass
$unattend = $unattend.Replace("<#REPLACEME#>", $specPass).Trim()
}
$unattend | Out-File -FilePath "$env:temp\unattend.xml" -Force -Encoding utf8
}
function New-CheckInstall {
# using here string to embedd firstrun
$checkInstall = @'
@echo off
if exist "C:\windows\cpu.txt" (
echo C:\windows\cpu.txt exists
) else (
echo C:\windows\cpu.txt does not exist
)
if exist "C:\windows\SerialNumber.txt" (
echo C:\windows\SerialNumber.txt exists
) else (
echo C:\windows\SerialNumber.txt does not exist
)
if exist "C:\unattend.xml" (
echo C:\unattend.xml exists
) else (
echo C:\unattend.xml does not exist
)
if exist "C:\Windows\Setup\Scripts\SetupComplete.cmd" (
echo C:\Windows\Setup\Scripts\SetupComplete.cmd exists
) else (
echo C:\Windows\Setup\Scripts\SetupComplete.cmd does not exist
)
if exist "C:\Windows\Panther\unattend.xml" (
echo C:\Windows\Panther\unattend.xml exists
) else (
echo C:\Windows\Panther\unattend.xml does not exist
)
if exist "C:\Windows\System32\Sysprep\unattend.xml" (
echo C:\Windows\System32\Sysprep\unattend.xml exists
) else (
echo C:\Windows\System32\Sysprep\unattend.xml does not exist
)
if exist "C:\Windows\FirstStartup.ps1" (
echo C:\Windows\FirstStartup.ps1 exists
) else (
echo C:\Windows\FirstStartup.ps1 does not exist
)
if exist "C:\Windows\winutil.ps1" (
echo C:\Windows\winutil.ps1 exists
) else (
echo C:\Windows\winutil.ps1 does not exist
)
if exist "C:\Windows\LogSpecialize.txt" (
echo C:\Windows\LogSpecialize.txt exists
) else (
echo C:\Windows\LogSpecialize.txt does not exist
)
if exist "C:\Windows\LogAuditUser.txt" (
echo C:\Windows\LogAuditUser.txt exists
) else (
echo C:\Windows\LogAuditUser.txt does not exist
)
if exist "C:\Windows\LogOobeSystem.txt" (
echo C:\Windows\LogOobeSystem.txt exists
) else (
echo C:\Windows\LogOobeSystem.txt does not exist
)
if exist "c:\windows\csup.txt" (
echo c:\windows\csup.txt exists
) else (
echo c:\windows\csup.txt does not exist
)
if exist "c:\windows\LogFirstRun.txt" (
echo c:\windows\LogFirstRun.txt exists
) else (
echo c:\windows\LogFirstRun.txt does not exist
)
'@
$checkInstall | Out-File -FilePath "$env:temp\checkinstall.cmd" -Force -Encoding Ascii
}
function New-FirstRun {
# using here string to embedd firstrun
$firstRun = @'
# Set the global error action preference to continue
$ErrorActionPreference = "Continue"
function Remove-RegistryValue
{
param (
[Parameter(Mandatory = $true)]
[string]$RegistryPath,
[Parameter(Mandatory = $true)]
[string]$ValueName
)
# Check if the registry path exists
if (Test-Path -Path $RegistryPath)
{
$registryValue = Get-ItemProperty -Path $RegistryPath -Name $ValueName -ErrorAction SilentlyContinue
# Check if the registry value exists
if ($registryValue)
{
# Remove the registry value
Remove-ItemProperty -Path $RegistryPath -Name $ValueName -Force
Write-Host "Registry value '$ValueName' removed from '$RegistryPath'."
}
else
{
Write-Host "Registry value '$ValueName' not found in '$RegistryPath'."
}
}
else
{
Write-Host "Registry path '$RegistryPath' not found."
}
}
function Stop-UnnecessaryServices
{
$servicesToExclude = @(
"AudioSrv",
"AudioEndpointBuilder",
"BFE",
"BITS",
"BrokerInfrastructure",
"CDPSvc",
"CDPUserSvc_dc2a4",
"CoreMessagingRegistrar",
"CryptSvc",
"DPS",
"DcomLaunch",
"Dhcp",
"DispBrokerDesktopSvc",
"Dnscache",
"DoSvc",
"DusmSvc",
"EventLog",
"EventSystem",
"FontCache",
"LSM",
"LanmanServer",
"LanmanWorkstation",
"MapsBroker",
"MpsSvc",
"OneSyncSvc_dc2a4",
"Power",
"ProfSvc",
"RpcEptMapper",
"RpcSs",
"SCardSvr",
"SENS",
"SamSs",
"Schedule",
"SgrmBroker",
"ShellHWDetection",
"Spooler",
"SysMain",
"SystemEventsBroker",
"TextInputManagementService",
"Themes",
"TrkWks",
"UserManager",
"VGAuthService",
"VMTools",
"WSearch",
"Wcmsvc",
"WinDefend",
"Winmgmt",
"WlanSvc",
"WpnService",
"WpnUserService_dc2a4",
"cbdhsvc_dc2a4",
"edgeupdate",
"gpsvc",
"iphlpsvc",
"mpssvc",
"nsi",
"sppsvc",
"tiledatamodelsvc",
"vm3dservice",
"webthreatdefusersvc_dc2a4",
"wscsvc"
)
$runningServices = Get-Service | Where-Object { $servicesToExclude -notcontains $_.Name }
foreach($service in $runningServices)
{
Stop-Service -Name $service.Name -PassThru
Set-Service $service.Name -StartupType Manual
"Stopping service $($service.Name)" | Out-File -FilePath c:\windows\LogFirstRun.txt -Append -NoClobber
}
}
"FirstStartup has worked" | Out-File -FilePath c:\windows\LogFirstRun.txt -Append -NoClobber
$Theme = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize"
Set-ItemProperty -Path $Theme -Name AppsUseLightTheme -Value 1
Set-ItemProperty -Path $Theme -Name SystemUsesLightTheme -Value 1
# figure this out later how to set updates to security only
#Import-Module -Name PSWindowsUpdate;
#Stop-Service -Name wuauserv
#Set-WUSettings -MicrosoftUpdateEnabled -AutoUpdateOption 'Never'
#Start-Service -Name wuauserv
Stop-UnnecessaryServices
$taskbarPath = "$env:AppData\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar"
# Delete all files on the Taskbar
Get-ChildItem -Path $taskbarPath -File | Remove-Item -Force
Remove-RegistryValue -RegistryPath "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband" -ValueName "FavoritesRemovedChanges"
Remove-RegistryValue -RegistryPath "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband" -ValueName "FavoritesChanges"
Remove-RegistryValue -RegistryPath "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband" -ValueName "Favorites"
# Stop-Process -Name explorer -Force
$process = Get-Process -Name "explorer"
Stop-Process -InputObject $process
# Wait for the process to exit
Wait-Process -InputObject $process
Start-Sleep -Seconds 3
# Delete Edge Icon from the desktop
$edgeShortcutFiles = Get-ChildItem -Path $desktopPath -Filter "*Edge*.lnk"
# Check if Edge shortcuts exist on the desktop
if ($edgeShortcutFiles)
{
foreach ($shortcutFile in $edgeShortcutFiles)
{
# Remove each Edge shortcut
Remove-Item -Path $shortcutFile.FullName -Force
Write-Host "Edge shortcut '$($shortcutFile.Name)' removed from the desktop."
}
}
Remove-Item -Path "$env:USERPROFILE\Desktop\*.lnk"
Remove-Item -Path "C:\Users\Default\Desktop\*.lnk"
# ************************************************
# Create WinUtil shortcut on the desktop
#
$desktopPath = "$($env:USERPROFILE)\Desktop"
# Specify the target PowerShell command
$command = "powershell.exe -NoProfile -ExecutionPolicy Bypass -Command 'irm https://christitus.com/win | iex'"
# Specify the path for the shortcut
$shortcutPath = Join-Path $desktopPath 'winutil.lnk'
# Create a shell object
$shell = New-Object -ComObject WScript.Shell
# Create a shortcut object
$shortcut = $shell.CreateShortcut($shortcutPath)
if (Test-Path -Path "c:\Windows\cttlogo.png")
{
$shortcut.IconLocation = "c:\Windows\cttlogo.png"
}
# Set properties of the shortcut
$shortcut.TargetPath = "powershell.exe"
$shortcut.Arguments = "-NoProfile -ExecutionPolicy Bypass -Command `"$command`""
# Save the shortcut
$shortcut.Save()
# Make the shortcut have 'Run as administrator' property on
$bytes = [System.IO.File]::ReadAllBytes($shortcutPath)
# Set byte value at position 0x15 in hex, or 21 in decimal, from the value 0x00 to 0x20 in hex
$bytes[0x15] = $bytes[0x15] -bor 0x20
[System.IO.File]::WriteAllBytes($shortcutPath, $bytes)
Write-Host "Shortcut created at: $shortcutPath"
#
# Done create WinUtil shortcut on the desktop
# ************************************************
Start-Process explorer
'@
$firstRun | Out-File -FilePath "$env:temp\FirstStartup.ps1" -Force
}