MMS 2015 unplugged : Preparing your App-V sequencer the right “automated” way

December 18, 2015 at 1:18 pm in App-V, App-V 5.0, applications, AppV, powershell, sequencing by Kenny Buntinx [MVP]

 

First of all – sorry for the delay as we promised to post this script much earlier. However as usual there are only 48 hours in a day :-)

If you attended our session “Sequencing applications with App-V 5.1 – Best Practices Edition”, Roy Essers and me showed you the latest techniques to prepare and analyze to virtualize apps using the latest version of Microsoft App-V. One of those best practices techniques is to prepare your sequencer the automated way  :

Another App-V MVP called Dan Gough originally created this script , but it wasn’t really a good solution in our eyes. The reason for that , was that it uses modules from chocolatey and boxstarter directly of the internet and we didn’t trust the big bad cloudy internet. Anyone could change the source code and inject malicious code anytime . Also changes made in revisions would also create an inconsistency in your build platform.

You will find the script below and we provide it AS-IS with no support :

# Disclaimer: This script is provided as-is, without warranty of any kind # # App-V sequencer / client generic build script # Version 1.0 - Dan Gough 04/07/15 # Version 1.1 - Fixed HideSCAHealth registry key # Version 1.2 - Fixed install on 32-bit Windows # Version 1.3 - Update for .NET 4.6 and Windows 10, better method of disabling Defender on Win8+ # Version 1.4 - Roy Essers - added native functions from chocolatey and boxstarter (so no need for those modules). # -sequencer only # -depends on local sources (dotnet, wmf, etc), if not found will try to download them from the internet # -added some features, onedrive removal. # planning to add option to (download and) install vcredists function Download-File() { <# .SYNOPSIS Downloads a file showing the progress of the download .DESCRIPTION This Script will download a file locally while showing the progress of the download .EXAMPLE .\Download-File.ps1 'http:\\someurl.com\somefile.zip' .EXAMPLE .\Download-File.ps1 'http:\\someurl.com\somefile.zip' 'C:\Temp\somefile.zip' .PARAMETER url url to be downloaded .PARAMETER localFile the local filename where the download should be placed .NOTES FileName : Download-File.ps1 Author : CrazyDave LastModified : 18 Jan 2011 9:39 AM PST #Requires -Version 2.0 #> param( [Parameter(Mandatory=$true)] [String] $url, [Parameter(Mandatory=$false)] [String] $localFile = (Join-Path $pwd.Path $url.SubString($url.LastIndexOf('/'))) ) begin { $client = New-Object System.Net.WebClient $Global:downloadComplete = $false $eventDataComplete = Register-ObjectEvent $client DownloadFileCompleted ` -SourceIdentifier WebClient.DownloadFileComplete ` -Action {$Global:downloadComplete = $true} $eventDataProgress = Register-ObjectEvent $client DownloadProgressChanged ` -SourceIdentifier WebClient.DownloadProgressChanged ` -Action { $Global:DPCEventArgs = $EventArgs } } process { Write-Progress -Activity 'Downloading file' -Status $url $client.DownloadFileAsync($url, $localFile) while (!($Global:downloadComplete)) { $pc = $Global:DPCEventArgs.ProgressPercentage if ($pc -ne $null) { Write-Progress -Activity 'Downloading file' -Status $url -PercentComplete $pc } } Write-Progress -Activity 'Downloading file' -Status $url -Complete } end { Unregister-Event -SourceIdentifier WebClient.DownloadProgressChanged Unregister-Event -SourceIdentifier WebClient.DownloadFileComplete $client.Dispose() $Global:downloadComplete = $null $Global:DPCEventArgs = $null Remove-Variable client Remove-Variable eventDataComplete Remove-Variable eventDataProgress [GC]::Collect() } } function Install-PinnedTaskBarItem { <# .SYNOPSIS Creates an item in the task bar linking to the provided path. .PARAMETER TargetFilePath The path to the application that should be launched when clicking on the task bar icon. .EXAMPLE Install-PinnedTaskBarItem "${env:ProgramFiles(x86)}\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe" This will create a Visual Studio task bar icon. #> param( [string] $targetFilePath ) Write-Debug "Running 'Install-PinnedTaskBarItem' with targetFilePath:`'$targetFilePath`'"; if (Test-Path($targetFilePath)) { $verb = "Pin To Taskbar" $path= split-path $targetFilePath $shell=new-object -com "Shell.Application" $folder=$shell.Namespace($path) $item = $folder.Parsename((split-path $targetFilePath -leaf)) $itemVerb = $item.Verbs() | ? {$_.Name.Replace("&","") -eq $verb} if($itemVerb -eq $null){ Write-Host "TaskBar verb not found for $item. It may have already been pinned" -ForegroundColor Yellow } else { $itemVerb.DoIt() } Write-host "`'$((Get-ChildItem $targetFilePath).Name)`' has been pinned to the task bar on your desktop." -ForegroundColor Green } else { $errorMessage = "`'$((Get-ChildItem $targetFilePath).Name)`' does not exist, not able to pin to task bar" } if($errorMessage){ Write-host $errorMessage -ForegroundColor Red throw $errorMessage } } function Set-StartScreenOptions { <# .SYNOPSIS Sets options for the Windows Start Screen. .PARAMETER EnableBootToDesktop When I sign in or close all apps on a screen, go to the desktop instead of Start .PARAMETER DisableBootToDesktop Disables the Boot to Desktop Option, see enableBootToDesktop .PARAMETER EnableDesktopBackgroundOnStart Show Desktop background on Start .PARAMETER DisableDesktopBackgroundOnStart Do not show Desktop background on Start .PARAMETER EnableShowStartOnActiveScreen Show Start on the display I'm using when I press the Windows logo key .PARAMETER DisableShowStartOnActiveScreen Disables the displaying of the Start screen on active screen, see enableShowStartOnActiveScreen .PARAMETER EnableShowAppsViewOnStartScreen Show the Apps view automatically when I go to Start PARAMETER DisableShowAppsViewOnStartScreen Disables the showing of Apps View when Start is activated, see enableShowAppsViewOnStartScreen .PARAMETER EnableSearchEverywhereInAppsView Search everywhere instead of just my apps when I search from the Apps View .PARAMETER DisableSearchEverywhereInAppsView Disables the searching of everywhere instead of just apps, see enableSearchEverywhereInAppsView .PARAMETER EnableListDesktopAppsFirst List desktop apps first in the Apps view when it's sorted by category .PARAMETER DisableListDesktopAppsFirst Disables the ability to list desktop apps first when sorted by category, see enableListDesktopAppsFirst .LINK http://boxstarter.org #> [CmdletBinding()] param( [switch]$EnableBootToDesktop, [switch]$DisableBootToDesktop, [switch]$EnableDesktopBackgroundOnStart, [switch]$DisableDesktopBackgroundOnStart, [switch]$EnableShowStartOnActiveScreen, [switch]$DisableShowStartOnActiveScreen, [switch]$EnableShowAppsViewOnStartScreen, [switch]$DisableShowAppsViewOnStartScreen, [switch]$EnableSearchEverywhereInAppsView, [switch]$DisableSearchEverywhereInAppsView, [switch]$EnableListDesktopAppsFirst, [switch]$DisableListDesktopAppsFirst ) $PSBoundParameters.Keys | %{ if($_-like "En*"){ $other="Dis" + $_.Substring(2)} if($_-like "Dis*"){ $other="En" + $_.Substring(3)} if($PSBoundParameters[$_] -and $PSBoundParameters[$other]){ throw new-Object -TypeName ArgumentException "You may not set both $_ and $other. You can only set one." } } $key = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer' $startPageKey = "$key\StartPage" $accentKey = "$key\Accent" if(Test-Path -Path $startPageKey) { if($enableBootToDesktop) { Set-ItemProperty -Path $startPageKey -Name 'OpenAtLogon' -Value 0 } if($disableBootToDesktop) { Set-ItemProperty -Path $startPageKey -Name 'OpenAtLogon' -Value 1 } if($enableShowStartOnActiveScreen) { Set-ItemProperty -Path $startPageKey -Name 'MonitorOverride' -Value 1 } if($disableShowStartOnActiveScreen) { Set-ItemProperty -Path $startPageKey -Name 'MonitorOverride' -Value 0 } if($enableShowAppsViewOnStartScreen) { Set-ItemProperty -Path $startPageKey -Name 'MakeAllAppsDefault' -Value 1 } if($disableShowAppsViewOnStartScreen) { Set-ItemProperty -Path $startPageKey -Name 'MakeAllAppsDefault' -Value 0 } if($enableSearchEverywhereInAppsView) { Set-ItemProperty -Path $startPageKey -Name 'GlobalSearchInApps' -Value 1 } if($disableSearchEverywhereInAppsView) { Set-ItemProperty -Path $startPageKey -Name 'GlobalSearchInApps' -Value 0 } if($enableListDesktopAppsFirst) { Set-ItemProperty -Path $startPageKey -Name 'DesktopFirst' -Value 1 } if($disableListDesktopAppsFirst) { Set-ItemProperty -Path $startPageKey -Name 'DesktopFirst' -Value 0 } } if(Test-Path -Path $accentKey) { if($EnableDesktopBackgroundOnStart) { Set-ItemProperty -Path $accentKey -Name 'MotionAccentId_v1.00' -Value 219 } if($DisableDesktopBackgroundOnStart) { Set-ItemProperty -Path $accentKey -Name 'MotionAccentId_v1.00' -Value 221 } } } function Get-CurrentUser { <# .SYNOPSIS Returns the domain and username of the currently logged in user. #> $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent() $parts = $identity.Name -split "\\" return @{Domain=$parts[0];Name=$parts[1]} } function Restart-Explorer { try{ Write-Host "Restarting the Windows Explorer process..." -ForegroundColor Cyan $user = Get-CurrentUser try { $explorer = Get-Process -Name explorer -ErrorAction stop -IncludeUserName } catch {$global:error.RemoveAt(0)} if($explorer -ne $null) { $explorer | ? { $_.UserName -eq "$($user.Domain)\$($user.Name)"} | Stop-Process -Force -ErrorAction Stop | Out-Null } Start-Sleep 1 if(!(Get-Process -Name explorer -ErrorAction SilentlyContinue)) { $global:error.RemoveAt(0) start-Process -FilePath explorer } } catch {$global:error.RemoveAt(0)} } function Set-WindowsExplorerOptions { <# .SYNOPSIS Sets options on the Windows Explorer shell .PARAMETER EnableShowHiddenFilesFoldersDrives If this flag is set, hidden files will be shown in Windows Explorer .PARAMETER DisableShowHiddenFilesFoldersDrives Disables the showing on hidden files in Windows Explorer, see EnableShowHiddenFilesFoldersDrives .PARAMETER EnableShowProtectedOSFiles If this flag is set, hidden Operating System files will be shown in Windows Explorer .PARAMETER DisableShowProtectedOSFiles Disables the showing of hidden Operating System Files in Windows Explorer, see EnableShowProtectedOSFiles .PARAMETER EnableShowFileExtensions Setting this switch will cause Windows Explorer to include the file extension in file names .PARAMETER DisableShowFileExtensions Disables the showing of file extension in file names, see EnableShowFileExtensions .PARAMETER EnableShowFullPathInTitleBar Setting this switch will cause Windows Explorer to show the full folder path in the Title Bar .PARAMETER DisableShowFullPathInTitleBar Disables the showing of the full path in Windows Explorer Title Bar, see EnableShowFullPathInTitleBar .LINK http://boxstarter.org #> [CmdletBinding()] param( [switch]$EnableShowHiddenFilesFoldersDrives, [switch]$DisableShowHiddenFilesFoldersDrives, [switch]$EnableShowProtectedOSFiles, [switch]$DisableShowProtectedOSFiles, [switch]$EnableShowFileExtensions, [switch]$DisableShowFileExtensions, [switch]$EnableShowFullPathInTitleBar, [switch]$DisableShowFullPathInTitleBar ) $PSBoundParameters.Keys | % { if($_-like "En*"){ $other="Dis" + $_.Substring(2)} if($_-like "Dis*"){ $other="En" + $_.Substring(3)} if($PSBoundParameters[$_] -and $PSBoundParameters[$other]) { throw new-Object -TypeName ArgumentException "You may not set both $_ and $other. You can only set one." } } $key = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer' $advancedKey = "$key\Advanced" $cabinetStateKey = "$key\CabinetState" Write-Host "Setting Windows Explorer options..." -ForegroundColor Cyan if(Test-Path -Path $advancedKey) { if($EnableShowHiddenFilesFoldersDrives) {Set-ItemProperty $advancedKey Hidden 1} if($DisableShowHiddenFilesFoldersDrives) {Set-ItemProperty $advancedKey Hidden 0} if($EnableShowFileExtensions) {Set-ItemProperty $advancedKey HideFileExt 0} if($DisableShowFileExtensions) {Set-ItemProperty $advancedKey HideFileExt 1} if($EnableShowProtectedOSFiles) {Set-ItemProperty $advancedKey ShowSuperHidden 1} if($DisableShowProtectedOSFiles) {Set-ItemProperty $advancedKey ShowSuperHidden 0} Restart-Explorer } if(Test-Path -Path $cabinetStateKey) { if($EnableShowFullPathInTitleBar) {Set-ItemProperty $cabinetStateKey FullPath 1} if($DisableShowFullPathInTitleBar) {Set-ItemProperty $cabinetStateKey FullPath 0} Restart-Explorer } } function Get-IsMicrosoftUpdateEnabled { <# .SYNOPSIS Returns $True if Microsoft Update is currently enabled .LINK http://boxstarter.org #> # Default response to false, unless proven otherwise $installed = $false $serviceManager = New-Object -ComObject Microsoft.Update.ServiceManager -Strict $serviceManager.ClientApplicationID = "Sequencer" foreach ($service in $serviceManager.Services) { if( $service.Name -eq "Microsoft Update") { $installed = $true; break; } } return $installed } function Enable-MicrosoftUpdate { <# .SYNOPSIS Turns on Microsoft Update, so additional updates for other Microsoft products, installed on the system, will be included when running Windows Update. .LINK http://boxstarter.org Disable-MicrsoftUpdate #> if(!(Get-IsMicrosoftUpdateEnabled)) { Write-Host "Microsoft Update is currently disabled." -ForegroundColor Yellow Write-Host "Enabling Microsoft Update..." -ForegroundColor Cyan $serviceManager = New-Object -ComObject Microsoft.Update.ServiceManager -Strict $serviceManager.ClientApplicationID = "Sequencer" $serviceManager.AddService2("7971f918-a847-4430-9279-4a52d1efe18d",7,"") } else { Write-Host "Microsoft Update is already enabled, no action will be taken." -ForegroundColor Green } } function Start-TimedSection { <# .SYNOPSIS Begins a timed section .DESCRIPTION A timed section is a portion of script that is timed. Used with Stop-TimedSection, the beginning and end of the section are logged to both the console and the log along with the amount of time elapsed. The function returns a guid that is used to identify the section when stopping it. .PARAMETER SectionName The Title or Label of the section being timed. This string is used in the logging to identify the section. .PARAMETER Verbose Instructs Start-TimedSection to write to the Verbose stream. Although this will always log messages to the Boxstarter log, it will only log to the console if the session's VerbosePreference is set to capture the Verbose stream or the -Verbose switch was set when calling Install-BoxstarterPackage. .EXAMPLE $session=Start-TimedSection "My First Section" Stop-TimedSection $session This creates a block as follows: + Boxstarter starting My First Section Some stuff happens here. + Boxstarter finished My First Section 00:00:00.2074282 .EXAMPLE Timed Sections can be nested or staggered. You can have multiple sections running at once. $session=Start-TimedSection "My First Section" $innerSession=Start-TimedSection "My Inner Section" Stop-TimedSection $innerSession Stop-TimedSection $session This creates a block as follows: + Boxstarter starting My First Section Some stuff happens here. ++ Boxstarter starting My Inner Section Some inner stuff happens here. ++ Boxstarter finished My Inner Section 00:00:00.1074282 Some more stuff happens here. + Boxstarter finished My First Section 00:00:00.2074282 Note that the number of '+' chars indicate nesting level. .EXAMPLE $session=Start-TimedSection "My First Section" -Verbose Stop-TimedSection $session This will write the start and finish messages to the Boxstarter log but will not write to the console unless the user has the the VerbosePreference variable or used the Verbose switch of Install-BoxstarterPackage. .NOTES If the SuppressLogging setting of the $Boxstarter variable is true, logging messages will be suppressed and not sent to the console or the log. .LINK http://boxstarter.org Stop-TimedSection about_boxstarter_logging #> param( [string]$sectionName, [switch]$Verbose) $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() $guid = [guid]::NewGuid().ToString() $timerEntry=@{title=$sectionName;stopwatch=$stopwatch;verbose=$Verbose} if(!$script:boxstarterTimers) {$script:boxstarterTimers=@{}} $boxstarterTimers.$guid=$timerEntry $padCars="".PadLeft($boxstarterTimers.Count,"+") Write-host "$sectionName" -ForegroundColor Cyan return $guid } function Stop-TimedSection { <# .SYNOPSIS Ends a timed section .DESCRIPTION A timed section is a portion of script that is timed. Used with Start-TimedSection, the beginning and end of the section are logged to both the console and the log along with the amount of time elapsed. .PARAMETER SectionId The guid that was generated by Start-TimedSection and identifies which section is ending. .EXAMPLE $session=Start-TimedSection "My First Section" Stop-TimedSection $session This creates a block as follows: + Boxstarter starting My First Section Some stuff happens here. + Boxstarter finished My First Section 00:00:00.2074282 .EXAMPLE Timed Sections can be nested or staggered. You can have multiple sections running at once. $session=Start-TimedSection "My First Section" $innerSession=Start-TimedSection "My Inner Section" Stop-TimedSection $innerSession Stop-TimedSection $session This creates a block as follows: + Boxstarter starting My First Section Some stuff happens here. ++ Boxstarter starting My Inner Section Some inner stuff happens here. ++ Boxstarter finished My Inner Section 00:00:00.1074282 Some more stuff happens here. + Boxstarter finished My First Section 00:00:00.2074282 Note that the number of '+' chars indicate nesting level. .LINK http://boxstarter.org Start-TimedSection about_boxstarter_logging #> param([string]$SectionId) $timerEntry=$script:boxstarterTimers.$SectionId if(!$timerEntry){return} $padCars="".PadLeft($boxstarterTimers.Count,"+") $script:boxstarterTimers.Remove($SectionId) $stopwatch = $timerEntry.stopwatch Write-Host "Finished $($timerEntry.Title) $($stopwatch.Elapsed.ToString())" -ForegroundColor Cyan $stopwatch.Stop() } function Install-WindowsUpdate { <# .SYNOPSIS Downloads and installs updates via Windows Update .DESCRIPTION This uses the windows update service to search, download and install updates. By default, only critical updates are included and a reboot will be induced if required. .PARAMETER GetUpdatesFromMS If this switch is set, the default windows update server, if any, is bypassed and windows update requests go to the public Microsoft Windows update service. .PARAMETER AcceptEula If any update requires a Eula acceptance, setting this switch will accept the Eula and allow the update to be installed. .PARAMETER SuppressReboots Setting this switch will suppress a reboot in the event that any update requires one. .PARAMETER Criteria The criteria used for searching updates. The default criteria is "IsHidden=0 and IsInstalled=0 and Type='Software'" which is effectively just critical updates. .LINK http://boxstarter.org #> param( [switch]$getUpdatesFromMS, [switch]$acceptEula, [switch]$SuppressReboots, [string]$criteria="IsHidden=0 and IsInstalled=0 and Type='Software' and BrowseOnly=0" ) <# if(Get-IsRemote){ Invoke-FromTask @" Import-Module $($boxstarter.BaseDir)\boxstarter.WinConfig\Boxstarter.Winconfig.psd1 Install-WindowsUpdate -GetUpdatesFromMS:`$$GetUpdatesFromMS -AcceptEula:`$$AcceptEula -SuppressReboots -Criteria "$Criteria" "@ -IdleTimeout 0 -TotalTimeout 0 if(Test-PendingReboot){ Invoke-Reboot } return } #> try{ $searchSession=Start-TimedSection "Checking for updates..." $updateSession =new-object -comobject "Microsoft.Update.Session" $Downloader =$updateSession.CreateUpdateDownloader() $Installer =$updateSession.CreateUpdateInstaller() $Searcher =$updatesession.CreateUpdateSearcher() if($getUpdatesFromMS) { $Searcher.ServerSelection = 2 #2 is the Const for the Windows Update server } $wus=Get-WmiObject -Class Win32_Service -Filter "Name='wuauserv'" $origStatus=$wus.State $origStartupType=$wus.StartMode Write-warning "Update service is in the $origStatus state and its startup type is $origStartupType." -verbose if($origStartupType -eq "Auto"){ $origStartupType = "Automatic" } if($origStatus -eq "Stopped"){ if($origStartupType -eq "Disabled"){ Set-Service wuauserv -StartupType Automatic } Write-Host "Starting windows update service..." -ForegroundColor Cyan Start-Service -Name wuauserv } else { # Restart in case updates are running in the background Write-Host "Restarting windows update service..." -ForegroundColor Cyan Restart-Service -Name wuauserv -Force -WarningAction SilentlyContinue } $Result = $Searcher.Search($criteria) Stop-TimedSection $searchSession $totalUpdates = $Result.updates.count If ($totalUpdates -ne 0) { Write-Host "$($Result.updates.count) Updates found." -ForegroundColor Magenta $currentCount = 0 foreach($update in $result.updates) { ++$currentCount if(!($update.EulaAccepted)){ if($acceptEula) { $update.AcceptEula() } else { Write-host " * $($update.title) has a user agreement that must be accepted. Call Install-WindowsUpdate with the -AcceptEula parameter to accept all user agreements. This update will be ignored." -ForegroundColor Yellow continue } } $Result= $null if ($update.isDownloaded -eq "true" -and ($update.InstallationBehavior.CanRequestUserInput -eq $false )) { Write-Host " * $($update.title) already downloaded" -ForegroundColor Green $result = install-Update $update $currentCount $totalUpdates } elseif($update.InstallationBehavior.CanRequestUserInput -eq $true) { Write-Host " * $($update.title) Requires user input and will not be downloaded." -ForegroundColor Yellow } else { Download-Update $update $result = Install-Update $update $currentCount $totalUpdates } } if($result -ne $null -and $result.rebootRequired) { if($SuppressReboots) { Write-Host "A Restart is Required." -ForegroundColor Yellow } else { $Rebooting=$true Write-Host "Restart Required. Restarting now..." -ForegroundColor Yellow Stop-TimedSection $installSession if(test-path function:\Invoke-Reboot) { return Invoke-Reboot } else { Restart-Computer -force } } } } else{Write-Host "There is no update applicable to this machine." -ForegroundColor Yellow} } catch { Write-Host "There were problems installing updates: $($_.ToString())." -ForegroundColor Red throw } finally { if($origAUVal){ Set-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate\AU -Name UseWuServer -Value $origAUVal -ErrorAction SilentlyContinue } if($origStatus -eq "Stopped") { Write-Host "Stopping win update service and setting its startup type to $origStartupType." -ForegroundColor Yellow Set-Service wuauserv -StartupType $origStartupType stop-service wuauserv -WarningAction SilentlyContinue } } } function Download-Update($update) { $downloadSession=Start-TimedSection "Download of $($update.Title)" $updates= new-Object -com "Microsoft.Update.UpdateColl" $updates.Add($update) | out-null $Downloader.Updates = $updates $Downloader.Download() | Out-Null Stop-TimedSection $downloadSession } function Install-Update($update, $currentCount, $totalUpdates) { $installSession=Start-TimedSection "Install $currentCount of $totalUpdates updates: $($update.Title)" $updates= new-Object -com "Microsoft.Update.UpdateColl" $updates.Add($update) | out-null $Installer.updates = $Updates try { $result = $Installer.Install() } catch { if(!($SuppressReboots)){ Restart-Computer -force } # Check for WU_E_INSTALL_NOT_ALLOWED if($_.Exception.HResult -eq -2146233087) { Write-Host "There is either an update in progress or there is a pending reboot blocking the install." -ForegroundColor Yellow $global:error.RemoveAt(0) } else { throw } } Stop-TimedSection $installSession return $result } if ([string]::IsNullOrEmpty($PSScriptRoot)) { $PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition } $Wow6432Node = "" ; if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") { $Wow6432Node = "Wow6432Node" } try { Clear-Host Write-Host "Installing App-V pre-reqs..." -ForegroundColor Magenta if (([environment]::OSVersion.Version.Major -eq 10)) { if (-not (Test-Path 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5')) { Write-Host "Win10 detected, let's only enable NetFx3...." -ForegroundColor Yellow try { DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /LimitAccess /Source:$PSScriptRoot Write-host ".Net3.5 installed." -ForegroundColor Green } catch { Write-Warning ".Net3.5 failed to install." } } else {write-host "NetFx3 allready installed." -ForegroundColor Green} } else { if (-not (Test-Path 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5')) { try { $NetFx3 = (Join-Path $PSScriptRoot "dotnetfx35.exe") if(-not (Test-Path $NetFx3)) { Write-Host ".Net3.5 source not found, let's download..." -ForegroundColor Yellow Download-File -url "http://download.microsoft.com/download/6/0/f/60fc5854-3cb8-4892-b6db-bd4f42510f28/dotnetfx35.exe" -localFile $NetFx3 } Write-Host "Installing .Net3.5 ..." -ForegroundColor Cyan Start-Process -FilePath `"$NetFx3`" -ArgumentList "/q /norestart" -Wait | Out-Null Write-host ".Net3.5 installed." -ForegroundColor Green } catch { Write-Warning ".Net3.5 failed to install." } } else {write-host ".Net3.5 allready installed." -ForegroundColor Green} if (-not (Test-Path 'HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319\SKUs\.NETFramework,Version=v4.6')) { try { $NetFx4 = (Join-Path $PSScriptRoot "NDP46-KB3045557-x86-x64-AllOS-ENU.exe") if(-not (Test-Path $NetFx4)) { Write-Host ".Net4.6 source not found, let's download..." -ForegroundColor Yellow Download-File -url "https://download.microsoft.com/download/C/3/A/C3A5200B-D33C-47E9-9D70-2F7C65DAAD94/NDP46-KB3045557-x86-x64-AllOS-ENU.exe" -localFile $NetFx4 } Write-Host "Installing .Net4.6..." -ForegroundColor Cyan Start-Process -FilePath `"$NetFx4`" -Wait | Out-Null Write-host ".Net4.6 installed." -ForegroundColor Green } catch { Write-Warning ".Net4.6 failed to install." } } else {write-host ".Net4.6 allready installed." -ForegroundColor Green} if ($host.version.Major -le 3) { try { If ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") { $WMF4 = (Join-Path $PSScriptRoot "Windows6.1-KB2819745-x64-MultiPkg.msu") if(-not (Test-Path $WMF4)) { Write-Host ".WMF4x64 source not found, let's download..." -ForegroundColor Yellow Download-File -url "https://download.microsoft.com/download/3/D/6/3D61D262-8549-4769-A660-230B67E15B25/Windows6.1-KB2819745-x64-MultiPkg.msu" -localFile $WMF4 } } else { $WMF4 = (Join-Path $PSScriptRoot "Windows6.1-KB2819745-x86-MultiPkg.msu") if(-not (Test-Path $WMF4)) { Write-Host ".WMF4x86 source not found, let's download..." -ForegroundColor Yellow Download-File -url "https://download.microsoft.com/download/3/D/6/3D61D262-8549-4769-A660-230B67E15B25/Windows6.1-KB2819745-x86-MultiPkg.msu" -localFile $WMF4 } } Write-Host "Installing WMF4 ..." -ForegroundColor Cyan Start-Process -FilePath wusa.exe -ArgumentList `"$WMF4`", "/quiet", "/norestart" -Wait | Out-Null Write-host "WMF4 installed." -ForegroundColor Green } catch { Write-Warning "WMF4 failed to install." } } else {write-host "WMF4 or higher allready installed." -ForegroundColor Green} } Write-Host "Disabling automatic Windows Updates..." -ForegroundColor Cyan New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" -Name AUOptions -PropertyType DWord -Value 1 -Force | Out-Null if (([environment]::OSVersion.Version.Major -eq 6 -and [environment]::OSVersion.Version.Minor -gt 1) -or ([environment]::OSVersion.Version.Major -gt 6)) { Write-Host "Disabling automatic Windows Store Updates..." -ForegroundColor Cyan New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsStore\WindowsUpdate" -Name AutoDownload -PropertyType DWord -Value 2 -Force | Out-Null } if (Test-Connection -ComputerName 2001:4860:4860::8888 -Count 3 -ErrorAction SilentlyContinue) # ping google for internet { Enable-MicrosoftUpdate try {Install-WindowsUpdate -Criteria "IsHidden=0 and IsInstalled=0 and Type='Software'" } catch { Install-WindowsUpdate -Criteria "IsHidden=0 and IsInstalled=0 and Type='Software'" } } Set-Service wuauserv -StartupType Disabled Write-Host "Disabling Security Center..." -ForegroundColor Cyan Set-Service -Name wscsvc -StartupType Disabled if ([environment]::OSVersion.Version.Major -lt 10) { New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" -Name HideSCAHealth -PropertyType DWord -Value 1 -Force | Out-Null } else { if (!(Test-Path -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer")) { New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer" | Out-Null } New-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer" -Name DisableNotificationCenter -PropertyType DWord -Value 1 -Force | Out-Null } Write-Host "Disabling System Restore..." -ForegroundColor Cyan Disable-ComputerRestore -Drive "C:\" Start-Process -FilePath vssadmin -ArgumentList "delete shadows /for=c: /all /quiet" -Wait | Out-Null Write-Host "Peforming SSD optimisations..." -ForegroundColor Cyan Set-Service -Name SysMain -StartupType Disabled New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters" -Name EnableSuperfetch -PropertyType DWord -Value 0 -Force | Out-Null New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters" -Name EnablePrefetcher -PropertyType DWord -Value 0 -Force | Out-Null New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\WMI\Autologger\ReadyBoot" -Name Start -PropertyType DWord -Value 0 -Force | Out-Null Write-Host "Disabling computer password change..." -ForegroundColor Cyan New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NetLogon\Parameters" -Name DisablePasswordChange -PropertyType DWord -Value 1 -Force | Out-Null Write-Host "Configuring power options..." -ForegroundColor Cyan powercfg -change -monitor-timeout-ac 0 powercfg -change -standby-timeout-ac 0 powercfg -h off Write-Host "Enabling Remote Desktop..." -ForegroundColor Cyan $oTS = Get-WmiObject -Class "Win32_TerminalServiceSetting" -Namespace root\cimv2\terminalservices if($oTS -eq $null) { Write-host "Unable to locate terminalservices namespace. Remote Desktop is not enabled." -ForegroundColor Red } try { $oTS.SetAllowTsConnections(1,1) | out-null } catch { Write-host "There was a problem enabling remote desktop. Make sure your operating system supports remote desktop and there is no group policy preventing you from enabling it." -ForegroundColor Red } Write-Host "Configuring Windows Explorer options..." -ForegroundColor Cyan Set-WindowsExplorerOptions -EnableShowHiddenFilesFoldersDrives -EnableShowFileExtensions If ([environment]::OSVersion.Version.Major -eq 6 -and [environment]::OSVersion.Version.Minor -gt 1) { Set-StartScreenOptions -EnableBootToDesktop -EnableDesktopBackgroundOnStart -EnableShowStartOnActiveScreen -EnableShowAppsViewOnStartScreen -EnableSearchEverywhereInAppsView -EnableListDesktopAppsFirst } Write-Host "Pinning taskbar shortcuts..." -ForegroundColor Cyan Install-PinnedTaskBarItem "${env:ProgramFiles(x86)}\Internet Explorer\iexplore.exe" Install-PinnedTaskBarItem "$env:windir\System32\cmd.exe" Install-PinnedTaskBarItem "$env:windir\System32\WindowsPowerShell\v1.0\powershell.exe" Install-PinnedTaskBarItem "$env:windir\regedit.exe" Install-PinnedTaskBarItem "$env:windir\Notepad.exe" Install-PinnedTaskBarItem "$env:windir\System32\SnippingTool.exe" Write-Host "Configuring Internet Explorer..." -ForegroundColor Cyan if(Test-Path "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}") { Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}" -Name "IsInstalled" -Value 0 } if(Test-Path "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}") { Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}" -Name "IsInstalled" -Value 0 } New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Internet Explorer\Main" -Name DisableFirstRunCustomize -PropertyType DWord -Value 1 -Force | Out-Null New-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Internet Explorer\Main" -Name "Start Page" -PropertyType String -Value "about:blank" -Force | Out-Null Restart-Explorer Write-host "IE Enhanced Security Configuration (ESC) has been disabled." -ForegroundColor Green if (Get-Process "OneDrive" -ErrorAction SilentlyContinue) { Write-Host "Removing OneDrive..." -ForegroundColor Cyan Start-Process -FilePath "taskkill.exe" -ArgumentList "/f /im OneDrive.exe" -Wait | Out-Null Start-Process -FilePath "C:\Windows\SysWOW64\OneDriveSetup.exe" -ArgumentList "/uninstall" -Wait | Out-Null Set-ItemProperty -Path "HKCU:\Software\classes\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}" -Name "System.IsPinnedToNameSpaceTree" -Value 0 -Force | Out-Null } Write-Host "Setting up App-V Sequencer build..." -ForegroundColor Magenta Write-Host "Disabling UAC..." -ForegroundColor Cyan New-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\policies\system" -Name EnableLUA -PropertyType DWord -Value 0 -Force | Out-Null Write-Host "Disabling Windows Defender..." -ForegroundColor Cyan if ([environment]::OSVersion.Version.Major -eq 6 -and [environment]::OSVersion.Version.Minor -lt 2) { Set-Service -Name WinDefend -StartupType Disabled } else { New-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender" -Name "DisableAntiSpyware" -PropertyType dword -Value 1 -Force | Out-Null } if (Get-Service CCmExec -ErrorAction SilentlyContinue) { Write-Host "Disabling SMS agent host..." -ForegroundColor Cyan Set-Service -Name WSearch -StartupType Disabled } Write-Host "Disabling Windows Search..." -ForegroundColor Cyan Set-Service -Name WSearch -StartupType Disabled Write-Host "Disabling FontCache..." -ForegroundColor Cyan Set-Service -Name FontCache3.0.0.0 -StartupType Disabled Write-Host "Disabling Sheduled Tasks..." -ForegroundColor Cyan schtasks /change /tn "\Microsoft\Windows\Application Experience\AitAgent" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\Application Experience\ProgramDataUpdater" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\AutoChk\Proxy" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\Customer Experience Improvement Program\Consolidator" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\Customer Experience Improvement Program\KernelCeipTask" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\Customer Experience Improvement Program\UsbCeip" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\Defrag\ScheduledDefrag" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\Diagnosis\Scheduled" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\DiskDiagnostic\Microsoft-Windows-DiskDiagnosticDataCollector" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\DiskDiagnostic\Microsoft-Windows-DiskDiagnosticResolver" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\Maintenance\WinSAT" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\Power Efficiency Diagnostics\AnalyzeSystem" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\RAC\RacTask" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\Registry\RegIdleBackup" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\Windows Error Reporting\QueueReporting" /disable | Out-Null schtasks /change /tn "\Microsoft\Windows\Windows Media Sharing\UpdateLibrary" /disable | Out-Null Write-Host "Creating dummy ODBC keys..." -ForegroundColor Cyan New-Item -Path "HKCU:\SOFTWARE\ODBC\ODBC.INI\ODBC Data Sources" -Force | Out-Null New-Item -Path "HKLM:\SOFTWARE\ODBC\ODBC.INI\ODBC Data Sources" -Force | Out-Null if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") { New-Item -Path "HKLM:\SOFTWARE\Wow6432Node\ODBC\ODBC.INI\ODBC Data Sources" -Force | Out-Null } if (-not ($SeqVersion = (Get-command "C:\Program Files\Microsoft Application Virtualization\Sequencer\Sequencer.exe" -ErrorAction SilentlyContinue).FileVersionInfo.ProductVersion)) { try { $Sequencer = (Join-Path $PSScriptRoot "appv_sequencer_setup.exe") if(-not (Test-Path $Sequencer)) { Write-Host "Sequencer source not found, please download and run the script again..." -ForegroundColor Red } else { Write-Host "Installing sequencer..." -ForegroundColor Cyan Start-Process -FilePath `"$Sequencer`" -ArgumentList "/ACCEPTEULA /q" -Wait | Out-Null Write-host "Sequencer installed." -ForegroundColor Green Install-PinnedTaskBarItem "$env:ProgramFiles\Microsoft Application Virtualization\Sequencer\Sequencer.exe" } } catch { Write-Warning "Sequencer failed to install." } } else {write-host "Sequencer $SeqVersion allready installed." -ForegroundColor Green} if (-not (Test-Path "HKLM:\SOFTWARE\$Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{A79B1F5E-FEC1-4DD7-86F3-7EB2ED1D28F2}")) { try { $ACE = (Join-Path $PSScriptRoot "ACE.msi") if(-not (Test-Path $ACE)) { Write-Host "ACE source not found, let's download..." -ForegroundColor Yellow Download-File -url "http://virtualengine.co.uk/?wpdmdl=3800" -localFile $ACE } Write-Host "Installing ACE ..." -ForegroundColor Cyan Start-Process -FilePath msiexec.exe -ArgumentList /i, `"$ACE`", RUNAPPLICATION=0, AI_QUICKLAUNCH_SH=1, AI_STARTMENU_SH=0, AI_STARTUP_SH=0, /qn -Wait | Out-Null Install-PinnedTaskBarItem "${env:ProgramFiles(x86)}\Virtual Engine\ACE\Ace.exe" Write-host "ACE installed." -ForegroundColor Green } catch { Write-Warning "ACE failed to install." } } else {write-host "ACE allready installed." -ForegroundColor Green} Write-Host "Add 'Copy as Path' Shellhandler..." -ForegroundColor Cyan Set-Location -LiteralPath "HKLM:\SOFTWARE\Classes\*\shell" | Out-Null New-Item . -Name "Copy as Path" -Force | Out-Null Set-Location -LiteralPath "HKLM:\SOFTWARE\Classes\*\shell\Copy as Path\" | Out-Null New-Item . -Name "command" -Value 'cmd.exe /c echo \"%1\"|clip' -Force | Out-Null New-Item -Path "HKLM:\SOFTWARE\Classes\Directory\shell" -Name "Copy as Path" -Force | Out-Null New-Item -Path "HKLM:\SOFTWARE\Classes\Directory\shell\Copy as Path" -Name "command" -Value 'cmd.exe /c echo \"%1\"|clip' -Force | Out-Null Set-Location $PSScriptRoot Write-Host "Optimising .NET assemblies..." -ForegroundColor Cyan Start-Process -FilePath "C:\Windows\Microsoft.NET\Framework\v4.0.30319\ngen.exe" -ArgumentList "executeQueuedItems /nologo /silent" -Wait if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") { Start-Process -FilePath "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\ngen.exe" -ArgumentList "executeQueuedItems /nologo /silent" -Wait } Write-Host "Performing disk clean up..." -ForegroundColor Cyan New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Recycle Bin" -Name "StateFlags0001" -PropertyType dword -Value 2 -Force | Out-Null New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Update Cleanup" -Name "StateFlags0001" -PropertyType dword -Value 2 -Force | Out-Null Start-Process cleanmgr.exe -ArgumentList "/sagerun:1" -Wait Remove-Item $env:temp\* -Force -Recurse Remove-Item C:\Windows\Temp\* -Force -Recurse #Zero unused sectors to allow VHD to be compacted efficiently with Optimize-VHD cmdlet $env:SEE_MASK_NOZONECHECKS = 1 if (Test-Path (Join-Path $PSScriptRoot "sdelete.exe")) { Start-Process -FilePath (Join-Path $PSScriptRoot "sdelete.exe") -ArgumentList "-AcceptEula -s -z c:" -Wait } elseif (Test-Path "\\live.sysinternals.com\tools\sdelete.exe") { Start-Process -FilePath "\\live.sysinternals.com\tools\sdelete.exe" -ArgumentList "-AcceptEula -s -z c:" -Wait } else { Write-Warning "Unable to run sysinternals sdelete.exe..." } } catch { Write-Warning $($_.Exception.Message) throw } do { $choice = Read-Host -Prompt "Reboot now? [y/n]" If ($choice -eq "y") { Write-Host "restarting now..." -ForegroundColor Green;Restart-Computer -Force} If ($choice -eq "n") { Write-Host "Reboot first, and start your Sequence." -ForegroundColor Green} } until ($choice)

Hope it Helps ,

Kenny Buntinx & Roy Essers

Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInPin on Pinterest