
# ***************************************************
# Script parameters
#
# ***************************************************

Param( 
    [parameter(Mandatory=$false)][string]$logspath,
    [parameter(Mandatory=$false)][string]$JSON,
    [parameter(Mandatory=$false)][switch]$NoReboot
)

$ScriptPath = (Split-Path $script:MyInvocation.MyCommand.Path)

$gblIgnoreWUCheck = $true   # WU Check Engine settings as default disabled for Prep Script as for the previous program compatibility

if($logspath) {
    if (Test-Path -Path "$logspath\prep.log") {
        $_tmpPrepHeaderString = @()
        $_tmpPrepHeaderString += ""
        Add-Content "$logspath\prep.log"  $_tmpPrepHeaderString
    }
}
else {
    $logspath = $ScriptPath
}

if($JSON) {
    if ((Test-Path $JSON) -and ($JSON -match ".json")) {
        $ini =  Get-Content -Raw -Path $JSON | ConvertFrom-Json
    }
    else {
        "Invalid JSON path ($JSON)" | LogMessage
        exit
    }
}
else {
    $ini =  Get-Content -Raw -Path "$ScriptPath\config.json" | ConvertFrom-Json
}

Import-Module $ScriptPath\HardwareSettings.psm1 -WarningAction SilentlyContinue
Import-Module $ScriptPath\DelayedTasks.psm1 -WarningAction SilentlyContinue
Import-Module $ScriptPath\SoftwareDisable.psm1 -WarningAction SilentlyContinue
Import-Module $ScriptPath\Telemetry.psm1 -WarningAction SilentlyContinue
Import-Module $ScriptPath\WindowsUpdates.psm1 -WarningAction SilentlyContinue

# Load CommonPS\CommonSystem.psm1 Library
if (-not (Get-Module CommonSystem))
{
    Import-Module "$ScriptPath\CommonSystem.psm1" -WarningAction SilentlyContinue
}

#
# Wow64 FS Redirection Disabled
#
DisableWow64FsRedirection

#
#   Check for Using WU process during SystemPrep Operation
#
try{
    if( $ini.UseWindowsUpdateDuringProcess ){
        # Config INI File Setting
        $gblIgnoreWUCheck = $false
    } else {
        # Default: Disable to use Windows Update Checking during Prep-operation
        $gblIgnoreWUCheck = $true
    }

} catch {}

# ***************************************************
# Functions
#
# ***************************************************

function Test-Admin {
  $currentUser = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent())
  $currentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}


function LogMessage { 
PROCESS {
    Add-Content "$logspath\prep.log" $_
    Write-Host $_
}}

function LogMessageNoConsole {
PROCESS {
    Add-Content "$logspath\prep.log" $_
}}

function Set-UwpVideoPlayerPolicy
{
    $_OSVer = [environment]::OSversion.version

    $_mmbSrc = $_OSVer.Major * 1000 + $_OSVer.Minor
    $_mmbTgt = 10 * 1000 + 0
    
    $_blApplyRegistryFix = $false

    if( $_mmbSrc -gt $_mmbTgt ){

        $_blApplyRegistryFix = $true

    } elseif( $_mmbSrc -eq $_mmbTgt ){

        if( $_OSVer.Build -ge 17000 ){
            $_blApplyRegistryFix = $true
        }
    }

    if( $_blApplyRegistryFix -eq $true ){
        #
        # New Policy Setting will be applied for Win 10.0.1700 or later
        #
        "Try to apply UWP VideoPlayer Policy..." | LogMessage
        $_blApplied = $true
        try{ $_iex_cmd = ". reg ADD " + '"HKCU\Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\documentsLibrary\Microsoft.ZuneVideo_8wekyb3d8bbwe"' + ' /v Value /t REG_SZ /d Allow /f'; Invoke-Expression -Command $_iex_cmd -ErrorAction SilentlyContinue 2>&1  } catch { $_blApplied = $false }
        try{ $_iex_cmd = ". reg ADD " + '"HKCU\Software\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\videosLibrary\Microsoft.ZuneVideo_8wekyb3d8bbwe"'    + ' /v Value /t REG_SZ /d Allow /f'; Invoke-Expression -Command $_iex_cmd -ErrorAction SilentlyContinue 2>&1  } catch { $_blApplied = $false }
        if( $_blApplied -eq $false ){
            "Fail to apply UWP VideoPlayer Policy." | LogMessage
        } else {
            "Success to apply UWP VideoPlayer Policy." | LogMessage
        }
    }

} # EOF

function Test-PathRegLoc
{
    param(
        [parameter(position=0, Mandatory=$true)]  $_RegLocation
    )

    $_blRetVal = $false
    $_iex_cmd2 = ". reg query " + '"' + $_RegLocation + '"'
    if( $_RegValueName ){
        $_iex_cmd2 = $_iex_cmd2 + ' /se '
    }

    try{
        $_contents = Invoke-Expression -Command "$($_iex_cmd2)" -ErrorAction SilentlyContinue 2>&1
        if( $LASTEXITCODE -eq 0 ){
            # If the query is succeeded by 'Reg.exe', the return code will be set as '0', otherwise '1'
            $_blRetVal = $true
        }
    } catch {}

    return( $_blRetVal )
}

