MMS 2015 unplugged: Unable to publish application globally if targeted user-based within Configmgr workaround

December 18, 2015 at 2:55 pm in App-V, App-V 5.0, Application Model, applications, AppV, ConfigMgr 2012, configmgr 2012 R2, ConfigMgr 2012 R2 SP1, ConfigMgr 2012 SP1, ConfigMgr SP2, ConfigMgr V.next, sccm, sccm 2012 R2, SCCM 2012 R2, SCCM 2012 R2 SP1, SCCM 2012 SP1, SCCM v.Next by Kenny Buntinx [MVP]

 

If you have been to our session called App-V standalone compared to CM12 Integrated: The Good, The Bad and The Ugly at MMS 2015 , we have showed you that some things by default cannot be done in Configmgr .

We showed a strong business case around the Application model in CM12 SP1 and using App-V 5.0 to do user-based software targeting. As most people are doing App-V integration in Configuration Manager and exploring the possibilities , they ran into some challenges I believe are critical and needs to be solved in a certain way . What the correct way is , I leave that up to the smart engineering guy’s in Redmond .

One of the great promises of application virtualization is dynamic delivery of software to end-users; however delivering plug-ins or add-ons to installed (i.e. not virtualized) software has thus far been a stumbling block. Internet Explorer has been particularly challenging due to the inability to separate the browser from the OS in a supported manner. So using App-V to deploy plug-ins like Flash or Java has meant changing the user experience with virtualization or falling back to standard install methods. Since App-V 5.0 SP2 this is very good news though, with the ability to seamlessly run an installed application inside a specified virtual environment. This means that the Flash plug-in can be delivered as a virtual package and made available to Internet Explorer without resorting to hacks or changing the user experience by providing a special shortcut.

The only requirement for specific Virtual Extensions (like the flash add-in) is that the package needs to be published Globally… only it doesn’t work great when deploying all your virtualized apps to users with System Center Configuration Manager and App-V 5.x. The table below will explain in what cases you will have to use Global publishing.

imageimage

We can overcome that hurdle with a sort of workaround that we are not going to explain in absolute detail as every customer has specific needs. See the steps below as a guide to think outside the box.

Workaround :

1. We are going to create a scheduled task which triggers on a eventID action 1003 from the eventlog “Microsoft-AppV-Client/Operational”

The script to create the scheduled task :