function ProcessIdleTaskWithUpdateCheck
{

    # idle tasks on Win10 include NGEN execution, WinSAT prepop and defrag
    "Process Idle System Tasks..." | LogMessage
    $_process = start-process "$ScriptPath\ProcessIdleTasks.cmd" -PassThru -NoNewWindow -ErrorAction SilentlyContinue

    # Async-updating process detector - Maximum Time for Waiter loop set as 60min
    #
    $_cntProcessIdleTasksRun = 0
    $_cntUpdateRestartRequiredDetected = 0
    $_cntUpdateRestartPendingDetected = 0
    $_blUpdateRebootConditionDetected = $true           # Set the minimum process time duration for ProcessIdleTaskWithUpdateCheck as 15min
    $_cntUpdateRebootConditionDetectedMaxWait = 900     # Once UpdateReboot condition detected, allocate the installation-process for 15min

    $_pollingloopSecTime = 5    # Ideal Idle-waiter pooling time as 5 sec
    $_blProcessIdleTaskEndDetected = $false
    $_cntIntervalForKickWUScan = 0
    $_blDetectedInstallationExperience = $false

    while( ($_process.HasExited -eq $false) -or ($_blUpdateRebootConditionDetected -eq $true) ){
        $_blRebootRestartRequired = $false

        if( $_process.HasExited -eq $false ){
            #
            # Check 'ProcessIdleTasks' activity
            #
            if( ($_cntProcessIdleTasksRun -gt 0) -and (($_cntProcessIdleTasksRun % 300) -eq 0) ){
                # Show the current running tasks every 5 min
                try{
                    $_list = Get-ScheduledTask -ErrorAction SilentlyContinue | Where-Object { ($_.Settings.MaintenanceSettings) -and ( ($_.State -eq "Queued") -or ($_.State -eq "Running") ) }
                    $_ProcIdleTasksChkTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss K"
                    "(Running Tasks Status - $($_ProcIdleTasksChkTime))" | LogMessage
                    try{
                        $_outtxt= $_list | Format-Table -AutoSize -ErrorAction SilentlyContinue | Out-String -ErrorAction SilentlyContinue
                        "$($_outtxt)" | LogMessageNoConsole
                        $_list
                        " " | LogMessage
                    } catch {}
                } catch {}
            }

            if( $_cntProcessIdleTasksRun -ge 7200 ){
                # May be stuck jobs.... over 2 hours.
                "Ignore the current maintenance tasks because of abnormal condition over 2 hours..." | LogMessage
                try{
                    $_process.Kill()
                } catch {}
                "... Terminate Process Idle Tasks" | LogMessage
                Start-Sleep -Seconds $_pollingloopSecTime
                $_blProcessIdleTaskEndDetected = $true
            }

            $_cntProcessIdleTasksRun = $_cntProcessIdleTasksRun + $_pollingloopSecTime

        } else {
            if( ($_blProcessIdleTaskEndDetected -eq $false) -and ($_process.HasExited -ne $false) ){
                $_blProcessIdleTaskEndDetected = $true
                $_prepExecTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss K"
                # Taking over WU update process for ProcessIdleTask...
                "[$($_prepExecTime)] Ended ProcessIdleTasks..." | LogMessage
                # Launch the daemon WU update process.... (sanity call)
                if ( ($ini.StartScanWUAtPrepIfApplicable -eq $true) -or ($gblIgnoreWUCheck -eq $false) ){
                    try{
                        $_processWU2 = start-process "$ScriptPath\StartWUScanInstall.cmd" -PassThru -WindowStyle Hidden -ErrorAction SilentlyContinue
                    } catch {}
                    $_processWU3 = @()
                } else {
                    # Old behavior
                    if( $_blDetectedInstallationExperience -eq $true ){
                        if( $_cntUpdateRestartPendingDetected -eq 0 ){
                            $_blRebootRestartRequired = $true
                        }
                    } else {
                        $_prepExecTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss K"
                        "[$($_prepExecTime)] Wait $($_cntUpdateRebootConditionDetectedMaxWait) sec more for background activity check..." | LogMessage
                    }
                }
            }
        }


        #
        #   Check for background software update/install activities which affects the system configuration changes
        #
        try{

            #
            # Check background update/install instance which affects the system base DelayedTasks
            #
            $_blRetVal = Test-PathRegLoc "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending"
            if( $_blRetVal ){
                $_cntUpdateRestartPendingDetected = $_cntUpdateRestartPendingDetected + $_pollingloopSecTime
                if( $_cntUpdateRestartPendingDetected -eq $_pollingloopSecTime ){
                    $_prepExecTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss K"
                    "[$($_prepExecTime)] Detect install/update process running..." | LogMessage
                    $_cntIntervalForKickWUScan = 0
                }
                if( $_cntUpdateRestartPendingDetected -gt 3600 ){
                    # Set max counter                       # over 3600sec (==60min)
                    $_cntUpdateRestartPendingDetected = 3600
                }
                $_blDetectedInstallationExperience = $true
            } else {
                if( $_cntUpdateRestartPendingDetected -gt 0 ){
                    $_prepExecTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss K"
                    "[$($_prepExecTime)] Detect the end of Install/Update process..." | LogMessage
                    # Continue to start WU Scan if PAT Option is enabled
                    if ( ($ini.StartScanWUAtPrepIfApplicable -eq $true) -or ($gblIgnoreWUCheck -eq $false) ){
                        "Start WU Scan again if applicable..." | LogMessage
                        try{
                            $_processWU1 = start-process "$ScriptPath\StartWUScan.cmd" -PassThru -WindowStyle Hidden -ErrorAction SilentlyContinue
                        } catch {}
                        $_processWU1 = @()
                    }
                    $_prepExecTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss K"
                    "[$($_prepExecTime)] Reset counter & Prepare more additional idle time as 1200sec" | LogMessage
                    $_blUpdateRebootConditionDetected = $true
                    $_cntUpdateRebootConditionDetectedMaxWait = 1200    # Idle Detection as 20min
                }
                $_cntUpdateRestartPendingDetected = 0   # Zero reset

            }

            if( ($_cntIntervalForKickWUScan % 600) -eq 0 ){
                # Launch the daemon WU update process.... for every 10min
                if ( ($ini.StartScanWUAtPrepIfApplicable -eq $true) -or ($gblIgnoreWUCheck -eq $false) ){
                    try{
                        $_processWU2 = start-process "$ScriptPath\StartWUScanInstall.cmd" -PassThru -WindowStyle Hidden -ErrorAction SilentlyContinue
                    } catch {}
                    $_processWU2 = @()
                }
            }
            $_cntIntervalForKickWUScan = $_cntIntervalForKickWUScan + $_pollingloopSecTime

            #
            #   Check for background software update/install which need to the system restart operation for update/install completion.
            #
            $_blRetVal = Test-PathRegLoc "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired"
            if( $_blRetVal ){
                $_cntUpdateRestartRequiredDetected = $_cntUpdateRestartRequiredDetected + $_pollingloopSecTime
                if( $_cntUpdateRestartRequiredDetected -eq $_pollingloopSecTime ){
                    $_prepExecTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss K"
                    "[$($_prepExecTime)] Update and restart condition is detected - checking the system state for a while..." | LogMessage
                }
                if( $_cntUpdateRestartRequiredDetected -ge 300 ){
                    $_cntUpdateRestartRequiredDetected = 300    # over 300sec (==5min)
                }
                $_blDetectedInstallationExperience = $true
            } else {
                if( $_cntUpdateRestartRequiredDetected -gt 0 ){
                    $_prepExecTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss K"
                    "[$($_prepExecTime)] Update and restart condition was cleared..." | LogMessage

                    # Reset counter & Prepare more additional idle time
                    $_blUpdateRebootConditionDetected = $true
                    $_cntUpdateRebootConditionDetectedMaxWait = 1200    # Idle Detection as 20min
                }
                $_cntUpdateRestartRequiredDetected = 0  # Zero reset
            }

            if( $_cntUpdateRestartRequiredDetected -ge 300 ){
                "Continuously detecting RebootRequired for 5 minutes" | LogMessage
                $_blRebootRestartRequired = $true
            }

            if( $_cntUpdateRestartPendingDetected -ge 3600 ){
                $_prepExecTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss K"
                "[$($_prepExecTime)] Update Pending is detected over 3600 sec (==60min)," | LogMessage
                " probably update process might be in an incorrect state." | LogMessage
                "Force the system reboot once, and continue the Prep Operation" | LogMessage
                $_blRebootRestartRequired = $true
            }

            if( ($_cntUpdateRestartRequiredDetected -gt 0) -or ($_cntUpdateRestartPendingDetected -gt 0) ){
                $_blUpdateRebootConditionDetected = $true
                $_cntUpdateRebootConditionDetectedMaxWait = 1200    # Idle Detection as 20min
            } else {
                if( $_cntUpdateRebootConditionDetectedMaxWait -ge $_pollingloopSecTime ){
                    $_cntUpdateRebootConditionDetectedMaxWait = $_cntUpdateRebootConditionDetectedMaxWait - $_pollingloopSecTime
                }
                if( $_cntUpdateRebootConditionDetectedMaxWait -lt $_pollingloopSecTime ){
                    $_blUpdateRebootConditionDetected = $false
                }
            }
        } catch { }

        if( $_blRebootRestartRequired -eq $true ){
            $_prepExecTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss K"
            "[$($_prepExecTime)] Signal found for 'Update and reboot' by new update(s)" | LogMessage
            shutdown -r -f -t 0
            Start-Sleep -Seconds 180
        } else {
            Start-Sleep -Seconds $_pollingloopSecTime   # Idle Loop Period : 5 sec
        }
    }

    # Sanity Reboot if any installation/update is/are detected during ProccessIdleTasks
    if( $_blDetectedInstallationExperience )
    {
        $_prepExecTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss K"
        "[$($_prepExecTime)] Detected any install/update during Process Idle Tasks - Restart System to run Prep-operation again..." | LogMessage
        shutdown -r -f -t 0
    }
}


# ***************************************************
# Script logic
#
# ***************************************************

# Auto-elevate permissions
if ((Test-Admin) -eq $false)  {
    if ($elevated) {
        # tried to elevate, did not work, aborting
    } else {
        Start-Process powershell.exe -Verb RunAs -ArgumentList "-noprofile -noexit -file $($myinvocation.MyCommand.Definition) -elevated"
    }
    exit
}

# Setup Prep Log Header
    $_prepExecTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss K"
    $_tmpPrepHeaderString = @()
    $_tmpPrepHeaderString += "=========== Start Prep-operation : $($_prepExecTime) ================"
    $_tmpPrepHeaderString += ""
    Add-Content "$logspath\prep.log"  $_tmpPrepHeaderString


# some power policy changes
"Disable power saving features..." | LogMessage
HardwareSettings-DisablePowerSavingTimeouts

# Set the system to keep Idle State for 5min
"Wait 3 minutes before starting the configuration..." | LogMessage
Start-Sleep -Seconds 180

# Check WU Scan before starting Idle tasks
ProcessIdleTaskWithUpdateCheck


if ($ini.HardwareSettings.Enabled)
{
    # set audio volume
    "Set volume to $($ini.HardwareSettings.VolumePercentage)%..." | LogMessage
    HardwareSettings-SetVolume $ini.HardwareSettings.VolumePercentage 2>&1

    # set screen brightness
    "Set screen brightness to $($ini.HardwareSettings.BrightnessPercentage)%..." | LogMessage
    HardwareSettings-SetScreenBrightness $ini.HardwareSettings.BrightnessPercentage 2>&1
}