param( [Parameter(ParameterSetName='Register')] [switch]$Register, [Parameter(ParameterSetName='UnRegister')] [switch]$UnRegister ) switch($PsCmdlet.ParameterSetName){ "Register"{ $Xml = Get-Content (Join-Path $PSScriptRoot "ScheduledTaskTemplate_Publish.xml") $hReplace = @{ _Date_=(Get-Date -Format s) _Author_="Publish_User2Global_1.0_EN" _WorkingDirectory_=$PSScriptRoot } foreach($key in $hReplace.Keys) { $Xml = $Xml -creplace $key, $hReplace.$key } Register-ScheduledTask -Xml ($Xml | Out-String) -TaskName "1_user_Publish_User2Global" -TaskPath "Microsoft\AppV\Publishing" -Force | Out-Null $Xml = Get-Content (Join-Path $PSScriptRoot "ScheduledTaskTemplate_UnPublish.xml") $hReplace = @{ _Date_=(Get-Date -Format s) _Author_="UnPublish_User2Global_1.0_EN" _WorkingDirectory_=$PSScriptRoot } foreach($key in $hReplace.Keys) { $Xml = $Xml -creplace $key, $hReplace.$key } #Register-ScheduledTask -Xml ($Xml | Out-String) -TaskName "1_user_UnPublish_User2Global" -TaskPath "Microsoft\AppV\Publishing" -Force | Out-Null } "UnRegister"{ Get-ScheduledTask -TaskPath "\Microsoft\AppV\Publishing\" -TaskName "1_user_Publish_User2Global" | Unregister-ScheduledTask -Confirm:$False | Out-Null #Get-ScheduledTask -TaskPath "\Microsoft\AppV\Publishing\" -TaskName "1_user_UnPublish_User2Global" | Unregister-ScheduledTask -Confirm:$False | Out-Null } }

The script is based on the following templates :

<?xml version="1.0" encoding="UTF-16"?> <Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task"> <RegistrationInfo> <Date>_Date_</Date> <Author>_Author_</Author> <URI>\Microsoft\AppV\Publishing\1_user_Publish_User2Global</URI> </RegistrationInfo> <Triggers> <EventTrigger> <Enabled>true</Enabled> <Subscription>&lt;QueryList&gt;&lt;Query Id="0" Path="Microsoft-AppV-Client/Operational"&gt;&lt;Select Path="Microsoft-AppV-Client/Operational"&gt;*[System[Provider[@Name='Microsoft-AppV-Client'] and EventID=1003]]&lt;/Select&gt;&lt;/Query&gt;&lt;/QueryList&gt;</Subscription> <ValueQueries> <Value name="ThePackageId">Event/EventData/Data[@Name='Package']</Value> <Value name="TheVersionId">Event/EventData/Data[@Name='Version']</Value> <Value name="UserSid">Event/System/Security/@UserID</Value> </ValueQueries> </EventTrigger> </Triggers> <Principals> <Principal id="Author"> <GroupId>S-1-5-18</GroupId> <RunLevel>LeastPrivilege</RunLevel> </Principal> </Principals> <Settings> <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy> <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries> <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries> <AllowHardTerminate>true</AllowHardTerminate> <StartWhenAvailable>false</StartWhenAvailable> <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable> <IdleSettings> <StopOnIdleEnd>true</StopOnIdleEnd> <RestartOnIdle>false</RestartOnIdle> </IdleSettings> <AllowStartOnDemand>false</AllowStartOnDemand> <Enabled>true</Enabled> <Hidden>true</Hidden> <RunOnlyIfIdle>false</RunOnlyIfIdle> <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession> <UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine> <WakeToRun>false</WakeToRun> <ExecutionTimeLimit>P3D</ExecutionTimeLimit> <Priority>7</Priority> <RestartOnFailure> <Interval>PT1M</Interval> <Count>3</Count> </RestartOnFailure> </Settings> <Actions Context="Author"> <Exec> <Command>powershell.exe</Command> <Arguments>-NonInteractive -ExecutionPolicy RemoteSigned -WindowStyle Hidden -File User2Global.ps1 -Publish -PackageId $(ThePackageId) -VersionId $(TheVersionId) -UserSid $(UserSid)</Arguments> <WorkingDirectory>_WorkingDirectory_</WorkingDirectory> </Exec> </Actions> </Task>

2. When the scheduled task is triggered by event-ID action 1003 from the eventlog “Microsoft-AppV-Client/Operational” , we kick-off the following Powershell script (see below). It will unpublished the  package from the user and will publish the package globally instead.

param( [Parameter(ParameterSetName='Publish')] [switch]$Publish, [Parameter(ParameterSetName='UnPublish')] [switch]$UnPublish, [guid]$PackageId, [guid]$VersionId, [string]$UserSid ) Function New-BurntToastNotification{ <# This function will show a BurnToastNotification #> [CmdletBinding(SupportsShouldProcess = $True)] Param ( [Parameter(Mandatory=$True)] $Text, [Parameter(Mandatory=$True)] $Title ) # create toast template TO xml [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null $toastXml = ([Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastImageAndText02)).GetXml() # message to show on toast $stringElements = $toastXml.GetElementsByTagName("text") | select -First 1 $stringElements.AppendChild($toastXml.CreateTextNode($Title)) > $null $stringElements = $toastXml.GetElementsByTagName("text") | select -Last 1 $stringElements.AppendChild($toastXml.CreateTextNode($Text)) > $null # image $imageElements = $toastXml.GetElementsByTagName("image") $imageElements[0].src = "file:///" + "$PSScriptRoot\appv.png" # convert from System.Xml.XmlDocument to Windows.Data.Xml.Dom.XmlDocument $windowsXml = New-Object Windows.Data.Xml.Dom.XmlDocument $windowsXml.LoadXml($toastXml.OuterXml) # send toast notification $toast = New-Object Windows.UI.Notifications.ToastNotification ($windowsXml) [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("App-V").Show($toast) } Import-Module "$env:ProgramFiles\Microsoft Application Virtualization\Client\AppvClient\AppvClient.psd1" $package = Get-AppVClientPackage -PackageId $PackageId -VersionId $VersionId -All switch($PsCmdlet.ParameterSetName) { "Publish" { try { Unpublish-AppvClientPackage $package -UserSID $UserSid if (! $package.IsPublishedGlobally) { Publish-AppVClientPackage $package -Global New-BurntToastNotification -Text "$($package.name)`nSuccesfully Published Globally." -Title "App-V User2Global" } } catch { New-BurntToastNotification -Text "Something went wrong while Publishing: `n$($package.name)." -Title "App-V User2Global" } } "UnPublish" { try { if (($package = Get-AppVClientPackage -PackageId $PackageId -VersionId $VersionId -All).IsPublishedGlobally) { $package | stop-AppVClientPackage -Global -ErrorAction SilentlyContinue | Unpublish-AppvClientPackage -Global New-BurntToastNotification -Text "$($package.name)`nSuccesfully UnPublished Globally." -Title "App-V User2Global" } } catch { New-BurntToastNotification -Text "Something went wrong while unpublishing: `n$($package.name)." -Title "App-V User2Global" } } }

You can choose how to deploy the script. You can create an App-V bubble or simply deploy this with Configmgr or GPO ….

Disclaimer : The script are delivered AS-IS and are not the complete solution to this story. It is an example on how to think outside the box and make a potential solution that will fit your specific company issue.

Hope it Helps ,

Kenny Buntinx & Roy Essers .

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

Configmgr 2012 : Broken Applications in your task sequences after an upgrade (error 615)

December 14, 2015 at 1:08 pm in 615, Application Model, applications, CM12, CM12 R2, CM12 R2 SP1, CM12 SP1, CM12 SP2, ConfigMgr 2012, configmgr 2012 R2, ConfigMgr 2012 R2 SP1, ConfigMgr 2012 SP1, ConfigMgr SP2, coretech, err, error 615, OSD, SCCM 2012, sccm 2012 R2, SCCM 2012 R2, SCCM 2012 R2 SP1, SCCM 2012 SP1, troubleshooting, xmasblogroll by Kenny Buntinx [MVP]

 

Scenario: Upgrading a Configmgr 2012 RTM/SP1/R2 environment to a new R2 SP1 environment will end up into broken applications in your Task sequences with error 615 in the status messages.

Issue: After the upgrade was successfully performed , suddenly all applications within my OSD task sequence start failing with the following error code :

The task sequence failed to install application Intel Management Engine 6.0.40.1215(ScopeId_67A221E3-64F0-47D4-AA5A-BB3729EC221F/Application_2071f753-7604-42a5-b6be-b1b45c3c1f0a) for action (Install HW Driver Applications for HP8540P) in the group () with exit code 615. The operating system reported error 615: The password provided is too short to meet the policy of your user account. Please choose a longer password.

clip_image002

To be honest with my blog readers, this particular message can be caused by multiple reasons. I will list all possible solutions / workarounds that I have come across to solve this issue.

Cause 1 – Applications have no ContentID associated:

I blogged about this beginning of 2013 at http://scug.be/sccm/2013/01/08/configmgr-2012-sp1-broken-applications-after-upgrading-from-rtm/

After some checks, I saw that it concerned only applications and I discovered that had no ContentID associated to each Deployment Type. In other words, all the applications created and that are embedded in a TS with no direct deployments attached to the Application. It appears that the upgrade process broke all applications.

You can confirm this with the Application Catalog downloads as well. You will see “+++ Did not detect app deployment type”… in the AppDiscovery.log file. Additionally, the Software Center will show the error message “Failed”. Clicking on the details will result in “The software change returned error code 0x87D00607(-2016410105).”

We found as workaround, you have simply to add a comment to each DT and it will update the content ID. Nevertheless, the change means that a redistribution of your application on all your DP’s.

Following the steps as further discussed in this blog post at http://scug.be/sccm/2013/01/27/configmgr-2012-sp1-powershell-script-to-repair-broken-applications-after-upgrading-them-from-rtm/, the application will successfully install afterwards.

Cause 2 – Corrupt task sequence:

In some cases the policy that is related to the task sequence gets corrupt. This can be easily solved by creating a brand new task sequence and copying the steps from the older one side-by-side. Delete the old task sequence & create a new deployment for the just newly created task sequence.

Cause 3 – SMSMP parameter set incorrect:

I had also had problems after upgrading to SCCM R2 SP1. I was not able to install any applications as part of a task sequence as they all failed with error 615 or error 0x80004005. Installing applications outside of a Task sequence did work normally. The status message reported was exactly the same as described above "615 Password too short".

After investigating the client side log files it turned out, that the SCCM client was trying to download the application package using https first and after a few retry’s would switch to http only.

Because my DP is configured to accept http and https as like default behavior. I fixed the Problem by changing the value of the SMSMP parameter in the Task sequence step "Setup Windows and Configuration Manager" from

SMSMP=myserver.mydomain.local

to this:

SMSMP=http://myserver.mydomain.local

After this change, application installation worked as expected again.

clip_image004

Cause 4 – FIPS has been enabled :

Enabling FIPS mode makes Windows and its subsystems use only FIPS-validated cryptographic algorithms. An example is Schannel, which is the system component that provides SSL and TLS to applications. When FIPS mode is enabled, Schannel disallows SSL 2.0 and 3.0, protocols that fall short of the FIPS standards. Applications such as web browsers that use Schannel then cannot connect to HTTPS web sites that don’t use at least TLS 1.0. (Note that the same results can be achieved without FIPS mode by configuring Schannel according to KB 245030 and this blog post.)

Enabling FIPS mode also causes the .NET Framework to disallow the use of non-validated algorithms.

Microsoft advises not to use FIPS anymore as shown in the screenshot below : http://blogs.technet.com/b/secguide/archive/2014/04/07/why-we-re-not-recommending-fips-mode-anymore.aspx

clip_image006

In our case this solved the issue with the error 615. Probably it was a combination of things , but this is certainly something to disable and try.

Cause 5 – Use the latest CU2 on CM12 R2 SP1 :

Always make sure to use the latest CU’s as they include important fixes . You can download CU2 over here : https://support.microsoft.com/en-us/kb/3100144#/en-us/kb/3100144

The two most important fixes that may help to avoid error 615 in CU2 for R2 SP1 are :

– Applications will not install when you use them with a dynamic variable list in a task sequence if no SMB package share was defined for the content. This affects only installations that use a dynamic variable list. Other installation methods are unaffected.

No Http location found
Failed to download content for SMS package PRI00080, hr=0x80004005
Install Dynamic software action failed to resolve content for packageID: ‘PRI00080′, programID: ‘TestApp’. Error Code 0x80004005

– In a Configuration Manager environment in which multiple certificates are deployed to client computers, the client may select the wrong certificate for use in management point communication. This occurs when one certificate is based on a version 2 template and one is based on version 3. The client will select the certificate that has the longest validity period. This may be the version 3 certificate, and this certificate may not be currently supported by Configuration Manager. Errors that resemble the following are recorded in the ClientIDManagerStartup.log file.

[RegTask] – Executing registration task synchronously.
RegTask: Failed to create registration request body. Error: 0x80090014

 

Hope it Helps ,

Kenny Buntinx

MVP Enterprise Mobility

Detect, Inventory and report about the encryption method used by Bitlocker thru ConfigMgr

October 5, 2015 at 6:54 pm in bitlocker, ConfigMgr 2007, ConfigMgr 2007 R2, ConfigMgr 2012, configmgr 2012 R2, ConfigMgr 2012 R2 SP1, ConfigMgr 2012 SP1, ConfigMgr Dashboards, ConfigMgr SP2, Encryption, Inventory, sccm, SCCM 2007, SCCM 2007 R2, SCCM 2007 R3, SCCM 2007 SP2, SCCM 2012, sccm 2012 R2, SCCM 2012 R2, SCCM 2012 R2 SP1, SCCM 2012 SP1, SCCM Dashboards, sccm RTM, SCCM v.Next, sccm2007 by Kenny Buntinx [MVP]

 

Recently at a client, we needed to provide a report that was listing what Bitlocker Encryption strength method was used. That information had to be fed into the CMDB to make sure we had ‘256AES with Diffuser’ enabled.

Unfortunately, Configmgr 2012 does deliver out-of-the-box a way to determine what Bitlocker Encryption strength method, and that means the information is not in the registry or WMI.

Dependencies :

Well I tried to find an easy way , and the customer required a solution that was :

– Flexible and dynamic as they where constantly migrating from Mcafee Disk Encryption to Bitlocker and the CMDB had to be dynamically updated.

– Centrally managed code , meaning that if we needed to change anything to the code , it had to be intelligent enough to update it auto magically to all clients.

– Had to be reliable .

The solution :

– was to use a kind of detection powershell script for the Bitlocker Encryption strength using the standard powershell commandlet ‘Manage-bde’ .

– The script was to be used with a “compliance Item” and deployed thru a “Baseline” as one of my colleagues Henrik Hoe explains here :  http://blog.coretech.dk/heh/configuration-items-and-baselines-using-scripts-powershell-example/ . By using a CI , you will meet the centrally managed code part , but also the automatically way of updating the detection logic to all clients.

Forget about the old package/program way and then a way to execute the script on regular basis ( That can all be done thru the Baseline deployment)

– The script will be executed and will write a registry value BitlockerEncryptionStrenght = “TheActualValue”  and the baseline will report complaint when it has the ‘256AES with Diffuser’ detected. When the machine is not bitlockered at all , we will write a value  BitlockerEncryptionStrenght = “None”

$ErrorActionPreference="silentlycontinue" $StrBEncryption = "" $objBEncryption = "" $objBEncryption=manage-bde.exe -status |Where-Object{$_ -like "*encryption method*"} $arrBEncryption=$objBEncryption.Split(":") $StrBEncryption=$arrBEncryption[1].Trim() If ($StrBEncryption.Contains("AES")) { New-ItemProperty -Path HKLM:\SYSTEM\ABPosdInstall -Name BitlockerEncryptionStrenght -Value $StrBEncryption -Property String -Force -ErrorAction SilentlyContinue | Out-Null if ($StrBEncryption -eq "AES 256 with Diffuser") { return 1 } } Else { New-ItemProperty -Path HKLM:\SYSTEM\ABPosdInstall -Name BitlockerEncryptionStrenght -Value "None" -Property String -Force -ErrorAction SilentlyContinue | Out-Null Return 0 }

– We will pick the value up later with a custom registry key hardware inventory extension and use that in our reporting later on. For more details on how to do it : https://technet.microsoft.com/en-us/library/gg712290.aspx

Hope it Helps ,

Kenny Buntinx

Enterprise Client Management MVP

Detect if machine has an SSD and report on it thru custom HW inventory

September 30, 2015 at 7:18 am in ConfigMgr 2012, configmgr 2012 R2, ConfigMgr 2012 R2 SP1, ConfigMgr 2012 SP1, HW inventory, OSD, sccm, SCCM 2012, sccm 2012 R2, SCCM 2012 R2, SCCM 2012 R2 SP1, SCCM 2012 SP1, SCCM v.Next, SSD, windows 10, Windows 7, Windows 7 SP1, windows 8, windows 8.1 by Kenny Buntinx [MVP]

 

Recently at a client, we needed to provide a report that was listing whether a workstation or laptop had an SSD or a spinning disk. That information had to be fed into the CMDB

Unfortunately, Windows or Configmgr 2012 does deliver out-of-the-box a way to determine a disk is spinning or solid state, and that means the information is not in the registry or WMI.

Dependencies :

Well I tried to find an easy way , and the customer required a solution that was :

– Flexible and dynamic as they where constantly upgrading physical disks to SSD and there CMDB had to be dynamically updated.

– Centrally managed code , meaning that if we needed to change anything to the code , it had to be intelligent enough to update it auto magically to all clients.

– Had to be reliable .

The solution :

– was to use a kind of detection powershell script for the SSD that we grabbed initially from here : “https://gist.github.com/grantcarthew/c74bbfd3eba167cd3a7a#file-test-ssd” but slightly altered it to fit our needs.

– The script was altered to be used with a “compliance Item” and deployed thru a “Baseline” as one of my colleagues Henrik Hoe explains here :  http://blog.coretech.dk/heh/configuration-items-and-baselines-using-scripts-powershell-example/ . By using a CI , you will meet the centrally managed code part , but also the automatically way of updating the detection logic to all clients.

Forget about the old package/program way and then a way to execute the script on regular basis ( That can all be done thru the Baseline deployment)

– The script will be executed and will write a registry value SSD_Detected = 1 or 0 and the baseline will report complaint when it has an SSD detected.

 

<# .SYNOPSIS Detects if the passed Physical Disk Id is a Solid State Disk (SSD) or a spindle disk. Returns true for an SSD and false for anything else. .DESCRIPTION The methods used for detecting are by reading the Nominal Media Rotation Rate and Seek Penalty. These values are measured through method calls into the Kernel32.dll. If either of the Win32 DLL calls return true then the script will return false. If an exception occurs in either of the Win32 DLL calls, the return value will be dependant on the remaining call. .PARAMETER PhysicalDiskId The LUN based physical disk id. #> $Code = @" using Microsoft.Win32.SafeHandles; using System; using System.Runtime.InteropServices; using System.Text; namespace Util { public class DetectSSD { // For CreateFile to get handle to drive private const uint GENERIC_READ = 0x80000000; private const uint GENERIC_WRITE = 0x40000000; private const uint FILE_SHARE_READ = 0x00000001; private const uint FILE_SHARE_WRITE = 0x00000002; private const uint OPEN_EXISTING = 3; private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; // CreateFile to get handle to drive [DllImport("kernel32.dll", SetLastError = true)] private static extern SafeFileHandle CreateFileW( [MarshalAs(UnmanagedType.LPWStr)] string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile); // For control codes private const uint FILE_DEVICE_MASS_STORAGE = 0x0000002d; private const uint IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE; private const uint FILE_DEVICE_CONTROLLER = 0x00000004; private const uint IOCTL_SCSI_BASE = FILE_DEVICE_CONTROLLER; private const uint METHOD_BUFFERED = 0; private const uint FILE_ANY_ACCESS = 0; private const uint FILE_READ_ACCESS = 0x00000001; private const uint FILE_WRITE_ACCESS = 0x00000002; private static uint CTL_CODE(uint DeviceType, uint Function, uint Method, uint Access) { return ((DeviceType << 16) | (Access << 14) | (Function << 2) | Method); } // For DeviceIoControl to check no seek penalty private const uint StorageDeviceSeekPenaltyProperty = 7; private const uint PropertyStandardQuery = 0; [StructLayout(LayoutKind.Sequential)] private struct STORAGE_PROPERTY_QUERY { public uint PropertyId; public uint QueryType; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public byte[] AdditionalParameters; } [StructLayout(LayoutKind.Sequential)] private struct DEVICE_SEEK_PENALTY_DESCRIPTOR { public uint Version; public uint Size; [MarshalAs(UnmanagedType.U1)] public bool IncursSeekPenalty; } // DeviceIoControl to check no seek penalty [DllImport("kernel32.dll", EntryPoint = "DeviceIoControl", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool DeviceIoControl( SafeFileHandle hDevice, uint dwIoControlCode, ref STORAGE_PROPERTY_QUERY lpInBuffer, uint nInBufferSize, ref DEVICE_SEEK_PENALTY_DESCRIPTOR lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped); // For DeviceIoControl to check nominal media rotation rate private const uint ATA_FLAGS_DATA_IN = 0x02; [StructLayout(LayoutKind.Sequential)] private struct ATA_PASS_THROUGH_EX { public ushort Length; public ushort AtaFlags; public byte PathId; public byte TargetId; public byte Lun; public byte ReservedAsUchar; public uint DataTransferLength; public uint TimeOutValue; public uint ReservedAsUlong; public IntPtr DataBufferOffset; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] PreviousTaskFile; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] CurrentTaskFile; } [StructLayout(LayoutKind.Sequential)] private struct ATAIdentifyDeviceQuery { public ATA_PASS_THROUGH_EX header; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public ushort[] data; } // DeviceIoControl to check nominal media rotation rate [DllImport("kernel32.dll", EntryPoint = "DeviceIoControl", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool DeviceIoControl( SafeFileHandle hDevice, uint dwIoControlCode, ref ATAIdentifyDeviceQuery lpInBuffer, uint nInBufferSize, ref ATAIdentifyDeviceQuery lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped); // For error message private const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; [DllImport("kernel32.dll", SetLastError = true)] static extern uint FormatMessage( uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, StringBuilder lpBuffer, uint nSize, IntPtr Arguments); // Method for no seek penalty public static bool HasSeekPenalty(string sDrive) { SafeFileHandle hDrive = CreateFileW( sDrive, 0, // No access to drive FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero); if (hDrive == null || hDrive.IsInvalid) { string message = GetErrorMessage(Marshal.GetLastWin32Error()); throw new System.Exception(message); } uint IOCTL_STORAGE_QUERY_PROPERTY = CTL_CODE( IOCTL_STORAGE_BASE, 0x500, METHOD_BUFFERED, FILE_ANY_ACCESS); // From winioctl.h STORAGE_PROPERTY_QUERY query_seek_penalty = new STORAGE_PROPERTY_QUERY(); query_seek_penalty.PropertyId = StorageDeviceSeekPenaltyProperty; query_seek_penalty.QueryType = PropertyStandardQuery; DEVICE_SEEK_PENALTY_DESCRIPTOR query_seek_penalty_desc = new DEVICE_SEEK_PENALTY_DESCRIPTOR(); uint returned_query_seek_penalty_size; bool query_seek_penalty_result = DeviceIoControl( hDrive, IOCTL_STORAGE_QUERY_PROPERTY, ref query_seek_penalty, (uint)Marshal.SizeOf(query_seek_penalty), ref query_seek_penalty_desc, (uint)Marshal.SizeOf(query_seek_penalty_desc), out returned_query_seek_penalty_size, IntPtr.Zero); hDrive.Close(); if (query_seek_penalty_result == false) { string message = GetErrorMessage(Marshal.GetLastWin32Error()); throw new System.Exception(message); } else { return query_seek_penalty_desc.IncursSeekPenalty; } } // Method for nominal media rotation rate // (Administrative privilege is required) public static bool HasNominalMediaRotationRate(string sDrive) { SafeFileHandle hDrive = CreateFileW( sDrive, GENERIC_READ | GENERIC_WRITE, // Administrative privilege is required FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero); if (hDrive == null || hDrive.IsInvalid) { string message = GetErrorMessage(Marshal.GetLastWin32Error()); throw new System.Exception(message); } uint IOCTL_ATA_PASS_THROUGH = CTL_CODE( IOCTL_SCSI_BASE, 0x040b, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); // From ntddscsi.h ATAIdentifyDeviceQuery id_query = new ATAIdentifyDeviceQuery(); id_query.data = new ushort[256]; id_query.header.Length = (ushort)Marshal.SizeOf(id_query.header); id_query.header.AtaFlags = (ushort)ATA_FLAGS_DATA_IN; id_query.header.DataTransferLength = (uint)(id_query.data.Length * 2); // Size of "data" in bytes id_query.header.TimeOutValue = 3; // Sec id_query.header.DataBufferOffset = (IntPtr)Marshal.OffsetOf( typeof(ATAIdentifyDeviceQuery), "data"); id_query.header.PreviousTaskFile = new byte[8]; id_query.header.CurrentTaskFile = new byte[8]; id_query.header.CurrentTaskFile[6] = 0xec; // ATA IDENTIFY DEVICE uint retval_size; bool result = DeviceIoControl( hDrive, IOCTL_ATA_PASS_THROUGH, ref id_query, (uint)Marshal.SizeOf(id_query), ref id_query, (uint)Marshal.SizeOf(id_query), out retval_size, IntPtr.Zero); hDrive.Close(); if (result == false) { string message = GetErrorMessage(Marshal.GetLastWin32Error()); throw new System.Exception(message); } else { // Word index of nominal media rotation rate // (1 means non-rotate device) const int kNominalMediaRotRateWordIndex = 217; if (id_query.data[kNominalMediaRotRateWordIndex] == 1) { return false; } else { return true; } } } // Method for error message private static string GetErrorMessage(int code) { StringBuilder message = new StringBuilder(255); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, IntPtr.Zero, (uint)code, 0, message, (uint)message.Capacity, IntPtr.Zero); return message.ToString(); } } } "@ # Function CheckSSD($PhysicalDiskId) { #initialize Add-Type -TypeDefinition $Code $hasRotationRate = $true $hasSeekPenalty = $true $driveString = "\\.\PhysicalDrive" + $PhysicalDiskId #Check RotationRate try { $hasRotationRate = [Util.DetectSSD]::HasNominalMediaRotationRate([string]$driveString) } catch { #"HasNominalMediaRotationRate detection failed with the following error;" # $Error[0].Exception.Message $hasRotationRate = $true } #Check SeekPenalty try { $hasSeekPenalty = [Util.DetectSSD]::HasSeekPenalty([string]$driveString) } catch { #"HasSeekPenalty detection failed with the following error;" #$Error[0].Exception.Message $hasSeekPenalty = $true } # Only return true if the disk has no rotation rate or no seek penalty. If ($hasRotationRate -eq 0 -and $hasSeekPenalty -eq 0) { #SSD detected New-ItemProperty -Path HKLM:\SYSTEM\ABPosdInstall -Name SSD_Detected -Value 1 -PropertyType DWORD -Force -ErrorAction SilentlyContinue | Out-Null Return 1 } Else { #No SSD detected New-ItemProperty -Path HKLM:\SYSTEM\ABPosdInstall -Name SSD_Detected -Value 0 -PropertyType DWORD -Force -ErrorAction SilentlyContinue | Out-Null Return 0 } } #initialize #Default No SSD detected $ResultCheckSSD=0 #check disk 0 Try { $ResultCheckSSD=CheckSSD(0) return $ResultCheckSSD } Catch { #error then no SSD detected $ResultCheckSSD=0 }

– We will pick the value up later with a custom registry key hardware inventory extension and use that in our reporting later on. For more details on how to do it : https://technet.microsoft.com/en-us/library/gg712290.aspx

 

Hope it Helps,

Kenny Buntinx

MVP Enterprise Client Management

MVP Award Renewal for 2015-2016: Enterprise Client Management

July 2, 2015 at 7:28 pm in MVP by Kenny Buntinx [MVP]

 

I’m very proud to inform you that my MVP award got renewed for the year 2015 – 2016 on Enterprise Client Management. This is certainly a great honor for me.

Thank you Microsoft, blog readers and all the community members that helped me out!

Thanks for the recognition. I am delighted.

Kenny Buntinx

Enterprise Client Management MVP

images7T7SFLEG

HCIDKIDT ever since CM12 R2 SP1 : Software update groups additional data available in the console

June 25, 2015 at 6:09 pm in 2012R2, CM12 R2, CM12 R2 SP1, CM12 SP2, SCCM 2012 R2, SCCM 2012 R2 SP1, Software updates by Kenny Buntinx [MVP]

 

Hello Folks ,

I didn’t realize that one of my personal wishes has been granted in CM12R2 sp1. I always wanted a quick overview at my software group on how much updates it contained , how many expired and to how many collection I deployed it too …and now it is reality . Good work PG !

Non R2 SP1 :

image

With R2 SP1 :

image

 

Hope it Helps ,

Kenny Buntinx

How to replace expired certificates on ADFS 3.0 the right way

June 4, 2015 at 1:44 pm in 2012R2, ADFS, ADFS 3.0, BYOD, certificates, Cloud, Enterprise Mobility Suite, Global Managed Service Account, IIS, Known Issue, Lab, Power Management, WAP, Web Application Proxy by Kenny Buntinx [MVP]

 

As with all IT equipment that is using certificates for enhanced security, there will be a time when the certificates expire and it will need to be replaced. Below you will find the procedure for ADFS 3.0 and the Web Application Proxy:

First step is to create a new CSR on one of you’re servers and request a renewal of the existing certificate ( in our case a *.demolabs.be) . After the request has been processed , download your certificate and import the certificate on the server where you created the CRS earlier. For ADFS / WAP it is very important you will have the private key exported with the certificate. You can only export the certificate with a private key on the sever where you previously created the CSR .Export with private keys to *.pfx and import on WAP + ADFS

If you do not do it as described above with and export of the private keys , you will face issues even if you did it exactly as described below as shown in the screenshot below :

image

 

Follow the procedure below , starting with the ADFS server:

  1. Log onto the ADFS server.
  2. Import the new (exported with private key) certificate to the server. Make sure this is added to the personal certificate store for the computer account.
  3. Find your thumbprint for the new certificate. Either use the GUI thru the MMC to see the details of the certificate or us powershell with Run Get-AdfsSslCertificate.. Take a copy of the thumbprint and ensure that the spaces are removed.
  4. Make sure that the service account that is running the ‘Active Directory Federation Services’ service is granted read access to the private key.
  5. Launch AD FS Management, expand ‘Service’ within the left pane and click ‘Certificates’ , then click ‘Set Service Communications Certificate

image

 

  1. Restart the ADFS services. However this is not enough. Changes made in  the GUI does not change the configuration based on the HTTP.sys. To complete the configuration change, run the following PowerShell command : Set-AdfsSslCertificate –Thumbprint <Thumbprintofyourcertificate>.
  2. Make sure to restart the server

Now you need to log onto the WAP server.

  1. Import the new (exported with private key) certificate to the server as in step 1. 
  2. Run the PowerShell commando for changing the certificate: Set-WebApplicationProxySslCedrtificate –Thumbprint <Thumbprintofyourcertificate>
  3. All of your publishing rules defined in the WAP need to be updated with the thumbprint of the new certificate. Use Powershell for  updating them with the new thumbprint. Run: Get-WebApplicationProxyApplication –Name “WebAppPublishingRuleName” | Set-WebApplicationProxyApplication –ExternalCertificateThumbprint “<Thumbprintofyourcertificate>”
  4. Restart the Web Application Proxy services to complete the configuration

Now you are done and you are a happy admin once more . Took me some time to figure it out .

Hope it Helps ,

Kenny Buntinx

MVP Enterprise Client Management

ConfigMgr 2012 NDES Site Role not healthy anymore after R2 SP1 upgrade

June 2, 2015 at 8:06 am in configmgr 2012 R2, ConfigMgr 2012 R2 SP1, EMS, ndes, R2 SP1, sccm 2012 R2, SCCM 2012 R2, SCCM 2012 R2 SP1, SP1, Windows Intune, windows inune by Kenny Buntinx [MVP]

 

A key feature of the mobile device management capabilities provided by System Center 2012 R2 Configuration Manager with Windows Intune is the ability to provision client certificates to managed devices.  Organizations that use an enterprise PKI for client authentication to resources like WiFi and VPN can use this feature to provision certificates to Windows, Windows Phone, iOS, and Android devices managed through Windows Intune.  This article provides an in-depth look at how this feature works, and where you can go to find out all of the information you need to get up and running.

For those customers that are using NDES and did an upgrade from System center Configuration Manager 2012 R2 to System center Configuration Manager 2012 R2 SP1  they will notice that their NDES Server hosting the NDES Site Server role will fail to reinstall as shown below in the screenshot :

image

Investigating the issue a little further and going to look at the logging (CRPSetup.log) on the NDES server hosting the NDES Site Server role , we got the error message “Enabling WCF 40 returned code 50. Please enable WCF HTTP Activation. “

image

The question is why it would complain now as it worked before . After investigation it turns out that System Center Configuration Manager 2012 R2 Sp1 supports now  the provisioning of  personal information exchange (.pfx) files to user’s devices including Windows 10, iOS, and Android devices. Devices can use PFX files to support encrypted data exchange.

In the Supported Configurations for Configuration Manager ( https://technet.microsoft.com/en-us/library/gg682077.aspx#BKMK_SiteSystemRolePrereqs ) , we found out that now “Http activation is required”

image

After enabling the feature , the role started to reinstall itself .

image

Looking at the log file it seems that is is installed :

image

Looks like the role installed itself and thus problem solved.

Hope it helps ,

Kenny Buntinx

MVP Enterprise Client Management

Announcing the availability of System Center 2012 R2 Configuration Manager SP1 and System Center 2012 Configuration Manager SP2

May 14, 2015 at 4:11 pm in CM12, CM12 R2, CM12 R2 SP1, CM12 SP1, CM12 SP2, sccm, SCCM 2012, sccm 2012 R2, SCCM 2012 R2, SCCM 2012 SP1 by Kenny Buntinx [MVP]

 

Following the announcements made at the Microsoft Ignite conference last week, I am happy to let you know that System Center 2012 R2 Configuration Manager SP1 and System Center 2012 Configuration Manager SP2 are now generally available and can be downloaded on the Microsoft Evaluation Center. These service packs deliver full compatibility with existing features for Windows 10 deployment, upgrade, and management.

Also included in these service packs are new hybrid features for customers using System Center Configuration Manager integrated with Microsoft Intune to manage devices. Some of the hybrid features that you can expect to see are conditional access policy, mobile application management, and support for Apple Device Enrollment Program (DEP). You can view the full list of hybrid features included in these service packs here.

As a side note : To be absolutely sure that there will be no bear on the road during deployment for SP2 , please install CU5 http://blogs.technet.com/b/configmgrteam/archive/2015/05/06/now-available-cumulative-update-5-for-system-center-2012-r2-configuration-manager.aspx first before upgrading to SP2 as there is one issue fixed in CU5 that could affect R2 SP1 installation:

– if you have over 10,000 deployments for legacy software distribution packages the R2 SP1 upgrade could stall. Installing CU5 beforehand will prevent this. This does not make CU5 an official pre-req though, as the given scenario should be rare but it doesn’t hurt to install CU5 first on the site servers , before upgrading to CM12 R2 SP1 or CM12 SP2 , without upgrading you’re clients.

Hope it Helps ,

Kenny Buntinx

MVP Enterprise Client Management