# override symbols path to an empty folder - speed up test time
[Environment]::SetEnvironmentVariable("_nt_symbol_path", "c:\symbols", "Machine")


# disable delayed logon tasks
if ($ini.DisableDelayedLogonTasks){
    "Disable delayed logon tasks..." | LogMessage
    DelayedTasks-Disable -LogPath $logspath
}

# disable memoryc compression to reduce variability
if ($ini.DisableMemCompression){
    "Disable memory compression..." | LogMessage
    try{
        Disable-MMAgent -MemoryCompression
    } catch {
        "Failed to disabled memory compression." | LogMessage
    }
}

# disable SPP
if ($ini.DisableSPPService){
    "Disable SPPSVC..." | LogMessage
    Disable-SPP
}

#Disable some tasks that were blocking PIT completion
if ($ini.DisableBlockMaintenanceTasks){
    "Disable Blocking Maintenance Tasks..." | LogMessage
    Disable-BlockingMaintenanceTasks
}

#Remove Skype preview to avoid variability from SkypeHost.exe on some scenarios
if ($ini.UninstallSkype){
    "Removing Skype Preview Appx package..." | LogMessage
    try{
            Remove-SkypePreview 
    } catch {
            $_.Exception.Message | LogMessage
    }
} else {
    "Skip removing Skype Preview Appx package..." | LogMessage
}

# disable app prelaunch to reduce variability
if ($ini.DisableAppPrelaunchVariability){
    $_funcFound = Get-ChildItem function:Disable-MMAgent -ErrorAction SilentlyContinue
    if( $_funcFound ){
        "Disable App Prelaunch MM agent..." | LogMessage
        Disable-MMAgent -ApplicationPreLaunch
    }
}

#disable EsifSvc to avoid issues on shutdown
if ($ini.DisableEsifService){
    "Disable memory compression..." | LogMessage
    Disable-EsifService
}

# disable Microsoft Office updates
if( $ini.DisableOfficeUpdates ) {
    "Disable Microsoft Office update..." | LogMessage
    Disable-OfficeUpdates
}

# Disable the ALS
if( $ini.DisableALSHardwareSetting ) {
    "Disable ALS..." | LogMessage
    HardwareSettings-DisableALS
}

# Check Fast Startup Capability and Fix the setting
if ($ini.EnableFastStartup)
{
    if( Test-FastStartupConfigState )
    {
        "System supports FastStartup capability -- Turn on HiberbootEnabled..." | LogMessage
        Repair-FastStartupConfigState
    }
    else
    {
        "The system does not have FastStartup capability..." | LogMessage
    }
}
else
{
    if( -not (Test-FastStartupConfigState) ) {
       "System supports FastStartup capability, but the configuration was disabled. Need FastStartup-setting turn on..." | LogMessage
    }
}

#Set default file associations
if( $ini.EnableDefaultFileAssociations ) {
    "Setting default file associations..." | LogMessage
    REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\FileAssociations\UpgradeChoice" /v Music /t REG_DWORD /d 00000001 /f
    REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\FileAssociations\UpgradeChoice" /v Video /t REG_DWORD /d 00000001 /f
    REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\FileAssociations\UpgradeChoice" /v Webbrowser /t REG_DWORD /d 00000001 /f 
}

# turn off system restore
#
if( $ini.DisableWindowsSystemRestore ) {
    "Disable Windows system restore..." | LogMessage
    reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\SystemRestore" /v RPSessionInterval /t REG_DWORD /d 0 /f
}

if( $ini.DisableSystemRestoreSchd ){
    "Disable Windows system restore(svc)..." | LogMessage
    try{
        Disable-ScheduledTask -TaskName "\Microsoft\Windows\SystemRestore\SR" -ErrorAction SilentlyContinue
    } catch {
        $_.Exception.Message | LogMessage
    }
}

# Disable CompatTelRunner service
#   Target:
#       SCHD    - \Microsoft\Windows\Application Experience\Microsoft Compatibility Appraiser
#       SCHD    - \Microsoft\Windows\Application Experience\ProgramDataUpdater
#
if( $ini.DisableCompatTelRunner )
{
    "Disable CompatTelRunner..." | LogMessage
    try
    {
        Disable-CompatTelRunner
    }
    catch
    {
        $_.Exception.Message | LogMessage
    }
}

# turn off defrag
#   Target:
#       SCHD    - \Microsoft\Windows\Defrag\ScheduledDefrag
#
if( $ini.DisableDefragScheduleSchd )
{
    "Disable defrag schedule..." | LogMessage
    try{
        Disable-ScheduledTask -TaskName "\Microsoft\Windows\Defrag\ScheduledDefrag" -ErrorAction SilentlyContinue
    } catch {
        $_.Exception.Message | LogMessage
    }
}

# turn off for Customer Experience Improvement Program
#   Target:
#       SCHD    - \Microsoft\Windows\Custom Experience Improvement Program\Consolidator
#
if( $ini.DisableCustomExperienceSchd ){
    "Disable Customer Experience Improvement Program schedule..." | LogMessage
    try{
        Disable-ScheduledTask -TaskName "\Microsoft\Windows\Custom Experience Improvement Program\Consolidator" -ErrorAction SilentlyContinue
    } catch {
        $_.Exception.Message | LogMessage
    }
}

# turn off for Power Efficiency Diagnostics tasks
#   Target:
#       SCHD    - \Microsoft\Windows\Power Efficiency Diagnostics\AnalyzeSystem
#
if( $ini.DisablePowerEfficiencyDiagSchd ){
    "Disable Power Efficiency Diagnostics Scheduled tasks..." | LogMessage
    try{
        Disable-ScheduledTask -TaskName "\Microsoft\Windows\Power Efficiency Diagnostics\AnalyzeSystem" -ErrorAction SilentlyContinue
    } catch {
        $_.Exception.Message | LogMessage
    }
}

# turn off for Hybrid Drive Cache tasks
#   Target:
#       SCHD    - \Microsoft\Windows\Sysmain\HybridDriveCachePrepopulate
#
if( $ini.DisableHybridDrvCacheSchd ){
    "Disable Hybrid Drive Cache Prepopulate Scheduled tasks..." | LogMessage
    try{
        Disable-ScheduledTask -TaskName "\Microsoft\Windows\Sysmain\HybridDriveCachePrepopulate" -ErrorAction SilentlyContinue
    } catch {
        $_.Exception.Message | LogMessage
    }
}

# turn off for Device Information tasks
#   Target:
#       SCHD    - \Microsoft\Windows\Device Information\Device
#
if( $ini.DisableDeviceInformationSchd ){
    "Disable Device Information Scheduled tasks..." | LogMessage
    try{
        Disable-ScheduledTask -TaskName "\Microsoft\Windows\Device Information\Device" -ErrorAction SilentlyContinue
    } catch {
        $_.Exception.Message | LogMessage
    }
}

# turn off for Device Setup tasks
#   Target:
#       SCHD    - \Microsoft\Windows\Device Setup\Metadata Refresh
#
if( $ini.DisableDeviceSetupSchd ){
    "Disable Device Information Scheduled tasks..." | LogMessage
    try{
        Disable-ScheduledTask -TaskName "\Microsoft\Windows\Device Setup\Metadata Refresh" -ErrorAction SilentlyContinue
    } catch {
        $_.Exception.Message | LogMessage
    }
}


# turn off for Disk Cleanup tasks
#   Target:
#       SCHD    - \Microsoft\Windows\DiskCleanup\SilentCleanup
#
if( $ini.DisableDiskCleanupSchd ){
    "Disable Disk Cleanup Scheduled tasks..." | LogMessage
    try{
        Disable-ScheduledTask -TaskName "\Microsoft\Windows\DiskCleanup\SilentCleanup" -ErrorAction SilentlyContinue
    } catch {
        $_.Exception.Message | LogMessage
    }
}

# turn off for Disk Diagnostic tasks
#   Target:
#       SCHD    - \Microsoft\Windows\DiskDiagnostic\Microsoft-Windows-DiskDiagnosticDataCollector
#
if( $ini.DisableDiskDiagnosticSchd ){
    "Disable Disk Diagnostic Scheduled tasks..." | LogMessage
    try{
        Disable-ScheduledTask -TaskName "\Microsoft\Windows\DiskDiagnostic\Microsoft-Windows-DiskDiagnosticDataCollector" -ErrorAction SilentlyContinue
    } catch {
        $_.Exception.Message | LogMessage
    }
}

# turn off for Time Synchronization tasks
#   Target:
#       SCHD    - \Microsoft\Windows\Time Synchronization\SynchronizeTime
#
if( $ini.DisableTimSynchronizationSchd ){
    "Disable Time Synchronization Scheduled tasks..." | LogMessage
    try{
        Disable-ScheduledTask -TaskName "\Microsoft\Windows\Time Synchronization\SynchronizeTime" -ErrorAction SilentlyContinue
    } catch {
        $_.Exception.Message | LogMessage
    }
}

# turn off for Windows Defender tasks
#   Target:
#       SCHD    - \Microsoft\Windows\Windows Defender\Windows Defender Verification
#
if( $ini.DisableWindowsDefenderSchd ){
    "Disable Windows Defender Scheduled tasks..." | LogMessage
    try{
        Disable-ScheduledTask -TaskName "\Microsoft\Windows\Windows Defender\Windows Defender Verification" -ErrorAction SilentlyContinue
    } catch {
        $_.Exception.Message | LogMessage
    }
}

# turn off for Windows MUI tasks
#   Target:
#       SCHD    - \Microsoft\Windows\MUI\LPRemove
#
if( $ini.DisableWindowsMUISchd ){
    "Disable Windows MUI Scheduled tasks..." | LogMessage
    try{
        Disable-ScheduledTask -TaskName "\Microsoft\Windows\MUI\LPRemove" -ErrorAction SilentlyContinue
    } catch {
        $_.Exception.Message | LogMessage
    }
}



# disable OneDrive on boot
if ($ini.DisableOneDriveOnBoot) {
    "Remove OneDrive from boot path..." | LogMessage
    try{ $_iex_cmd = ". reg DELETE " + '"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"'             + ' /v "OneDrive" /f'; Invoke-Expression -Command $_iex_cmd -ErrorAction SilentlyContinue 2>&1  } catch{}
    try{ $_iex_cmd = ". reg DELETE " + '"HKCU\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run"' + ' /v "OneDrive" /f'; Invoke-Expression -Command $_iex_cmd -ErrorAction SilentlyContinue 2>&1  } catch{}
    try{ $_iex_cmd = ". reg DELETE " + '"HKCU\SOFTWARE\WOWAA32Node\Microsoft\Windows\CurrentVersion\Run"' + ' /v "OneDrive" /f'; Invoke-Expression -Command $_iex_cmd -ErrorAction SilentlyContinue 2>&1  } catch{}
}

# disable settings sync
if ($ini.DisableSettingSync) {
    "Disable settings sync..." | LogMessage
    reg add "HKLM\SOFTWARE\Microsoft\PolicyManager\current\device\Experience" /v AllowSyncMySettings /t REG_DWORD /d 0 /f
}


# Build NGen Cache:
if ($ini.EnableBuildNgenCache) {
    "Run NGEN..." | LogMessage
    $_ngen_exe = "$env:WinDir\Microsoft.NET\Framework\v4.0.30319\ngen.exe"
    if (Test-Path( $_ngen_exe )){
        Start-Process "$($_ngen_exe)" -ArgumentList "ExecuteQueuedItems" -Wait
    }

    $_ngen_exe = "$env:WinDir\Microsoft.NET\Framework64\v4.0.30319\ngen.exe"
    if (Test-Path( $_ngen_exe )){
        Start-Process "$($_ngen_exe)" -ArgumentList "ExecuteQueuedItems" -Wait
    }
}

# Opt out telemetry for non-critical events 
try
{
    if ($ini.DisableUTC)
    {
        "UTC disable..." | LogMessage
        Disable-Telemetry
    }
    else
    {
        "UTC opt-out..." | LogMessage
        Reduce-Telemetry
    }
}
catch
{
    $_.Exception.Message | LogMessage
}



# Build Windows Defender cache 
if ($ini.EnableBuildWDAVCache) {
    "Build Windows Defender cache..." | LogMessage
    $_mpcmdrun_exe = $null
    if( $_mpcmdrun_exe -eq $null ){ $_mpcmdrun_exe = "$env:ProgramW6432\Windows Defender\mpcmdrun.exe"       ;if( -not (Test-Path( $_mpcmdrun_exe )) ){ $_mpcmdrun_exe = $null } }
    if( $_mpcmdrun_exe -eq $null ){ $_mpcmdrun_exe = "$env:ProgramFiles(Arm)\Windows Defender\mpcmdrun.exe"  ;if( -not (Test-Path( $_mpcmdrun_exe )) ){ $_mpcmdrun_exe = $null } }
    if( $_mpcmdrun_exe -eq $null ){ $_mpcmdrun_exe = "$env:ProgramFiles(x86)\Windows Defender\mpcmdrun.exe"  ;if( -not (Test-Path( $_mpcmdrun_exe )) ){ $_mpcmdrun_exe = $null } }
    if( $_mpcmdrun_exe -eq $null ){ $_mpcmdrun_exe = "$env:ProgramFiles\Windows Defender\mpcmdrun.exe"       ;if( -not (Test-Path( $_mpcmdrun_exe )) ){ $_mpcmdrun_exe = $null } }

    if ( $_mpcmdrun_exe -ne $null ){
        Start-Process "$($_mpcmdrun_exe)" -ArgumentList "BuildSFC -Timeout 7200000" -Wait
    }
}

#apply WU disable
if ($ini.DisableWindowsUpdateService) {
    "Disable auto updates..." | LogMessage
    Disable-WindowsUpdate
}

#Disable ContentDeliveryManager keys
if ($ini.DisableContentDeliveryManager) {
    "Disable ContentDeliveryManger keys..." | LogMessage
    try{
        Disable-ContentDeliveryManagerRegistry
    } catch {
        $_.Exception.Message | LogMessage
    }
}

#Apply Video Player Policy from RS4
"Check and apply UWP Video Player Policy..." | LogMessage
Set-UwpVideoPlayerPolicy

# Disable Paging Executive flag
if ($ini.DisablePagingExecutive) {
    "Disable Paging Executive Policy in Session Manager..." | LogMessage

    $_blApplied = $true
    try{ $_iex_cmd = ". reg ADD " + '"HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management"' + ' /v DisablePagingExecutive /t REG_DWORD /d 00000001 /f'; Invoke-Expression -Command $_iex_cmd -ErrorAction SilentlyContinue 2>&1  } catch { $_blApplied = $false }

    if( $_blApplied -eq $false ){
        "Fail to disable Paging Executive Policy." | LogMessage
    } else {
        "Success to disable Paging Executive Policy." | LogMessage
    }
}

# Disable CrashControl AutoReboot Option
if( $ini.DisableCrashControlAutoReboot ){
    "Disable Windows CrashControl - AutoReboot Option to Zero..." | LogMessage

    $_blApplied = $true

    try{ $_iex_cmd = ". reg ADD " + '"HKLM\SYSTEM\CurrentControlSet\Control\CrashControl"' + ' /v AutoReboot /t REG_DWORD /d 00000000 /f'; Invoke-Expression -Command $_iex_cmd -ErrorAction SilentlyContinue 2>&1  } catch { $_blApplied = $false }

    if( $_blApplied -eq $false ){
        "Fail to disable CrashControl AutoReboot option." | LogMessage
    } else {
        "Success to disable CrashControl AutoReboot option." | LogMessage
    }

}

#   Record the process end time
    $_prepExecTime = Get-Date -Format "yyyy/MM/dd HH:mm:ss K"
    $_tmpPrepHeaderString = @()
    $_tmpPrepHeaderString += "----------- End Prep-operation : $($_prepExecTime) ----------------"
    $_tmpPrepHeaderString += ""
    Add-Content "$logspath\prep.log"  $_tmpPrepHeaderString

#
# Wow64 FS Redirection Reverted
#
RevertWow64FsRedirection

if( $NoReboot )
{
    "Force system reboot later in assessment..." | LogMessage
}
else
{
    shutdown -r -f -t 0
}

# SIG # Begin signature block
# MIIPFgYJKoZIhvcNAQcCoIIPBzCCDwMCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCATXY2t55iTTP3t
# xo8U7DQSCcjbs35LDqZssVbaFJlvZaCCDBEwggV2MIIEXqADAgECAhMzAAAFdY/t
# ZZABUyRhAAEAAAV1MA0GCSqGSIb3DQEBCwUAMHkxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xIzAhBgNVBAMTGk1pY3Jvc29mdCBUZXN0aW5nIFBD
# QSAyMDEwMB4XDTIzMDIxNjE4MzM0MloXDTI0MDUxNjE4MzM0MlowdDELMAkGA1UE
# BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc
# BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEeMBwGA1UEAxMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAorUr
# gCj5FlJ+7vhjx+0mGUFTOka+WKbcrK7B95uaztftwdrnWN27Jslwy9AWtQJY3826
# OWRV4ajdLBVUB94DUgcw2heDY71cYIC7jcMwpwV6N8FHJN+OwTBzkAUWWwVarEPb
# 957z09miEYlJtASbQ8Sf61Beo2h0h82SRLPU4Q1F4CRN9WlXyn+6u5kulYIUUC0c
# bQP6qe+yukueASohANo9BRI/M6bAebYfvFookHLdybZdNFMo7sr1Bt6mCYdHPlyO
# sFYBXyZd+iQ3P6LQnjeZl9aFXXp6aFW88QawMKk/8ce2YTKAFG8y31/0IQWsAZw/
# iyhPJ9e9f9z8xdAWAQIDAQABo4IB+jCCAfYwPAYJKwYBBAGCNxUHBC8wLQYlKwYB
# BAGCNxUIg8+JTa3yAoWhnwyC+sp9geH7dIFPi/M4gp/5IgIBZAIBFTApBgkrBgEE
# AYI3FQoEHDAaMAwGCisGAQQBgjcKAxUwCgYIKwYBBQUHAwMwDgYDVR0PAQH/BAQD
# AgeAMB8GA1UdJQQYMBYGCCsGAQUFBwMDBgorBgEEAYI3CgMVMB0GA1UdDgQWBBTR
# /PEuPn+0r5mHo7syx14SmaNUSDAfBgNVHSMEGDAWgBS/ZaKrb3WjTkWWVwXPOYf0
# wBUcHDBcBgNVHR8EVTBTMFGgT6BNhktodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20v
# cGtpb3BzL2NybC9NaWNyb3NvZnQlMjBUZXN0aW5nJTIwUENBJTIwMjAxMCgxKS5j
# cmwwaQYIKwYBBQUHAQEEXTBbMFkGCCsGAQUFBzAChk1odHRwOi8vd3d3Lm1pY3Jv
# c29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRlc3RpbmclMjBQQ0El
# MjAyMDEwKDEpLmNydDBDBgkrBgEEAYI3FAIENh40AE0AUwBJAFQAVABlAHMAdABD
# AG8AZABlAFMAaQBnAG4AaQBuAGcAUwBoAGEAMgAtAEMAUzAMBgNVHRMBAf8EAjAA
# MA0GCSqGSIb3DQEBCwUAA4IBAQAg7Ej3KuUo0ndCL+pCb2eqn8rz77O2j90YQr2Y
# MhMsinWGq1OTp3LZfPNeI3G2BXFtvjIE++ZXjLRa/bnReVrq2p/PikV7zq0WpWzS
# gb1TBvmg80mt7Pgq/RcuNfBlO5t1wRKnmmoR3zZLHmJrXCKKSL55CyL2ZYvi+ilO
# UgcBn4E7fTGAGr41x2aKt7BhnUbiYaVwGdyYKnJv9q+6AC+fI7xnoX2mbO63zWl8
# Se9LfD7P4S/03jwAafqPiHXgkAmw4cgsK4kX9pTS/sYb336dvlilbmcAhtGf1cQ0
# /5h279IUhQb53WulhCAZ3H42KxtetiyNi8MNLoEWK9wh/hb2MIIGkzCCBHugAwIB
# AgITMwAAAC01ekaIyQdx2AAAAAAALTANBgkqhkiG9w0BAQsFADCBkDELMAkGA1UE
# BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc
# BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE6MDgGA1UEAxMxTWljcm9zb2Z0
# IFRlc3RpbmcgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0yMDEy
# MTAyMDQzMjBaFw0zNTA2MTcyMTA0MTFaMHkxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
# EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
# ZnQgQ29ycG9yYXRpb24xIzAhBgNVBAMTGk1pY3Jvc29mdCBUZXN0aW5nIFBDQSAy
# MDEwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvzxggau+7P/XF2Py
# pkLRE2KcsBfOukYaeyIuVXOaVLnG1NHKmP53Rw2OnfBezPhU7/LPKtRi8ak0CgTX
# xQWG8hD1TdOWCGaF2wJ9GNzieiOnmildrnkYzwxj8Br/gampQz+pC7lR8bNIOvxE
# Ll8RxVY6/8oOzYgIwf3H1fU+7+pOG3KLI71FN54fcMGnybggc+3zbD2LIQXPdxL+
# odwH6Q1beAlsMlUQR9A3yMf3+nP+RjTkVhaoN2RT1jX7w4C2jraGkaEQ1sFK9uN6
# 1BEKst4unhCX4IGuEl2IAV3MpMQoUpxg8ArmiK9L6VeK7KMPNx4p9l0h09faXQ7J
# TtuNbQIDAQABo4IB+jCCAfYwDgYDVR0PAQH/BAQDAgGGMBIGCSsGAQQBgjcVAQQF
# AgMBAAEwIwYJKwYBBAGCNxUCBBYEFOqfXzO20F+erestpsECu0A4y+e1MB0GA1Ud
# DgQWBBS/ZaKrb3WjTkWWVwXPOYf0wBUcHDBUBgNVHSAETTBLMEkGBFUdIAAwQTA/
# BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2Nz
# L1JlcG9zaXRvcnkuaHRtMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMA8GA1Ud
# EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUowEEfjCIM+u5MZzK64V2Z/xltNEwWQYD
# VR0fBFIwUDBOoEygSoZIaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwv
# cHJvZHVjdHMvTWljVGVzUm9vQ2VyQXV0XzIwMTAtMDYtMTcuY3JsMIGNBggrBgEF
# BQcBAQSBgDB+ME0GCCsGAQUFBzAChkFodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20v
# cGtpL2NlcnRzL01pY1Rlc1Jvb0NlckF1dF8yMDEwLTA2LTE3LmNydDAtBggrBgEF
# BQcwAYYhaHR0cDovL29uZW9jc3AubWljcm9zb2Z0LmNvbS9vY3NwMA0GCSqGSIb3
# DQEBCwUAA4ICAQAntNCFsp7MD6QqU3PVbdrXMQDI9v9jyPYBEbUYktrctPmvJuj8
# Snm9wWewiAN5Zc81NQVYjuKDBpb1un4SWVCb4PDVPZ0J87tGzYe9dOJ30EYGeiIa
# aStkLLmLOYAM6oInIqIwVyIk2SE/q2lGt8OvwcZevNmPkVYjk6nyJi5EdvS6ciPR
# mW9bRWRT4pWU8bZIQL938LE4lHOQAixrAQiWes5Szp2U85E0nLdaDr5w/I28J/Z1
# +4zW1Nao1prVCOqrosnoNUfVf1kvswfW3FY2l1PiAYp8sGyO57GaztXdBoEOBcDL
# edfcPra9+NLdEF36NkE0g+9dbokFY7KxhUJ8WpMiCmN4yj9LKFLvQbctGMJJY9Ew
# HFifm2pgaiaafKF1Gyz+NruJzEEgpysMo/f9AVBQ/qCdPQQGEWp3QDIaef4ts9QT
# x+RmDKCBDMTFLgFmmhbtUY0JWjLkKn7soz/LIcDUle/p5TiFD4VhfZnAcvYQHXfu
# slnyp+yuhWzASnAQNnOIO6fc1JFIwkDkcM+k/TspfAajzHooSAwXkrOWrjRDV6wI
# 0YzMVHrEyQ0hZ5NnIXbL3lrTkOPjf3NBu1naSNEaySduStDbFVjV3TXoENEnZiug
# JKYSwmhzoYHM1ngipN5rNdqJiK5ukp6E8LDzi3l5/7XctJQY3+ZgHDJosjGCAlsw
# ggJXAgEBMIGQMHkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# IzAhBgNVBAMTGk1pY3Jvc29mdCBUZXN0aW5nIFBDQSAyMDEwAhMzAAAFdY/tZZAB
# UyRhAAEAAAV1MA0GCWCGSAFlAwQCAQUAoIGcMBkGCSqGSIb3DQEJAzEMBgorBgEE
# AYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJ
# BDEiBCCRJz5H/pGtm3do7DecsdYrLPN9u1+r5BW8P3eofNu0ZzAwBgorBgEEAYI3
# AgEMMSIwIKAegBwAUwBTAEMAXABXAGkAbgBSAFQATQBwAGIAbABkMA0GCSqGSIb3
# DQEBAQUABIIBAJDCe2mH+nf0WabGDSiYdezaoCcANdP2gAUhQ6FVGxVudMvqQRjB
# +NCDIUT1n93qzRpGdUnBcC6tdQWPw0j958GfexLWcwY6EfVg8tsDoXu/OEBQ7EfR
# o62u9MPotw6ilbwYNFcyyoxCXESUzDQ2pKxtPiaeCCsa9xOfXumn2Owp4BbfbCbq
# qFRPHU1gOWdk7rlwfgVRJTN91UiXCHC3QCAlOgM9Z0MGm5BTKYQr7+7YCMwB3lWk
# F7oNhzZfZRTNj6UCAcgwhPxn5/koSsXd3qL2dXyVExqlgLA4qFRHOfNsMiZ6dH6d
# FvzajatWsFWtZoQHJ7TxejHgSWo8ukvp5Wc=
# SIG # End signature block
