Quantcast
Channel: Aaron Parker
Viewing all 177 articles
Browse latest View live

Monitoring MDT Task Sequences with PowerShell

$
0
0

The Microsoft Deployment Toolkit provides a Lite Touch deployment model – typically a device requires an engineer to manually start the deployment task sequence. Using PowerShell to drive MDT offers the chance to provide a little more automation around OS deployments.

Here’s a couple of sample videos that demonstrate the use of PowerShell to automate OS deployments using MDT task sequences. Both of these examples are utilising the monitoring feature in MDT 2012 to watch the progress of each task sequence to enable managing the complete deployment, both before and after the task sequence.

Using PowerShell with MDT

To use PowerShell with MDT requires installing the MDT console which will provide the PowerShell snapin support. For this article, I’ve used MDT 2012 Update 1. Either 32-bit or 64-bit should work.

I’m first going to set a couple of variables. In this instance, I’ve set the computer name of the target machine that I want to monitor and the path to the MDT deployment share. For this example, I’m using a local path because I’m running the PowerShell script on the server hosting the MDT deployment share. A UNC path will also work.

$target = "VM1"
$deploymentShare = "E:\Deployment"

To manage MDT we need to load the MDT snapin and create a PowerShell drive that will be used to access the MDT deployment share.

Add-PSSnapin "Microsoft.BDD.PSSNAPIN"
If (!(Test-Path MDT:)) { New-PSDrive -Name MDT -Root $deploymentShare -PSProvider MDTPROVIDER }

Before starting the task sequence, I want to remove any existing monitoring data that might exist for the target machine. Duplicates are possible, so I want to remove all entries to ensure monitoring will be successful. The following line will remove any existing monitoring data for the machine specified by $target:

Get-MDTMonitorData -Path MDT: | Where-Object { $_.Name -eq $target } | Remove-MDTMonitorData -Path MDT:

Once the target machine has booted into the Lite Touch WinPE environment, monitoring data should be sent to the MDT server; however we aren’t interested in that data yet because it will be pre-task sequence, which isn’t much use to us.

The screenshot below shows the monitoring data returned pre-task sequence. Typically, any machine name that starts with MININT will be the WinPE environment:

Pre-TaskSequence

So, although we can start gathering data, we really need to wait or loop until the task sequence starts. When the task sequence has started, we can then get monitoring data for the target machine. The example below shows an in-progress task sequence:

TaskSequence-Progress

To gather data, use the Get-MDTMonitorData cmdlet and save the output to a variable:

$InProgress = Get-MDTMonitorData -Path MDT: | Where-Object { $_.Name -eq $target }

The information returned proves interesting as it includes the percentage of the task sequence complete, the current step and the step name:

PS C:\> $InProgress

Name               : VM1
PercentComplete    : 30
Settings           :
Warnings           : 0
Errors             : 0
DeploymentStatus   : 1
StartTime          : 02/06/2013 17:05:23
EndTime            :
ID                 : 32
UniqueID           : c7b224e0-a918-4182-a370-96d5c9cb7410
CurrentStep        : 40
TotalSteps         : 131
StepName           : Install Operating System
LastTime           : 02/06/2013 17:05:39
DartIP             :
DartPort           :
DartTicket         :
VMHost             :
VMName             :
ComputerIdentities : {}

Using these properties and the Write-Progress cmdlet we can display the progress of the task sequence and some status info during execution of the script:

TaskSequenceWriteProgress

Putting this together, we need a script that will perform the following high level tasks:

  1. Connects to the MDT share
  2. Removes any existing monitoring data for the target machine
  3. Waits for the task sequence to begin by interrogating the MDT monitoring data until the right machine data is returned
  4. Monitors and displays the progress of the task sequence so that we can continue processing once the deployment is complete

The Complete Script

The script listing below put these pieces together and provides two loops – one that waits for the task sequence to begin and once it has, waits for the task sequence to complete.

$target = "VM1"
$deploymentShare = "E:\Deployment"

# Connect to the MDT share
Write-Host "Connecting to MDT share." -ForegroundColor Green
Add-PSSnapin "Microsoft.BDD.PSSNAPIN"
If (!(Test-Path MDT:)) { New-PSDrive -Name MDT -Root $deploymentShare -PSProvider MDTPROVIDER }

# Clean up the MDT monitor data for the target VM if it exists
Write-Host "Clearing MDT monitor data." -ForegroundColor Green
Get-MDTMonitorData -Path MDT: | Where-Object { $_.Name -eq $target } | Remove-MDTMonitorData -Path MDT:

# Wait for the OS deployment to start before monitoring
# This may require user intervention to boot the VM from the MDT ISO if an OS exists on the vDisk
If ((Test-Path variable:InProgress) -eq $True) { Remove-Variable -Name InProgress }
Do {
    $InProgress = Get-MDTMonitorData -Path MDT: | Where-Object { $_.Name -eq $target }
    If ($InProgress) {
        If ($InProgress.PercentComplete -eq 100) {
            $Seconds = 30
            $tsStarted = $False
            Write-Host "Waiting for task sequence to begin..." -ForegroundColor Green
        } Else {
            $Seconds = 0
            $tsStarted = $True
            Write-Host "Task sequence has begun. Moving to monitoring phase." -ForegroundColor Green
        }
    } Else {
        $Seconds = 30
        $tsStarted = $False
        Write-Host "Waiting for task sequence to begin..." -ForegroundColor Green
    }
    Start-Sleep -Seconds $Seconds
} Until ($tsStarted -eq $True)

# Monitor the MDT OS deployment once started
Write-Host "Waiting for task sequence to complete." -ForegroundColor Green
If ((Test-Path variable:InProgress) -eq $True) { Remove-Variable -Name InProgress }
Do {
    $InProgress = Get-MDTMonitorData -Path MDT: | Where-Object { $_.Name -eq $target }
    If ( $InProgress.PercentComplete -lt 100 ) {
        If ( $InProgress.StepName.Length -eq 0 ) { $StatusText = "Waiting for update" } Else { $StatusText = $InProgress.StepName }
        Write-Progress -Activity "Task sequence in progress" -Status $StatusText -PercentComplete $InProgress.PercentComplete
        Switch ($InProgress.PercentComplete) {
            {$_ -lt 25}{$Seconds = 35; break}
            {$_ -lt 50}{$Seconds = 30; break}
            {$_ -lt 75}{$Seconds = 10; break}
            {$_ -lt 100}{$Seconds = 5; break}
        }
        Start-Sleep -Seconds $Seconds
    } Else {
        Write-Progress -Activity "Task sequence complete" -Status $StatusText -PercentComplete 100
    }
} Until ($InProgress.CurrentStep -eq $InProgress.TotalSteps)
Write-Host "Task sequence complete." -ForegroundColor Green

Creative Commons LicenseMonitoring MDT Task Sequences with PowerShell is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2013 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

Automating the XenDesktop 7 Virtual Desktop Agent Installation

$
0
0

Citrix provides a nice wizard for installing the XenDesktop 7 VDA and some pretty good documentation on using a command line installation, but the wizard does not expose all of the available options and working out what the wizard is doing in relation to the command line takes a bit of translation. Here’s how to automate a typical VDA deployment.

I usually use a batch file to deploy components, so the commands I’ve listed here assume you’ll be using a batch file too. To make the batch file easier to read, I place all command line options in an environment variable named OPTIONS. To start with, I’m going to set a couple of items that will enable an unattended deployment:

SET OPTIONS=
SET OPTIONS=/QUIET
SET OPTIONS=%OPTIONS% /NOREBOOT

When running the wizard, you’re first asked whether you’re deploying to a master image, or a persistent virtual machine/physical PC.

1_Configuration

In this example, I’m deploying to a master image, so I’ll set the MASTERIMAGE flag:

SET OPTIONS=%OPTIONS% /MASTERIMAGE

The next page lists the options to install the VDA and optionally Receiver:

2_CoreComponents

I’m just looking to install the VDA, but I could also install Receiver, by adding PLUGINS to the COMPONENTS option:

SET OPTIONS=%OPTIONS% /COMPONENTS VDA

Next up is configuring the location of the Delivery Controllers.

3_DeliveryController

I’m going to specify a static list of Controllers using the aptly named CONTROLLERS property:

SET OPTIONS=%OPTIONS% /CONTROLLERS "ctx-xd7-ddc1.lab.com,ctx-xd7-ddc2.lab.com"

There are additional options at this point and the recommended approach is to specify the XD site GUID using SITE_GUID (this is the same as ‘Choose locations from Active Directory’ shown below). Don’t use CONTROLLERS and SITE_GUID at the same time.

The last option – ‘Let Machine Creation Services do it automatically’ doesn’t appear to be available as a command line option. From the command line perspective, I assume this is the same as not specifying CONTROLLERS or SITE_GUID at all.

ConfigurationOptions

The Features page lists a few options that look completely unrelated, but I assume they need to go somewhere.

4_Features

Each feature has its own command line option. In my case, I don’t really need to add the option for Remote Assistance, because I’ve used an automated deployment that has already enabled that feature, but it doesn’t hurt to enable the option anyway.

SET OPTIONS=%OPTIONS% /OPTIMIZE
SET OPTIONS=%OPTIONS% /ENABLE_REMOTE_ASSISTANCE
SET OPTIONS=%OPTIONS% /ENABLE_REAL_TIME_TRANSPORT

The VDA requires several inbound ports for core features to work.

5_Firewall

Fortunately, Windows Firewall configuration is simple using the ENABLE_HDX_PORTS flag:

SET OPTIONS=%OPTIONS% /ENABLE_HDX_PORTS

Finally then, a summary of what the wizard is about to install and configure. It’s worth pointing out that for Windows Server workloads, you will need to install the Remote Desktop Session Host before installing the VDA. If the RDSH role is not installed, setup will install it and reboot the server.  This will potentially break your automated deployment; however, if you’ve used the right approach and automated the deployment of Windows, then this role will already be enabled.

6_Summary

With my script created now, I can automate the deployment of the VDA as a component of automating the entire deployment of the master image. Here’s a sample script that will use the options listed above for 32-bit or 64-bit platforms.

SET OPTIONS=
SET OPTIONS=/QUIET
SET OPTIONS=%OPTIONS% /NOREBOOT
SET OPTIONS=%OPTIONS% /MASTERIMAGE
SET OPTIONS=%OPTIONS% /COMPONENTS VDA
SET OPTIONS=%OPTIONS% /CONTROLLERS "ctx-xd7-ddc1.lab.com,ctx-xd7-ddc2.lab.com"
SET OPTIONS=%OPTIONS% /OPTIMIZE
SET OPTIONS=%OPTIONS% /ENABLE_REMOTE_ASSISTANCE
SET OPTIONS=%OPTIONS% /ENABLE_REAL_TIME_TRANSPORT
SET OPTIONS=%OPTIONS% /ENABLE_HDX_PORTS

IF "%PROCESSOR_ARCHITECTURE%"=="AMD64" PUSHD "x64\XenDesktop Setup"
IF "%PROCESSOR_ARCHITECTURE%"=="x86" PUSHD "x86\XenDesktop Setup"
START /WAIT XenDesktopVDASetup.exe %OPTIONS%

In the lab, I’ve imported a full copy of the XenDesktop 7 ISO into my MDT deployment share, where I’ve configured install scripts for Controllers (with Studio and Director), StoreFront and various flavours of VDA deployments (desktop, server, physical PCs etc).

The documentation is quite clear and easy to understand; however there’s a few options that I would recommend having clear understanding of what they enable:

  • OPTIMIZE – this option will optimise the base image for a virtual machine using the changes outlined in this support article: How to Optimize XenDesktop Machines. I would recommend understanding clearly what each change does and removing this option if you have implemented your own optimisations.
  • NODESKTOPEXPERIENCE – I utilise my own solution for making a Windows Server look like a desktop OS and would generally leave this out as a result. This enables the default Citrix wallpaper, which is pretty horrible.
  • BASEIMAGE – this will enable PVD support. Use at your own risk ;)
  • PORTNUMBER – using a custom port for the VDA other than the default TCP 80, requires installing the VDA and then re-rerunning setup to specify a different port.

There’s not much different here to previously releases, but I would like to see Citrix add all options to the wizard and then provide the command line, based on what you’ve selected, at the end to lower the barriers to automation even further.

Creative Commons LicenseAutomating the XenDesktop 7 Virtual Desktop Agent Installation is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2013 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

A Quick Look at Work Folders in Windows Server 2012 R2

$
0
0

Microsoft announced some interesting new features in Windows Server 2012 R2 at TechEd 2013 and one of those that piqued my interest is Work Folders. I’m not the biggest fan of Redirected Folders and Offline files, but it’s essentially the only enterprise solution Microsoft provides today for taking your data offline. Microsoft needs to provide a completely new method of syncing file data – one that is designed for todays use cases and computing environment.

Work Folders is a brand new direction for enabling access to data in offline scenarios, along the lines of Citrix ShareFile and Dropbox, but without the web and sharing features. Like most Microsoft OS features, Work Folders is tied to a specific release of Windows; however according to this Channel 9 video, Microsoft will release Work Folders for Windows 7, iOS and “other devices” (presumably Android). This is excellent news.

Here’s a short look at setting up and connecting to Work Folders using the preview releases of Windows Server 2012 R2 and Windows 8.1 – what’s version 1.0 going to deliver?

Server Configuration

For a more detailed walkthrough on deploying Work Folders, download this document: Windows Server 2012 R2: Enabling Windows Server Work Folders.

Work Folders is a component of the File and Storage Services role in Windows Server. I’ve installed Windows Server 2012 R2 into a virtual machine and am using local storage.

WorkFolders-InstallRole

Once installed, Work Folders is managed through Server Manager:

WorkFolders-ServerManager

Creating a new sync share is performed via a wizard which will first ask where the Sync Share will be located. This can be a new folder or an existing share – mixing user home drives and Work Folders should be possible. Note that at this time, Work Folders only supports providing users with exclusive access to Sync Share location – there is no provision for providing access to shared data.

WorkFolders-Setup1

Sub-folders can be created using just the users’ username/alias or alias@domain. If using an existing share, it’s probably best to stick with user alias. For existing shares, it is possible to sync only a single subfolder (e.g. Documents). This should really allow multiple subfolders, so that folders such as Documents, Desktop, Pictures etc could all be synced.

WorkFolders-Setup2

Give the Sync Share a name. Each Sync Share requires a unique name and I suspect that information about the share is stored in Active Directory.

WorkFolders-Setup3

Provide access to a specified set of users. Is the option ‘Disable inherited permissions and grant users exclusive access to their files’ remains checked, then the administrator won’t have access to the users’ folder. Unchecking this option is probably ideal for most environments.

WorkFolders-Setup4

Work folders and enable some basic security options on the device. On Windows, the Encrypt Work Folders option looks to utilise EFS.

WorkFolders-Setup5

Once configuration is complete, there is a confirmation page:

WorkFolders-Setup6

You can then see the results as the wizard creates the Sync Share:

WorkFolders-Setup7

Once a client has connected to the Sync Share, the administrator can see the following folder structure on the server. File data is stored in the Data folder, but I haven’t seen what’s stored in the Profile folder at this time.

WorkFolders-AaronFolder

Back in Server Manager, the administrator can view properties on user accounts used to connect to the Sync Share, including details on the devices storing data. There doesn’t appear to be a way to initiate a remote wipe at this time.

WorkFolders-AaronParkerProperties

One piece that I haven’t shown here, is the certificate configuration required to connect to Work Folders. Synchronisation is over HTTPS and Work Folders is hosted in IIS, so it is reasonably straight-forward to configure certificates to enable SSL/TLS encryption. Using the new Web Application Proxy feature in Windows Server 2012 R2 or DirectAccess, you could provide remote access to Work Folders for clients outside of the corporate network.

Client Configuration

Accessing Work Folders from a client device, requires Windows 8.1 at this time with other operating systems to follow. I’ve used a non-domain joined Windows virtual machine.

To connect to a Sync Share using Work Folders, open the Work Folder applet in Control Panel:

WorkFolders-Config1

To make setup simpler, a user can use their email address, which will require some DNS configuration.

WorkFolders-Config2

I don’t have the right DNS configuration in my test environment, so I’ve had to

WorkFolders-Config3

Because I’m on non-domain joined PC, I need to authenticate using my domain credentials. Once authenticated, Work Folders asks where to store the synchronised data. At this time, we can’t change from the default location.

WorkFolders-Config4

Because I’ve configured encryption and password policies on my Sync Folder, the user needs to accept that these policies will be applied to the local device to continue:

WorkFolders-Config5

Finally a confirmation that Work Folders has been setup successfully. Note that at this time, a device can only connect to a single Sync Share.

WorkFolders-Config6

Control Panel will now display status information about Work Folders:

WorkFolders-ControlPanel

Work Folders are now available directly from within the Computer/This PC window:

WorkFolders-WindowsExplorer

I can now move or copy files into this location and synchronisation appears to be instant. That’s probably in part to do with both the client and server running on the same host. Unfortunately at the moment there isn’t any visual indication from within Explorer as to the sync status of a file or folder.

WorkFolders-WindowsExplorer2

Drilling down a bit further, I can see the data stored in my Work Folders and access it just like any other local folder.

WorkFolders-WindowsExplorer3

Conclusion

The entrenched players in this space, don’t have much to be concerned about with version 1 of Work Folders; theres no access from a browser, no ability to share files and no integration with Outlook. Updates will be tied to Windows Server releases and it’s encouraging to see that Microsoft will deliver clients for operating system other than Windows 8.1.

Considering that this feature is built into the operating system, it’s just a matter of time (and maybe waiting for v3) until Work Folders becomes the de facto standard for synchronising user data to Windows devices at least. Maybe, just maybe, the writing is on the wall for Offline Files.

Creative Commons LicenseA Quick Look at Work Folders in Windows Server 2012 R2 is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2013 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

Testing Citrix Receiver on Android without an Android device

$
0
0

I have too many devices but not one of them runs Android. A good part of my job is testing, presenting and demoing, so it’s handy being able to show the user experiences across different devices. One of everything is perhaps going a bit too far, so I’d prefer to run Android as a VM.

Parallels provides a handy way to download an Android VM, but it’s a little limited – no Google Play store, for example, which means getting Citrix Receiver into the VM is going to be a challenge (if at all possible).

Parallels-AndroidVM

Today though, I came across Genymotion which provides Android virtual machines, targeted at developers; however these are VMs with reasonably recent versions of Android (4.2.2). Additionally these VMs have Google Play installed in them, making them an excellent way of testing and demoing Android.

Underneath, VirtualBox is required to get this up and running. I’ve been testing on OS X and I’ve installed VirtualBox alongside Parallels Desktop. For Windows machines, Genymotion provides a standalone installer that includes VirtualBox.

GenymotionDownloadOptions

I haven’t yet tested, but I believe that the VMs could be converted into other virtualization formats. On OS X, the device images are stored in ~/.Genymobile and the virtual disks are in VMDK format.

Once the Genymotion application is installed, grabbing an Android VM is very easy – virtual device images can be downloaded directly from the site via the application:

AvailableVMs

Here’s an Android VM running emulating a Google Nexus. Notice the controls down the right-hand side – there’s options for emulating battery status and GPS to Android, plus hardware buttons that might be on a physical device, as well as being able to rotate the VM.

AndroidLockScreen

Once the up and running, I’ve set it up with my Google credentials and downloaded Google Chrome and Citrix Receiver:

AndroidHome

Receiver works just like you’d expect:

AndroidReceiverWord

So far this looks to work very well and because the VMs run a pretty stock version of Android, there’s all sorts of uses for this – testing the VMware View client, testing and demoing various MDM solutions such as XenMobile or AppSense MobileNow, or essentially anything you might do with a physical device; without having to pay for one. Which means my wife won’t have to roll her eyes if I was to bring home yet another device.

Creative Commons LicenseTesting Citrix Receiver on Android without an Android device is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2014 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

Customizing the Windows 8.1 Start Screen? Don’t follow Microsoft’s guidance

$
0
0

WIndows81StartScreen

For enterprises, Windows 8.1 delivers the control around the Start Screen that should have been there in Windows 8.0, although I’m sure what they’ve delivered won’t appease everyone as there’s still no programmatic way to pin or unpin shortcuts from the Start Screen.

Windows 8.1 introduces a Group Policy method for distributing a Start Screen layout, but that’s a policy – i.e. it’s enforced and unless you’re a control freak, that approach only makes sense in specific cases (e.g. schools, kiosks etc.). Note that Start Screen control is only available in Windows 8.1 Enterprise and Windows RT 8.1, so you’re either paying SA or delivering the Surface RT/2 (or maybe even the Lumia 2520) to your users.

Microsoft have an article available on TechNet that describes a number of ways that you can configure the default Start Screen experience that will work for Windows 8/8.1, Window Server 2012 and Windows Server 2012 R2, but the choices are:

  1. Create a reference image and use the CopyProfile setting in unattend.xml to customise the default profile including the Start Screen
  2. Use the StartTiles setting in unattend.xml to specify a list of tiles to add to the Start Screen
  3. Use SysPrep to generate AppsFolderLayout.bin and then copy that to the default profile

Each one of those approaches looks tedious.

Fortunately, there’s a far easier way. Microsoft has added a couple of PowerShell cmdlets that provide for a way of getting your custom Start Screen layout into the default profile. These works for all edition of Windows 8.1 (even RT).

This approach is really about customising the default Start Screen experience (i.e. first logon). If you want control of the Start Screen (users receive the same screen every session) you will need Windows 8.1 Enterprise or Windows Server 2012 R2. You can use this method to customise a reference image, an unattended deployment using RTM media or even an existing Windows installation.

Here’s what you need to do at a high level:

  1. Deploy and/or log onto a machine that has the applications that you want to pin to the Start Screen
  2. Customise that Start Screen to your heart’s content
  3. Export the Start Screen configuration with Export-StartLayout
  4. Import the Start Screen configuration with Import-StartLayout

Exporting the Start Screen layout is simple, just ensure you export the configuration file in binary format, as Import-StartLayout won’t import XML files. Here’s the export command:

Export-StartLayout -As BIN -Path CustomStartScreenLayout.bin -Verbose

Which should look like this:

Export-StartLayout

The documentation for Import-StartLayout seems to indicate that this cmdlet only works against offline images (mounted with ImageX); however this isn’t the case – the cmdlet can be run against the current Windows installation.

That means that we can import a custom Start Screen layout during any type of deployment. For example, you could script the import of the customisation during an MDT or SCCM task sequence. The following command will import the customisation into the default profile of the local desktop. This will need to be run from an elevated command prompt.

POWERSHELL -NonInteractive -Command Import-StartLayout -LayoutPath .\CustomStartScreenLayout.bin -MountPath %SystemDrive%\

Using MDT, this command runs as part of a script that customises the default profile. The process is ultimately pretty painless.

Windows8Default

A Better Way to Customize the Windows Default Profile

$
0
0

Multiple Methods

The Deployment Guys have a great article from 2009 that I recommend reading for a overview of customisation methods: Configuring Default User Settings – Full Update for Windows 7 and Windows Server 2008 R2. This article is still applicable today and the process hasn’t changed that much between Windows versions. Here are most of the ways that you could edit the default user profile:

  • Copy a configured profile over the default profile – this is the most common way of changing the default user experience but this approach is unsupported by Microsoft and therefore I recommend against using it.
  • Using Sysprep and the CopyProfile value – this approach requires creating a reference image and using Sysprep to generalise the image. Many enterprise desktop deployments will use reference images so this isn’t too hard; however Microsoft has not documented every setting that is copied to the default user profile, so it’s a bit of pot luck.
  • Place a default profile in NETLOGON – a default profile copied to the NETLOGON share of a domain controller (and replicated) will be copied down to the local machine at first logon. The downside of this approach is that there can be only one default profile and it will be copied to all machines, regardless as to whether the profile should apply to that machine or not.
  • Commands or scripts run from the RunOnce Registry key to edit the user profile.
  • Logon scripts to edit the user profile.
  • Group Policy Preferences – GPP has become more prevalent in the past few years, so should now be available across the board.
  • Editing the default profile directly, typically during an automated deployment, but you could run the same script on any existing PC.

So there are multiple methods (of driving yourself to madness), I’d recommend experimenting with each approach and you’ll most likely implement a combination of approaches to best suit your environment.

Group Policy As A Last Resort

Group Policy is great, until it isn’t. Group Policy is pervasive and every Windows admin is familiar with it, but there a two things to consider when using it to manage the default user experience:

  1. Group Policy is is a policy – that is, if you’re using policies to manage default user settings, the user cannot then change to their own preference.
  2. Group Policy Preferences must be processed to determine whether they have been applied. Whilst GPPs can implement a preference rather than a policy, Windows must determine whether the preference has been applied by reading a flag. Whilst checking those flags isn’t a big problem, implementing GPPs should be considered in the context of whatever else is running at logon, how many preferences are implemented plus what happens to the environment over time (how many additional policies, applications, scripts etc. will be added to the environment over the life of that desktop).

I have seen many organisations over-relying on Group Policy and missing the most important component user environment management – change control and ownership. Group Policy becomes a black hole, complete with settings that no one can remember why they were implemented and settings that are no longer relevant. Group Policy Preferences are great for replacing logon scripts, but use Group Policy and GPP sparingly so as not to adversely affect the user experience.

A Better Way – Edit the Default Profile Directly

My preferred method for modifying the default user experience is to edit the default user profile directly using a script that is run during Windows deployment. This type of script can also be run on existing machines or used in combination with CopyProfile. A benefit of this approach is that you can modify the default profile with or without a reference image.

Editing the Default Profile

To edit the default profile, we’ll use the command line tool REG to mount and make changes to the default user registry hive. Additionally we can make folder and file changes to the default profile and a couple of other command line tools to perform tasks such as pin and unpin shortcuts or change the Windows 7 Libraries. As far as this article is concerned, the default profile is in its default location, usually C:\Users\Default. In a script, you could refer to this location as %SystemDrive%\Users\Default.

Finding Settings

To find the profile locations to modify there’s a couple of methods that I rely on:

  • Google (or your favourite search engine)
  • Process Monitor and Process Explorer

In most cases, someone (or even Microsoft) will have documented a registry value or profile location that is used to store a setting. More obscure or new settings will require detecting the location with Process Monitor. For example, to determine where a setting is stored in the Registry, create a filter in Process Monitor using the process name or process ID, additionally filtering on the operation such as RegSetValue, as shown below:

Configuring Process Monitor filter

A trace with Process Monitor when making a preference change should result in something like this:

Process Monitor results

Regshot is also useful for comparing a before and after change to the profile for determining registry value locations.

Additionally Process Explorer can be useful for tracking down a process that might be responsible for writing a setting by viewing the command line used to launch the process. Finding settings can sometimes be a time consuming process, but once found and documented, you’ve got a detailed understanding of the default profile.

Editing the Registry

To make direct registry edits to the default user profile, the REG command line utility is used to load the default profile registry hive, change a registry value and then unload the hive, saving it back to the default profile. The following lines show a rough example of how this is done:

REG LOAD HKU\DefaultUser %SystemDrive%\Users\Default\NTUSER.DAT
REG ADD HKU\DefaultUser\Software\KeyName /v ValueName /d Data /t REG_SZ /f
REG UNLOAD HKU\DefaultUser

Note that this will need to be run with administrative privileges and in an elevated context, so that you have write access to the default profile.

Pinning and Unpinning Shortcuts

A common requirement is to modify the the pinned shortcuts on the Taskbar or Start menu. This can be automated using a script, which needs to run a first logon (either as the user, or in the profile copied over the default profile via Sysprep/CopyProfile). Unfortunately I can’t find the original source for this script; however it works quite well and allows you to pin shortcuts to and unpin shortcuts from the Taskbar and Start menu via a command line. The script is available here:

ExecuteVerbAction.vbs ExecuteVerbAction.vbs

Note that Windows 8 and above, do not expose a programatic method to pin and unpin shortcuts to the Start screen. If you’re looking to customise the Start screen, refer to this existing article: http://stealthpuppy.com/customizing-the-windows-8-1-start-screen-dont-follow-microsofts-guidance/.

Modifying the Windows Libraries

By default, the Libraries introduced in Windows 7, include the public folder locations. Removing these or adding locations requires editing the Libraries; however they’re stored in XML files and are created at first logon. To modify the libraries, you can use a command line tool ShLib.exe. Like pinning and unpinning shortcuts, this tool also needs to be run at first logon (and won’t work via CopyProfile). This article, Administratively Create and Modify Windows 7 Libraries, covers the use of ShLib.exe quite well.

Implementing a Script to Modify the Default Profile

Once you’ve created your script to make changes to the default registry, modify the default profile folder locations, pin and unpin shortcuts and make changes to the Libraries, you’ll need to implement the changes on the target PCs via script. Using an automation solution such as the Microsoft Deployment Toolkit (or an ESD like System Center Configuration Manager) the script can be run during a deployment task sequence. In the case of MDT, the script will be run after Windows unattended setup has completed in the local Administrator context. This way the script will have full elevation and write access to the default profile. An ESD solution will typically run the script via the local SYSTEM account. If you need to make changes to existing PCs, you’ll need a method to do so, such as an advertisement in Configuration Manager. If you take this approach, you can combine a script that makes direct changes to the default profile with the CopyProfile approach. That allows you to modify the profile for deployments from an unmodified OS as well as a custom image, keeping consistency across deployment types.

Example Scripts

Included here, along with some notation, are some example scripts for modifying the Windows 7 and Windows 8.1 default profiles. These example scripts include creation of a script at runtime that will run during first logon of any new profile. This is implemented as a batch file to keep things as simple as possible. Users will see a Command Prompt window as the script runs (but only once). The command lines includes in the script could be implemented with a UEM solution such as AppSense Environment Manager or even Group Policy to improve the user experience.

Windows 7

Here’s a sample script that will modify the default profile on a Windows 7 PC (x86 and x64). At a high level, the script will perform the following steps:

  • Load and modifies the registry of the default profile
  • Copies ExecuteVerbAction.VBS and ShLib.exe to folder under %ProgramFiles%
  • Creates a batch script that will run on first logon to edit the Libraries and pin/unpin shortcuts. Once the script runs for the user, it will delete itself.

@ECHO OFF
REM Load the default profile hive
SET HKEY=HKU\Default
REG LOAD %HKEY% %SystemDrive%\Users\Default\NTUSER.DAT

REM Sound and end-application
REG ADD "%HKEY%\Control Panel\Sound" /v Beep /t REG_SZ /d NO /f
REG ADD "%HKEY%\Control Panel\Sound" /v ExtendedSounds /t REG_SZ /d NO /f
REG ADD "%HKEY%\Control Panel\Desktop" /v HungAppTimeout /t REG_SZ /d 5000 /f
REG ADD "%HKEY%\Control Panel\Desktop" /v AutoEndTasks /t REG_SZ /d 1 /f
REG ADD "%HKEY%\Control Panel\Desktop" /v WaitToKillAppTimeout /t REG_SZ /d 4000 /f

REM Command Prompt settings
REG ADD "%HKEY%\Console" /v QuickEdit /t REG_DWORD /d 1 /f
REG ADD "%HKEY%\Software\Microsoft\Command Processor" /v CompletionChar /t REG_DWORD /d 9 /f
REG ADD "%HKEY%\Software\Microsoft\Command Processor" /v PathCompletionChar /t REG_DWORD /d 9 /f
REG ADD "%HKEY%\Software\Microsoft\Windows NT\CurrentVersion\Network\Persistent Connections" /v SaveConnections /d "no" /t REG_SZ /f

REM Language bar - only apply if using single regional settings
REM	REG ADD "%HKEY%\Software\Microsoft\CTF\LangBar" /v ShowStatus /t REG_DWORD /d 3 /f
REM	REG ADD "%HKEY%\Software\Microsoft\CTF\LangBar" /v Label /t REG_DWORD /d 1 /f
REM	REG ADD "%HKEY%\Software\Microsoft\CTF\LangBar" /v ExtraIconsOnMinimized /t REG_DWORD /d 0 /f

REM Windows Explorer and Start Menu
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v SeparateProcess /t REG_DWORD /d 1 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v ServerAdminUI /t REG_DWORD /d 0 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v Start_AdminToolsRoot /t REG_DWORD /d 0 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v Start_PowerButtonAction /t REG_DWORD /d 2 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v Start_ShowDownloads /t REG_DWORD /d 1 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v Start_ShowMyGames /t REG_DWORD /d 0 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v Start_ShowMyMusic /t REG_DWORD /d 0 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v StartMenuAdminTools /t REG_DWORD /d 0 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v StartMenuFavorites /t REG_DWORD /d 1 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v TaskbarSizeMove /t REG_DWORD /d 0 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\AutoComplete" /v "Append Completion" /t REG_SZ /d YES /f
REG ADD "%HKEY%\AppEvents\Schemes\Apps\Explorer\Navigating\.Current" /ve /t REG_EXPAND_SZ /d "" /f

REM Set IE as default browser, prevent prompting user
REG ADD "%HKEY%\Software\Clients\StartmenuInternet" /ve /d "IEXPLORE.EXE" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.mht\UserChoice" /v Progid /d "IE.AssocFile.MHT" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice" /v Progid /d "IE.AssocFile.HTM" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.htm\UserChoice" /v Progid /d "IE.AssocFile.HTM" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.url\UserChoice" /v Progid /d "IE.AssocFile.URL" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.mhtml\UserChoice" /v Progid /d "IE.AssocFile.MHT" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.xht\UserChoice" /v Progid /d "IE.AssocFile.XHT" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.svg\UserChoice" /v Progid /d "IE.AssocFile.SVG" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.partial\UserChoice" /v Progid /d "IE.AssocFile.PARTIAL" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.website\UserChoice" /v Progid /d "IE.AssocFile.WEBSITE" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.xhtml\UserChoice" /v Progid /d "IE.AssocFile.XHT" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice" /v Progid /d "IE.HTTPS" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\ftp\UserChoice" /v Progid /d "IE.FTP" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice" /v Progid /d "IE.HTTP" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\Shell\Associations\MIMEAssociations\message/rfc822\UserChoice" /v Progid /d "IE.message/rfc822" /f
REG ADD "%HKEY%\Software\Microsoft\Windows\Shell\Associations\MIMEAssociations\text/html\UserChoice" /v Progid /d "IE.text/html" /f

REM Additional Internet Explorer options
REG ADD "%HKEY%\Software\Microsoft\Internet Explorer\TabbedBrowsing" /v PopupsUseNewWindow /t REG_DWORD /d 0 /f
REG ADD "%HKEY%\Software\Microsoft\Internet Explorer\PhishingFilter" /v Enabled /t REG_DWORD /d 1 /f
REG ADD "%HKEY%\Software\Microsoft\Internet Explorer\Main" /v "Enable AutoImageResize" /t REG_SZ /d YES /f
REG ADD "%HKEY%\Software\Microsoft\Internet Explorer\PhishingFilter" /v Enabled /t REG_DWORD /d 2 /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\domain.local" /v * /t REG_DWORD /d 1 /f
REM	REG ADD "%HKEY%\Software\Microsoft\Internet Explorer\New Windows\Allow" /v *.domain.local /t REG_BINARY /d 0000 /f

REM Windows Media Player
REG ADD "%HKEY%\Software\Microsoft\MediaPlayer\Setup\UserOptions" /v DesktopShortcut /d No /t REG_SZ /f
REG ADD "%HKEY%\Software\Microsoft\MediaPlayer\Setup\UserOptions" /v QuickLaunchShortcut /d 0 /t REG_DWORD /f
REG ADD "%HKEY%\Software\Microsoft\MediaPlayer\Preferences" /v AcceptedPrivacyStatement /d 1 /t REG_DWORD /f
REG ADD "%HKEY%\Software\Microsoft\MediaPlayer\Preferences" /v FirstRun /d 0 /t REG_DWORD /f
REG ADD "%HKEY%\Software\Microsoft\MediaPlayer\Preferences" /v DisableMRU /d 1 /t REG_DWORD /f
REG ADD "%HKEY%\Software\Microsoft\MediaPlayer\Preferences" /v AutoCopyCD /d 0 /t REG_DWORD /f

REM Help and Support
REG ADD "%HKEY%\Software\Microsoft\Assistance\Client\1.0\Settings" /v OnlineAssist /d 1 /t REG_DWORD /f
REG ADD "%HKEY%\Software\Microsoft\Assistance\Client\1.0\Settings" /v IsConnected /d 1 /t REG_DWORD /f

REM Remove localisation - Themes, Feeds, Favourites
REG DELETE "%HKEY%\Software\Microsoft\Windows\CurrentVersion\RunOnce" /v mctadmin /f

REM Snipping Tool
REG ADD "%HKEY%\Software\Microsoft\Windows\TabletPC\Snipping Tool" /v ShowCaptureStroke /d 0 /t REG_DWORD /f

REM Unload the default profile hive
REG UNLOAD %HKEY%

REM Setup Taskbar unpin items on first login
IF NOT EXIST "%ProgramFiles%\Scripts" MD "%ProgramFiles%\Scripts"
COPY /Y ExecuteVerbAction.VBS "%ProgramFiles%\Scripts\ExecuteVerbAction.VBS"
COPY /Y ShLib.exe "%ProgramFiles%\Scripts\ShLib.exe"

MD "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"
ECHO @ECHO OFF > "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd"
ECHO cscript.exe "%ProgramFiles%\Scripts\ExecuteVerbAction.vbs" "%ProgramData%\Microsoft\Windows\Start Menu\Programs\Windows Media Player.lnk" UnpinFromTaskbar >> "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd"
ECHO "%ProgramFiles%\Scripts\shlib" remove "%%APPDATA%%\Microsoft\Windows\Libraries\Documents.library-ms" %PUBLIC%\Documents >> "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd"
ECHO "%ProgramFiles%\Scripts\shlib" remove "%%APPDATA%%\Microsoft\Windows\Libraries\Music.library-ms" %PUBLIC%\Music >> "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd"
ECHO "%ProgramFiles%\Scripts\shlib" remove "%%APPDATA%%\Microsoft\Windows\Libraries\Pictures.library-ms" %PUBLIC%\Pictures >> "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd"
ECHO "%ProgramFiles%\Scripts\shlib" remove "%%APPDATA%%\Microsoft\Windows\Libraries\Videos.library-ms" %PUBLIC%\Videos >> "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd"
ECHO DEL /Q "%%APPDATA%%\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd" >> "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd"

If you use this in a production environment, please test and confirm each setting to ensure you understand what the script will implement.

Windows 8.1

Here’s a sample script that will modify the default profile on a Windows 8.1 PC (x86 and x64). At a high level, the script will perform the following steps:

  • Load and modifies the registry of the default profile
  • Import a pre-configured Start screen
  • Copies ExecuteVerbAction.VBS and ShLib.exe to folder under %ProgramFiles%
  • Creates a batch script that will run on first logon to edit the Libraries and pin/unpin shortcuts. Once the script runs for the user, it will delete itself

@ECHO OFF
REM Load the default profile hive
SET HKEY=HKU\Default
REG LOAD %HKEY% %SystemDrive%\Users\Default\NTUSER.DAT

REM Sound and end-application
REG ADD "%HKEY%\Control Panel\Sound" /v Beep /t REG_SZ /d NO /f
REG ADD "%HKEY%\Control Panel\Sound" /v ExtendedSounds /t REG_SZ /d NO /f
REG ADD "%HKEY%\Control Panel\Desktop" /v HungAppTimeout /t REG_SZ /d 5000 /f
REG ADD "%HKEY%\Control Panel\Desktop" /v AutoEndTasks /t REG_SZ /d 1 /f
REG ADD "%HKEY%\Control Panel\Desktop" /v WaitToKillAppTimeout /t REG_SZ /d 4000 /f

REM Command Prompt settings
REG ADD "%HKEY%\Console" /v QuickEdit /t REG_DWORD /d 1 /f
REG ADD "%HKEY%\Software\Microsoft\Windows NT\CurrentVersion\Network\Persistent Connections" /v SaveConnections /d "no" /t REG_SZ /f

REM Language bar - only apply if using single regional settings
REM	REG ADD "%HKEY%\Software\Microsoft\CTF\LangBar" /v ShowStatus /t REG_DWORD /d 3 /f
REM	REG ADD "%HKEY%\Software\Microsoft\CTF\LangBar" /v Label /t REG_DWORD /d 1 /f
REM	REG ADD "%HKEY%\Software\Microsoft\CTF\LangBar" /v ExtraIconsOnMinimized /t REG_DWORD /d 0 /f

REM Windows Explorer
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v SeparateProcess /t REG_DWORD /d 1 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v TaskbarSizeMove /t REG_DWORD /d 0 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\AutoComplete" /v "Append Completion" /t REG_SZ /d YES /f
REG ADD "%HKEY%\AppEvents\Schemes\Apps\Explorer\Navigating\.Current" /ve /t REG_EXPAND_SZ /d "" /f

REM Windows 8 navigation settings
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage" /v OpenAtLogon /t REG_DWORD /d 0 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage" /v DesktopFirst /t REG_DWORD /d 0 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage" /v MakeAllAppsDefault /t REG_DWORD /d 0 /f
REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage" /v MonitorOverride /t REG_DWORD /d 0 /f

REM Set IE as default browser, prevent prompting user
REM	REG ADD "%HKEY%\Software\Clients\StartmenuInternet" /ve /d "IEXPLORE.EXE" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.mht\UserChoice" /v Progid /d "IE.AssocFile.MHT" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice" /v Progid /d "IE.AssocFile.HTM" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.htm\UserChoice" /v Progid /d "IE.AssocFile.HTM" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.url\UserChoice" /v Progid /d "IE.AssocFile.URL" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.mhtml\UserChoice" /v Progid /d "IE.AssocFile.MHT" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.xht\UserChoice" /v Progid /d "IE.AssocFile.XHT" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.svg\UserChoice" /v Progid /d "IE.AssocFile.SVG" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.partial\UserChoice" /v Progid /d "IE.AssocFile.PARTIAL" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.website\UserChoice" /v Progid /d "IE.AssocFile.WEBSITE" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.xhtml\UserChoice" /v Progid /d "IE.AssocFile.XHT" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice" /v Progid /d "IE.HTTPS" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\ftp\UserChoice" /v Progid /d "IE.FTP" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice" /v Progid /d "IE.HTTP" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\Shell\Associations\MIMEAssociations\message\rfc822\UserChoice" /v Progid /d "IE.message/rfc822" /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\Shell\Associations\MIMEAssociations\text\html\UserChoice" /v Progid /d "IE.text/html" /f

REM Additional Internet Explorer options
REM	REG ADD "%HKEY%\Software\Microsoft\Internet Explorer\TabbedBrowsing" /v PopupsUseNewWindow /t REG_DWORD /d 0 /f
REM	REG ADD "%HKEY%\Software\Microsoft\Internet Explorer\PhishingFilter" /v Enabled /t REG_DWORD /d 1 /f
REM	REG ADD "%HKEY%\Software\Microsoft\Internet Explorer\Main" /v "Enable AutoImageResize" /t REG_SZ /d YES /f
REM	REG ADD "%HKEY%\Software\Microsoft\Internet Explorer\PhishingFilter" /v Enabled /t REG_DWORD /d 2 /f
REM	REG ADD "%HKEY%\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\domain.local" /v * /t REG_DWORD /d 1 /f
REM	REG ADD "%HKEY%\Software\Microsoft\Internet Explorer\New Windows\Allow" /v *.domain.local /t REG_BINARY /d 0000 /f

REM Windows Media Player
REG ADD "%HKEY%\Software\Microsoft\MediaPlayer\Setup\UserOptions" /v DesktopShortcut /d No /t REG_SZ /f
REG ADD "%HKEY%\Software\Microsoft\MediaPlayer\Setup\UserOptions" /v QuickLaunchShortcut /d 0 /t REG_DWORD /f
REG ADD "%HKEY%\Software\Microsoft\MediaPlayer\Preferences" /v AcceptedPrivacyStatement /d 1 /t REG_DWORD /f
REG ADD "%HKEY%\Software\Microsoft\MediaPlayer\Preferences" /v FirstRun /d 0 /t REG_DWORD /f
REG ADD "%HKEY%\Software\Microsoft\MediaPlayer\Preferences" /v DisableMRU /d 1 /t REG_DWORD /f
REG ADD "%HKEY%\Software\Microsoft\MediaPlayer\Preferences" /v AutoCopyCD /d 0 /t REG_DWORD /f

REM Unload the default profile hive
REG UNLOAD %HKEY%

REM Configure the default Start Screen
IF NOT EXIST %SystemDrive%\Users\Default\AppData\Local\Microsoft\Windows MD %SystemDrive%\Users\Default\AppData\Local\Microsoft\Windows
POWERSHELL -NonInteractive -Command Import-StartLayout -LayoutPath .\CustomStartScreenLayout.bin -MountPath %SystemDrive%\

REM Setup Taskbar unpin items on first login
IF NOT EXIST "%ProgramFiles%\Scripts" MD "%ProgramFiles%\Scripts"
COPY /Y ExecuteVerbAction.VBS "%ProgramFiles%\Scripts\ExecuteVerbAction.VBS"
COPY /Y ShLib.exe "%ProgramFiles%\Scripts\ShLib.exe"

MD "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"
ECHO @ECHO OFF > "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd"
REM	ECHO cscript.exe "%ProgramFiles%\Scripts\ExecuteVerbAction.vbs" "%ProgramData%\Microsoft\Windows\Start Menu\Programs\Windows Media Player.lnk" UnpinFromTaskbar >> "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd"
ECHO "%ProgramFiles%\Scripts\shlib" remove "%%APPDATA%%\Microsoft\Windows\Libraries\Documents.library-ms" %PUBLIC%\Documents >> "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd"
ECHO "%ProgramFiles%\Scripts\shlib" remove "%%APPDATA%%\Microsoft\Windows\Libraries\Music.library-ms" %PUBLIC%\Music >> "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd"
ECHO "%ProgramFiles%\Scripts\shlib" remove "%%APPDATA%%\Microsoft\Windows\Libraries\Pictures.library-ms" %PUBLIC%\Pictures >> "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd"
ECHO "%ProgramFiles%\Scripts\shlib" remove "%%APPDATA%%\Microsoft\Windows\Libraries\Videos.library-ms" %PUBLIC%\Videos >> "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd"
ECHO DEL /Q "%%APPDATA%%\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd" >> "%SystemDrive%\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\PinnedItemsLibraries.cmd"

If you use this in a production environment, please test and confirm each setting to ensure you understand what the script will implement.

Summing Up

There are numerous ways to edit the default profile, some more complicated and involved than others. It’s my view that the best way to modify the default profile is targeting the required settings, which does mean more work. However, this approach results in a better understanding of the user environment and with any luck a better user experience.

Each new major release of Windows results in less modifications, so your job will be easier. There are a few scripts and tools you’ll need to have in place and I’m confident the approach outlined here will result in happy users (or at least users who aren’t complaining).

In the next article on the same subject, I’ll cover customising the default profile for Remote Desktop Services Session Hosts.

Creative Commons LicenseA Better Way to Customize the Windows Default Profile is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2014 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

3rd European App-V User Group announced

$
0
0

AppVUserGroupBannerThose all round good guys over at Login Consultants have announced the 2014 European App- User Group. Just like previous years, the event will be held at the Microsoft HQ in Amsterdam near Schiphol airport, making it very easy to get to.

No concrete details are in place yet, but expect a high level of involvement from App-V MVPs, so you can be guaranteed that the information presented will be of high quality. Login Consultants are looking to gauge the level of interest in the event and what topics attendees would like to see and you can register your details now.

If you’ve not been to previous events, videos of last years presentations are available on Nicke Källén’s blog.

 

Creative Commons License3rd European App-V User Group announced is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2014 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

Work around for getting File Transfer Manager to download from TechNet/MSDN

$
0
0

The subtitle to this post should be – “How to get faster downloads from TechNet and MSDN”.

I download quite a bit of stuff from TechNet and/or MSDN fairly regularly for deploying into a lab. With downloads typically in the gigabytes and often needing those downloads as soon as possible, I need to be able to download files consistently and faster than a browser alone might be able to.

Microsoft has used File Transfer Manager (FTM) for some time to make downloads easier and faster from TechNet and MSDN. Apparently Microsoft is transitioning over to Download Manager, but I’m yet to see it in action.

Recently (perhaps the last 12 months), I’ve noticed that FTM hasn’t been launching to download a target file and instead the download has been via the browser directly. This hasn’t been an issue for me until I’ve moved from 60Mbps cable in the UK to ~7.5Mbps ADSL in Australia. Things take a little longer to download here, as you might guess. Here’s the download speeds I’ve typically been seeing from TechNet:

Slow download speed in IE

I know FTM does a far better job than this, so why won’t it launch when downloading files? Turns out that because FTM is ActiveX based and uses scripting and for whatever reason, it won’t actually launch from IE10 or IE11. The exact details on why are a bit of mystery but it seems that Microsoft haven’t gotten around to supporting their latest browsers.

Fortunately a work around is straight-forward – enable emulation mode to view the TechNet or MSDN sites as IE9. Emulation is enabled via the following steps:

  1. For Internet Explorer 11, press F12 to bring up the developer tools window
  2. Click the Emulation icon (bottom left) or press Ctrl+8
  3. Select ‘9’ under Document Mode
  4. Choose ‘Internet Explorer 9′ under User Agent String

Emulation with Developer Tools

Now clicking on a download should result in FTM launching. Download speeds are now far more reasonable:

FTM faster download

You can now close the Developer Tools window and even the browser, while your download continues.


“There isn’t enough memory available to create a ramdisk device” booting VMs on Hyper-V

$
0
0

Booting a virtual machine under Windows Server 2012 R2 Hyper-V may result in the following:

Recovery
Your PC needs to be repaired
There isn’t enough memory available to create a ramdisk device.
Error code: 0x0000017

There isn’t enough memory available to create a ramdisk device

Thankfully, the error message is pretty self explanatory.

Booting a standard Windows ISO does not result in the above error, but in this particular case, I’m booting a Gen 2 VM with a customised Microsoft Deployment Toolkit boot ISO with a scratch space size of 64Mb (I assume though, that the scratch space could be just about any size).

The VM is configured with dynamic memory enabled and the default startup RAM size of 512Mb. This issue is easily remedied by increasing the startup RAM size. The minimum RAM size can then still be configured for 512Mb, if required.

DynamicMemory

Sequential Starting of a List of VMs

$
0
0

In my lab environment, I often want to start a list of virtual machines, but without taxing the system in the process by starting them all at the same time.  I could do that manually, but that’s no fun.

Here’s a short function I wrote to sequentially start a list of virtual machines – the script will start a VM and wait for that VM to boot before starting the next VM. You can optionally also wait additional time before starting the next VM to give the first one some time to finish starting it’s services etc.

This version currently supports Hyper-V only. The script does not currently return anything, but has a number of parameters:

  • ComputerName – the name of the Hyper-V host. Specify “.” for the local machine (without quotes)
  • VM – specify a comma separated list of VMs
  • Wait – the number of seconds to wait between starting a VM after the previous VM. Specify the number of VMs as a number (integer) only. This will default to 180 seconds
  • ShowProgress – Specify whether to show progress while starting the VMs. This is cosmetic only, but does give some indication as to how far through the boot process the script is.
  • Other standard parameters such as Verbose are supported.

Function Start-SequentialVMs {
    <#
        .SYNOPSIS
            Starts a list of VMs.
 
        .DESCRIPTION
            This function starts a list of VMs sequentially. It will wait until a VM is booted, optionally pause for a number of seconds, before starting the next VM.
 
        .PARAMETER ComputerName
            Specifies the Hyper-V host to start the VM on.
 
        .PARAMETER VM
            Specifies a list of VMs to start.
 
        .PARAMETER Wait
            Specifies a number of seconds to wait after the previous VM has booted successfully. Defaults to 180 seconds.

        .PARAMETER ShowProgress
            Specified whether to show progress as VMs are started.
 
        .EXAMPLE
            Start-SequentialVMs -ComputerName hyperv1 -VMList "sql1", "pvs1", "xd71" -Wait 20

        .NOTES
 
        .LINK
            http://stealthpuppy.com/sequential-start-vms
 
    #>
    param(
        [Parameter(Mandatory=$true, Position=0,HelpMessage="Hyper-V host.")]
        [string]$ComputerName = $(throw = "Please specify a remote Hyper-V host to start VMs on."),

        [Parameter(Mandatory=$true, Position=1,HelpMessage="List of VMs to start.")]
        [string[]]$VMList = $(throw = "Please specifiy a list of VMs to start"),

        [Parameter(Mandatory=$false)]
        [int]$Wait = 180,

        [Parameter(Mandatory=$false)]
        [bool]$ShowProgress
    )

    # Connect to Hyper-V host before attempting to start VMs. Stop script if unable to connect
    Write-Verbose "Connecting to VM host."
    Get-VMHost -ComputerName $ComputerName -Verbose $False -ErrorAction Stop

    # Start progress at 0
    $Percent = 0

    # Step through list of provided VMs
    ForEach ( $vm in $VMList ) {

        # Convert current location in list of VMs to a percentage
        $Percent = ($VMList.IndexOf($vm)/$VMList.Count) * 100

        # Show progress if specified on the command line
        If ($ShowProgress -eq $True) { Write-Progress -Activity "Starting VMs." -Status "Starting VM $vm." -PercentComplete $Percent }

        # Get status for current VM
        Remove-Variable currentVM -ErrorAction SilentlyContinue
        Write-Verbose "Getting status for VM $vm..."
        $currentVM = Get-VM -ComputerName $ComputerName -Name $vm -ErrorAction SilentlyContinue

        # If the VM exists, then power it on if it is in an Off state
        If ($currentVM.Length -gt 0) {
            If ($currentVM.State -eq "Off" ) {
                Start-VM -ComputerName $ComputerName -Name $vm -Verbose
                
                # Wait for VM to boot and report a heartbeat
                Write-Verbose "Waiting for VM heartbeat."
                Do {
                    Start-Sleep -milliseconds 100
                } Until ((Get-VMIntegrationService $currentVM | ?{$_.name -eq "Heartbeat"}).PrimaryStatusDescription -eq "OK")

                # Wait the specified number of seconds before booting the next VM, unless this is the last VM in the list
                If ($Wait -gt 0 -and $VMList.IndexOf($vm) -lt ($VMList.Count-1)) {
                    Write-Verbose "Waiting for $Wait seconds before starting next VM."
                    Start-Sleep -Seconds $Wait
                }

            } Else {
                Write-Verbose "VM $vm already running."
            }

        } Else {
            Write-Error -Message "Unable to find VM $vm on host $ComputerName." -Category ObjectNotFound
        }

     }

     Write-Verbose "Started VMs."

     # Show progress if specified on the command line
     If ($ShowProgress -eq $True) { Write-Progress -Activity "Starting VMs." -Status "Started all VMs." -PercentComplete 100 }
     Start-Sleep -Seconds 1
}

Save the script as Start-SequentialVMs.ps1 and run it or add the function to your PowerShell profile so that the function is available when starting PowerShell. Use Get-Help to see the full syntax and examples from within a PowerShell window.

Creative Commons LicenseSequential Starting of a List of VMs is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2014 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

Cleaning up and Reducing the Size of your Master Image

$
0
0

Compressed Car

There’s typically not too much that you can do to reduce the size of your master image. You might use application virtualization or layering solutions to reduce the number of master images, but once you work out what needs to go into the core image, that’s going to dictate the size of the image.

Reducing the size of your master image can help reduce the capacity required to store master images and virtual machines (dedupe helps, of course) and spend less cycles transmitting an image across the network for physical PCs.

An easy win, is running the Disk Clean-up tool included in Windows (since Windows XP) and fortunately this tool can be automated to run at the end of a build (e.g from MDT or ConfigMgr). For physical PCs or persistent desktops, this tool could even be run as a scheduled task.

Microsoft released an important update for Windows 7 last year that can result in a significant reduction in disk space: Disk Clean-up Wizard addon lets users delete outdated Windows updates on Windows 7 SP1. The same feature was originally delivered with Windows 8. (Windows 8.1 Update 1 is expected to reduce disk space requirements again).

Here’s an example system where I’ve run the Disk Clean-up tool that has resulted in a 3.4 GB reduction in disk usage – on the left is the before image, on the right is after the cleanup. (I’m cheating a bit here, this is a system that has gone from Windows 7 to Windows 7 SP1, hence the reason for such a large change).

Compare Disk Cleanup Before and After

Disk Clean-up can remove a number of interesting items, most of which will actually be applicable for PCs and persistent desktops post-deployment. Here’s the items that Disk Clean-up can manage on Windows 8.1:

Disk Cleanup options

To automate Disk Clean-up, use the following steps:

  1. Elevate a command prompt
  2. Run CLEANMGR /SAGESET:<number> (where <number is any number between 1 and 65535)
  3. Select each of the items to clean up
  4. Click OK

To run Disk Clean-up from a script run CLEANMGR /SAGERUN:<number> (where <number> is the same number use with SAGESET.

To automate the process of running Disk Cleanup, the following script can be used to enable all of the tool’s options in the registry and then execute the cleanup process. This script should work for both Windows 7 and Windows 8 and would be useful to run at the end of a deployment. This example uses 100 as the configuration setting, so you would run CLEANMGR /SAGERUN:100 to run Disk Cleanup with these settings.

@ECHO OFF
REM Enable components to cleanup
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Active Setup Temp Folders" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\BranchCache" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Downloaded Program Files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\GameNewsFiles" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\GameStatisticsFiles" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\GameUpdateFiles" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Internet Cache Files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Memory Dump Files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Offline Pages Files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Old ChkDsk Files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Previous Installations" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Recycle Bin" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Service Pack Cleanup" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Setup Log Files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\System error memory dump files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\System error minidump files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Temporary Files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Temporary Setup Files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Temporary Sync Files" /V StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Thumbnail Cache" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Update Cleanup" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Upgrade Discarded Files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\User file versions" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Defender" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Error Reporting Archive Files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Error Reporting Queue Files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Error Reporting System Archive Files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Error Reporting System Queue Files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows ESD installation files" /v StateFlags0100 /d 2 /t REG_DWORD /f
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Windows Upgrade Log Files" /v StateFlags0100 /d 2 /t REG_DWORD /f

REM Run cleanup
IF EXIST %SystemRoot%\SYSTEM32\cleanmgr.exe START /WAIT cleanmgr /sagerun:100

It’s important to note that while Disk Clean-up exists on Windows 7 and Windows 8, it does not exist on Windows Server unless the Desktop Experience feature is installed (i.e. a Remote Desktop Session Host).

If your image is Windows 8.1 or Windows Server 2012 R2, then the following command is available to perform an even more in depth cleanup of the WinSXS folder, making some additional space available:

Dism.exe /online /Cleanup-Image /StartComponentCleanup /ResetBase

Running Disk Clean-up and the above DISM command in a script to clean up your master image should result in a smaller image. Don’t forget that this approach is also useful for persistent desktops – unless you’re using some type of dedupe solution, then there’s potentially gigabytes per desktop that can be removed.

There is one more method worth for reducing space worth mentioning – the Uninstall-WindowsFeature PowerShell cmdlet in Windows Server 2012 and Windows Server 2012 R2. This can go a long way too to reducing the disk footprint by completely removing features from Windows (making them unavailable for install).

For instance, if you’re deploying a Remote Desktop Session Host, there’s no need for IIS or Hyper-V to be in the component store. See this blog post article for full details: How to Reduce the Size of the Winsxs directory and Free Up Disk Space on Windows Server 2012 Using Features on Demand

[May 14 2014] Microsoft has released this update for Windows Server 2008 R2, which can be on the original KB article here: Disk Cleanup Wizard add-on lets users delete outdated Windows updates on Windows 7 SP1 or Windows Server 2008 R2 SP1. The update is available from Windows Update and WSUS.

Creative Commons LicenseCleaning up and Reducing the Size of your Master Image is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2014 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

Building a Lab Server to Run ESXi and Hyper-V

$
0
0

One of the great things I enjoyed about working at Kelway was the access to a pretty solid lab environment. While I do have access to a lab environment at Atlantis (3 in fact), now that I work primarily from home, I really prefer a lab environment that can provide me more flexibility. Only a local environment can do that.

I originally started out with the aim of building a system that achieved 3 goals – low power consumption, enough grunt to deliver the workloads I’d like to run, plus be (relatively) quiet. As you can probably guess, I’ve achieved only two of those objectives (plus blowing my budget in the process).

Having recently moved back to Australia from the UK, I’ve gone from spending approximately £500 a year on electricity and gas, to what I estimate will be $1500 AU on electricity (no gas appliances in our current house). If you weren’t already aware, Australian summers can be hot (or bloody hot, as I prefer to say). Living in Melbourne means summers are shorter than Sydney or Brisbane, but I’ll still have two issues – heat and the cost of running a lab at home.

I first started looking at a Lenovo ThinkCentre M83 SFF Pro, as it’s the only small-form factor PC that I can find that can take 32 GB of RAM. While it looks like a good PC, it was coming out a bit expensive for what it is and an unknown quantity when it comes to noise.

It’s been a long time since I’ve built a PC from scratch, so to get exactly what I wanted, I thought this would be a good opportunity to do so. First though, a word of caution, I’m no expert, what I’ve ended up with worked for me and this spec could be definitely be improved upon.

Picking a CPU

My first step was to settle on a CPU – that way I can build everything else around it as the choice of CPU has an impact on the socket and motherboard plus the maximum amount of RAM. While I did do some research on various processors, I did find that I ended up being limited by availability.

Intel CPUs have been my personal preference, so I ruled out AMD immediately. If I’d used an AMD CPU, I probably could have saved a bit on the final build.

Starting with the Core i5 made some sense, both from a power consumption and cost perspective, but the i5 has two things going against it – no Hyper-Threading and a maximum of 32 GB of RAM. I didn’t want to limit my workloads, so I’ve gone with a Core i7.

To build a 32 GB system, you could go with the Core i7-4770K that uses a socket LGA1150. One problem with the 4th generation Core i7 (i.e. Haswell) is that they don’t yet support 64GB of RAM (as far as I can tell).

Core-i7-CPUFor a 64 GB system I picked the Core i7-4820K – this CPU is the older Ivy Bridge-E architecture. While I priced up a system based on the 4770K, I ended up going with the 4820K, so that I could build a machine with 64 GB of RAM.

As I’m doing testing and modelling with a solution that utilise a lot of RAM, I really needed to go with as much RAM as I could afford. There ended up being about $500-$600 AU difference between a 32 GB system and a 64 GB system, so budget be damned, 64 GB PC is what I got.

Selecting a Motherboard

I had originally wanted to build a system around a min-ITX or mini/microATX board to build a smaller PC but the choice of CPU using the socket LGA2011 and 64 GB of RAM has forced me on to a full ATX board.

As I’m not interested in over-clocking, my requirements for a motherboard were simple – I went for the lowest price board that could fit 64 GB of RAM (8 DIMM slots) and supports a minimum of 4 x SATA3 (6Gbps) ports. Unless you’re looking at server boards, you’ll find most desktop motherboards come with a lot of extra features that are just not required for a lab server (sound, SPDIF, heaps of USB ports, FireWire etc.).

ASRock-Extreme6Ultimately I went for the ASRock X79 Extreme 6 with 5 x SATA 3 ports. One thing I’ve found out in building this PC, is that the Intel chipsets typically provide 2 x SATA3 ports only. The remaining SATA ports are provided by a second chipset (or sometimes even a third chipset). Not a problem for Windows, but not the best choice for ESXi (more on that later).

Filling it With RAM

G.Skill-RipjawsX

With 8 DIMM slots to fill and 64 GB of RAM to get to, I needed to find 8 x 8 GB DIMMs. The ASRock X79 Extreme 6 supports 2400 / 2133 / 1866 / 1600 / 1333 / 1066 MHz clock speeds.

I originally looked at Corsair Vengeance RAM but settled on G.Skill RipjawsX DDR3-1600 F3-1600C9Q-32GXM, at $100 AU less than the Corsair. With a CAS latency of 9-9-9-24, I think this ended up being good value for money.

Housing the Rig in a Case

Corsair-330rI had two main requirements for a case – help the PC be as silent as possible and look unassuming (as it’s not locked away but sitting next to the living room). Additionally, as I’d locked myself into an ATX board, I needed an ATX case.

When picking a case, I looked at cooling options as well – by picking a CPU cooler, case fans and a case from the same manufacture, I was comfortable that I could build the system knowing that every thing would fit. I picked the Corsair Carbide 330R Quiet Mid-Tower case which looks nice and has good reviews.

Keeping it Cool

Corsair-H55While a water cooler probably pulls more power than a heat sink/fan combination, I went with water cooling to ensure I could move heat away from the CPU as efficiently as possible.

I chose the Corsair Hydro Series H55 Quiet CPU Cooler. This is a single fan, 120mm radiator but should be enough to sufficiently move any heat generated by the CPU.

The 330R includes 1 x 120mm (rear) and 1 x 140mm fans (front), but I’ve replaced those with Corsair’s Quiet Edition 120mm and 140mm fans with a second 140mm in the front to pull in more air. The case does include room for two 120mm or 140mm fans with a radiator in the top, which requires popping the top plate off to allow for exhaust but would increase the noise coming out of the system.

Snorage

samsung_840_evo_ssd_0To ensure the lowest power consumption for storage devices, I’ve stuck with SSDs. I had a few SSDs already on hand already, but did purchase a couple more to provide more capacity.

In the PC I have installed:

  • 1 x Corsair 64 GB SSD SATA2 (although this drive works under Windows, I can’t mount it under ESXi)
  • 1 x OCZ Vertex 3 120 GB SSD
  • 1 x Samsung 840 EVO Pro 120 GB SSD
  • 2 x Samsung 840 EVO 250 GB SSDs (these are new)

I’ve also got an 8GB USB3 flash drive that ESXi is running from. It will be interesting to see when this drive fails, which is inevitable if I’ve got an OS running from it.

Powering the Beast

Calculating how much power was quite simple, once you find a tool that does it for you. Bryan Chriscoli put me onto eXtreme Power Supply Calculator Lite which does a fantastic job of calculating the minimum PSU wattage required.

Corsair-RM450To power the PC I chose the Corsair RM450 power supply. This is a 450W 80 PLUS Gold Certified (i.e. highly efficient) modular power supply, which is probably more than I need but I found 400W power supplies, that didn’t look like cheap crap, hard to come by.

The RM450 has a fan that will only power on after the PSU reaches a temperature that requires a fan shifting heat, keep noise down during normal operation. It’s a great quality PSU that looks good and feels nice in the hand.

I had originally looked at the Seasonic 400W fanless power supply, but was a little worried that on a really hot day, shifting heat out of the case could be a problem and it’s also a pretty expensive PSU.

Miscellaneous additions

The ASRock mother board has a single Broadcom BCM57781 Gigabit adapter on-board, so I’ve added an Intel Gigabit CT Desktop PCIe adapter. This way I can use the Broadcom adapter for management traffic and the Intel adapter for virtual machine networks.

Something I didn’t realise until I’d put the whole thing together, is that the ASRock Extreme 6 motherboard doesn’t include a GPU. I’d originally focussed on motherboards with on-board Intel graphics and completely forgot to check the ASRock board when ordering it. So I’ve added an EVGA NVIDIA GeForce 201 fanless graphics adapter to the build as well. While this is silent, will have increased the power consumption of the system a bit.

Thoughts on Building this PC

Building this PC took a really long time – it’s been quite a while since I last built a PC and I needed to ensure I got this one right and it was up and running on first go (other than having to source a graphics adapter after completing the build).

Here’s a few thoughts and tips if you’re looking to build your own lab PC:

  • Picking the right hardware and finding out which parts will be suitable is painful. The best site I found that helped me build the right parts as PCPartPicker. It would be nice if PC parts retailers provided this functionality in their web sites, but most of them (at least in Australia) have terrible web sites.
  • The Corsair Carbide 330R is a nice case and performs well for airflow and noise. It would have been nice to have more than 4 x 3.5″ drive bays and there’s not a lot of space between the back of the motherboard and the side panel. This makes putting the side panel back on a challenge, because the routed cables don’t sit completely flat. While I think the 330R is a nice case, I think you could choose a better case.
  • This is the first time I’ve built a water cooled PC – fitting the fan and radiator was fiddly, but fitting the CPU cooler was very simple. Although Corsair recommends fitting the radiator fan so that it sucks air into the case, I’ve fitted it to blow air out of the case – which is a good thing, since…
  • I should have picked low profile DIMMs. The radiator fan is practically sitting right on top of the RAM heat sinks. I don’t think this is an issue, but at least it’s not the radiator touch the heat sinks.
  • Unfortunately the i7 4820K CPU can run at up to 130W, so not ideal for low power.
  • To get the additional SSDs connected to SATA ports on the ASMedia chipset working, I needed to follow this article: How to make your unsupported SATA AHCI Controller work with ESXi 5.5. Without this change to ESXi, the drives connected to the additional SATA ports were just not seen. This wasn’t a problem under Windows Server.
  • The noise level at idle is pretty good, but could be better. I’m now investigating a fan controller and I’m sure that I can run the fans at lower speeds to reduce noise, without affecting cooling performance too much.

Performance

Getting this up and running under Windows Server 2012 R2 was very simple, practically all drivers were picked up by Windows natively or found on Windows Update. Taking a look at Task Manager is a thing of beauty:

hv2-TaskManager-RAM-VanillaInstall

I’m yet to do full performance tests and one thing to attempt is running Login VSI to see what I can get out of it. A simple test of IOmeter simulating a VDI workload on ILIO for Persistent VDI drove an impressive 42K IOPs (with ILIO for Stateless VDI doing about the same number).

Lab-ILIO-Test1

As for power consumption, at idle with ESXi 5.5 booted, it draws up to around 105 watts. I have seen it drop to a low of between 65 and 71 watts as well. As a very basic CPU stress test, I ran HeavyLoad 3.3 on a Windows 8.1 x86 virtual machine with 1 vCPU and 8 cores. Power consumption jumped up to a consistent 128 watts.

128watts

So not as low power as I originally set out to accomplish, but with this configuration it’s a pretty beefy work horse. Some more testing with different settings and under Hyper-V is required.

Spec List

Here’s the final list of components that went into the build and the price in Australian dollars. I’ve colour coded the totals to make it simple to see where the costs went into. It’s not surprising that the most expensive component of this build was the RAM.

PCbuild

Finally, here’s a look inside the finished build:

InsideCustomBuild

Creative Commons LicenseBuilding a Lab Server to Run ESXi and Hyper-V is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2014 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

Performing vSphere VM RAM Overhead Lookups in Excel

$
0
0

Running VMs under ESXi will incur a memory overhead for each virtual machine.  You can read about this overhead here: Understanding Memory Overhead. Essentially memory overhead is:

Overhead memory includes space reserved for the virtual machine frame buffer and various virtualization data structures, such as shadow page tables. Overhead memory depends on the number of virtual CPUs and the configured memory for the guest operating system.

While ESXi provides memory optimisations such as page sharing which have the potential to save more memory than is taken up by the overhead, it’s still worth including the RAM overhead in any calculations used to determine the number of VMs per host (especially for VDI or RDS/XenApp).

If I’m going through a sizing exercise, I’m not typically going to account for RAM optimisations as I don’t know how much RAM will be saved until the solution is deployed.

VMware has a reasonably complete table for VM RAM overhead for ESXi 4.0, plus a sample table for ESXi 5.1. From what I can tell, a complete table for ESXi 5.x doesn’t exist, so unfortunately you’ll need to create your own. That’s a straight-forward task, but will be time consuming.

I’ve created an Excel spreadsheet that I can use for estimating the number of virtual desktops or XenApp servers per host based on some specific configurations and that includes calculating the VM RAM overhead.

Creating a formula to perform the lookup, I’ve used the INDEX and MATCH functions to look up the number of vCPUs against the amount of RAM assigned to the VM, to return the VM RAM Overhead.

Here’s what it looks like in Excel:

The INDEX formula is used to return the amount of RAM overhead based on the vCPU and RAM values that we input into the spreadsheet. In this instance, I have two inputs – number of vCPUs (B3) and amount of RAM in GB (B4) assigned to my sample VM (for RDS/XenApp or VDI, I’ve assumed that all VMs on the host are configured identically.

INDEX(array,row_num,column_num)

Here, array is the amount of RAM Overhead to select from – essentially the lookup table I’ve added into the spreadsheet that lists the amount of VM RAM Overhead (D6 to I16), row_num is the number of vCPUs assigned to the VM (1 to 8), column_num is the amount of RAM assigned to the VM (256Mb to 256GB).

To select from the appropriate row and column in the table, I need to match the inputs from the array of vCPUs (E5 to L5, or 1 to 8 vCPUs) and the amount of RAM (from D6 to D16, or 256Mb to 256GB of RAM).  The MATCH formula will look like the below. Lookup_value will be the number of vCPUs or amount of RAM, lookup_array is the number of vCPUs in the table to select from (1 to 8). We can ignore match_type.

MATCH(lookup_value, lookup_array, [match_type])

So, now my formula will look something like this:

INDEX(array,(MATCH(lookup_value, lookup_array)),(MATCH(lookup_value, lookup_array)))

To make this work in Excel, I’ve also added two extra components to the formula, converting GB to MB by multiplying the VM RAM size input (B5) by 1024 and rounding the result to a single decimal place. The resulting formula is then:

=ROUND((INDEX(<Lookup table>,MATCH((<VM RAM size in GB>*1024),<VM RAM size column>),MATCH(<No. VM vCPUs,<vCPUs Row>))),1)

I can then multiply the result by the number of VMs to get a full picture of the amount of RAM consumed on the host.

Here’s a downloadable version of the Excel spreadsheet, which includes the ESXi 4.x version of the VM RAM Overhead.

VM RAM Overhead Calculator VM RAM Overhead Calculator

With a bit of effort, you could update the table for ESXi 5.x.

Creative Commons LicensePerforming vSphere VM RAM Overhead Lookups in Excel is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2014 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

BriForum 2014 – Hands Off My Gold Image! The Slides

$
0
0

BriForum 2014 - Hands off my gold image

Thanks to all who attended my BriForum 2014 session in Boston – Hands Off My Gold Image! I was pleasantly surprised to have a full room and good feedback after the session.

For reference, or if you weren’t able to attend, here’s a copy of the full slide deck. If you have any questions, drop me a line on Twitter.

Hands Off My Gold Image! BriForum 2014, Boston Hands Off My Gold Image! BriForum 2014, Boston

Creative Commons LicenseBriForum 2014 – Hands Off My Gold Image! The Slides is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2014 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

Retrieving a VM’s UUID from Hyper-V

$
0
0

I’ve previously posted about retrieving the UUID from a virtual machine hosted on vSphere. UUIDs are useful if you want to uniquely identify a target machine for OS deployment task sequences and the like (e.g. MDT). Here’s how to obtain the UUID from a virtual machine hosted on Hyper-V.

Just like with vSphere, the UUID isn’t a property of the virtual machine that can be queried directly. We need to go via WMI to query the target virtual machine. Note that in this function, I’m using version 2 of the Root\Virtualization WMI namespace (root\virtualization\v2. This means the function as written, will only work on Windows 8 and Windows Server 2012 (and above). If you want to use this function on earlier versions of Hyper-V, remove the “\v2″ from the namespace.

As an example, here’s how to retrieve the UUIDs from a set of VMs on a target Hyper-V host named hv1:

PS C:\> Get-HypervVMUUID -ComputerName hv1 -VM win71, file3, pvs1

Name		BIOSGUID
----		----
WIN71		E6E1A176-0713-4BB0-99E9-4570A1A3A94A 
FILE3		9E9D788A-15E2-4760-A049-9F6EB88677A9 
PVS1		74EFF5BC-A24E-48C3-85BE-12D758FE7AB6

Here’s the full function code listing. Please let me know if you find any bugs:

#---------------------------------------------------------------------------
# Author: Aaron Parker
# Desc:   Function that uses retrieves the UUID from a specified VM and
#         formats it into the right format for use with MDT/SCCM etc
# Date:   Aug 18, 2014
# Site:   http://stealthpuppy.com
#---------------------------------------------------------------------------
 

Function Get-HypervVMUUID {

   <#
        .SYNOPSIS
            Retrieve the UUID from a virtual machine or set of virtual machines.
 
        .DESCRIPTION
            This function will retrieve the UUID from from a virtual machine or set of virtual machines from a Hyper-V host.
 
        .PARAMETER ComputerName
            Specifies the host from which to query the virtual machine or set of virtual machines.
 
        .PARAMETER VM
            Specifies the virtual machine or set of virtual machines (a comma delimited list) from which to obtain the UUID/s.
 
         .EXAMPLE
            PS C:\> Get-HypervVMUUID -ComputerName hv1 -VM win71, win72
 
            This command retrieves the UUIDs from the virtual machines win71 and win72 from the host hv1.
 
        .EXAMPLE
            PS C:\> Get-HypervVMUUID -VM win71, win72
 
            This command retrieves the UUIDs from the virtual machines win71 and win72 from the local host.
 
        .EXAMPLE
            PS C:\> Get-HypervVMUUID
 
            This command retrieves the UUIDs from the all of the virtual machines on the local host.
 
        .NOTES
            http://stealthpuppy.com/retrieving-a-vms-uuid-from-hyperv/ for support information.
 
        .LINK
 
http://stealthpuppy.com/retrieving-a-vms-uuid-from-hyperv/
 
    #>

    [cmdletbinding(SupportsShouldProcess=$True)]
    param(
        [Parameter(Mandatory=$false,HelpMessage="Specifies one or more Hyper-V hosts from which virtual machine UUIDs are to be retrieved. NetBIOS names, IP addresses, and fully-qualified domain names are allowable. The default is the local computer — use ""localhost"" or a dot (""."") to specify the local computer explicitly.")]
        [string]$ComputerName,

        [Parameter(Mandatory=$false, Position=0,HelpMessage="Specifies the virtual machine from which to retrieve the UUID.")]
        [string[]]$VM
    )

    # If ComputerName parameter is not specified, set value to the local host
    If (!$ComputerName) { $ComputerName = "." }

    # If VM parameter is specified, return those VMs, else return all VMs
    If ($VM) {
        $UUIDs = Get-VM -ComputerName $ComputerName -VM $VM -ErrorAction SilentlyContinue | Select-Object Name,@{Name="BIOSGUID";Expression={(Get-WmiObject -ComputerName $_.ComputerName -Namespace "root\virtualization\v2" -Class Msvm_VirtualSystemSettingData -Property BIOSGUID -Filter ("InstanceID = 'Microsoft:{0}'" -f $_.VMId.Guid)).BIOSGUID}}
    } Else {
        $UUIDs = Get-VM -ComputerName $ComputerName -ErrorAction SilentlyContinue | Select-Object Name,@{Name="BIOSGUID";Expression={(Get-WmiObject -ComputerName $_.ComputerName -Namespace "root\virtualization\v2" -Class Msvm_VirtualSystemSettingData -Property BIOSGUID -Filter ("InstanceID = 'Microsoft:{0}'" -f $_.VMId.Guid)).BIOSGUID}}
    }

    # Remove curly brackets from the UUIDs and return the array
    ForEach ( $UID in $UUIDs ) { $UID.BIOSGUID = $UID.BIOSGUID -replace "}"; $UID.BIOSGUID = $UID.BIOSGUID -replace "{" }
    Return $UUIDs
}

 

Creative Commons LicenseRetrieving a VM’s UUID from Hyper-V is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2014 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

Creating an MCS-based XenDesktop Machine Catalog with PowerShell

$
0
0

Driving XenDesktop with PowerShell is a challenge to say the least. While documentation for the XenDesktop PowerShell modules is OK and Citrix Studio outputs PowerShell code after you’ve completed a task in the console, there’s still plenty of work to get that code into something usable.

As part of an ongoing series of articles themed around automating virtual desktop deployment, I’ve written some PowerShell code to automate the creation of an non-persistent, MCS-based Machine Catalog based on a specific Windows image, that we’ve already automated with a solution such as MDT.

Don’t expect to copy and paste the PowerShell output in Citrix Studio and have a complete script. The code is missing a number of lines that link tasks together. I found this article on the Citrix Blogs quite useful – Using PowerShell to Create a Catalog of Machine Creations Services Machines; however I’ve taken my script a few steps further.

Linking the Code to the UI

While the Create Machine Catalog wizard doesn’t expose everything that goes on behind the scenes when a machine catalog is created, I think it’s still worth showing how specific functions relate to choices that the administrator makes in the wizard.

The screenshots below show just a snippet of the functions required to automate the catalog creation using PowerShell. These walkthrough the same environment that the full code listing at the end of this article is creating. See the image captions for example code that applies to each step.

New-BrokerCataog is used to create the machine catalog and set a number of properties. You’ll see New-BrokerCatalog across a number of these screen shots. First up is setting the broker type – in this instance, I’m deploying a Windows 8 image, so need to choose ‘Windows Desktop OS':

Selecting the Machine Catalog type - New-BrokerCatalog SessionSupport SingleSession

Selecting the Machine Catalog type – New-BrokerCatalog -SessionSupport SingleSession

Because were using MCS, I’m going to specify that I’m using virtual machines and choose the storage on which to deploy those VMs and use the ProvisioningType parameter on New-BrokerCatalog to specify MCS. This is done in PowerShell via a number of commands – see around line 45 where we specify the hypervisor management and storage resource to use.

Selecting the provisioning type - New-BrokerCatalog -ProvisioningType $provType

Selecting the provisioning type – New-BrokerCatalog -ProvisioningType MCS

Also on the New-BrokerCatalog, we can specify that this is a set of randomly assigned desktops.

Selecting Random or Static desktops - New-BrokerCatalog -AllocationType Random

Selecting Random or Static desktops – New-BrokerCatalog -AllocationType Random

To find the image to use, I’ve obtained the path to the master image and its snapshot via the Get-ChildItem command (on the path XDHyp:\HostingUnits\<Storage Resource>) and passed that to New-ProvScheme.

Selecting the master image and snapshot to use - New-ProvScheme -ProvisioningSchemeName "Windows 8" -HostingUnitName "HV1-LocalStorage -MasterImageVM "XDHyp:\HostingUnits\HV1-LocalStorage\WIN81.vm\MasterImage.snapshot"

Selecting the master image and snapshot to use – New-ProvScheme -ProvisioningSchemeName “Windows 8″ -HostingUnitName “HV1-LocalStorage” -MasterImageVM “XDHyp:\HostingUnits\HV1-LocalStorage\WIN81.vm\MasterImage.snapshot”

Also with New-ProvScheme we can set the number of virtual CPUs and the amount of RAM to assign to each virtual desktop. To specify the number of desktops to create, we’re actually first specifying the number of AD machine accounts to create via New-AcctADAccount and then creating the same number of desktops to assign to those accounts.

Selecting the virtual machine configurations - New-ProvScheme -VMCpuCount 2 -VMMemoryMB 2048

Selecting the virtual machine configurations – New-ProvScheme -VMCpuCount 2 -VMMemoryMB 2048

New-AcctIdentityPool is used to create an identity pool that stores the machine accounts by specifying the naming convention and where the accounts will be stored.

Setting machine account names and location - New-AcctIdentityPool -Domain 'home.stealthpuppy.com' -NamingScheme 'W8-MCS-###'-NamingSchemeType Numeric -OU 'OU=MCS Pooled,OU=Workstations,DC=home,DC=stealthpuppy,DC=com'

Setting machine account names and location – New-AcctIdentityPool -Domain ‘home.stealthpuppy.com’ -NamingScheme ‘W8-MCS-###’-NamingSchemeType Numeric -OU ‘OU=MCS Pooled,OU=Workstations,DC=home,DC=stealthpuppy,DC=com’

Again we can see where New-BrokerCataog is used to specify the catalog name and description.

Setting the machine catalog name and description - New-BrokerCatalog  -Name "Windows 8 x86" -Description "Windows 8.1 x86 SP1 with Office 2013"

Setting the machine catalog name and description – New-BrokerCatalog -Name “Windows 8 x86″ -Description “Windows 8.1 x86 SP1 with Office 2013″

There’s plenty that the wizard does to hide the complexity of setting up a catalog from the administrator. If you attempt the same via PowerShell, what goes on under the hood is laid bare.

The Code

Below is the full code listing with comments inline that should provide some detail on the process the code follows. At this point the code provides some error checking for the most important steps. There are still some additional steps and error checking that could be integrated:

  • This code should find the last snapshot of the target master image; it would be simple enough to specify a particular snapshot if required
  • Checking whether provisioning schemes are already available or exist before attempting to create a new provisioning scheme
  • Additional checking that some tasks have completed successfully before continuing

#---------------------------------------------------------------------------
# Author: Aaron Parker
# Desc:   Using PowerShell to create a XenDesktop 7.x machine catalog 
# Date:   Aug 19, 2014
# Site:   http://stealthpuppy.com
#---------------------------------------------------------------------------

# Set variables for the target infrastructure
# ----------
$adminAddress = 'xd71.home.stealthpuppy.com' #The XD Controller we're going to execute against
$xdControllers = 'xd71.home.stealthpuppy.com'

# Hypervisor and storage resources
# These need to be configured in Studio prior to running this script
# This script is hypervisor and management agnostic - just point to the right infrastructure
$storageResource = "HV1-LocalStorage" #Storage
$hostResource = "Lab SCVMM" #Hypervisor management

# Machine catalog properties
$machineCatalogName = "Windows 8 x86"
$machineCatalogDesc = "Windows 8.1 x86 SP1 with Office 2013"
$domain = "home.stealthpuppy.com"
$orgUnit = "OU=MCS Pooled,OU=Workstations,DC=home,DC=stealthpuppy,DC=com"
$namingScheme = "W8-MCS-###" #AD machine account naming conventions
$namingSchemeType = "Numeric" #Also: Alphabetic
$allocType = "Random" #Also: Static
$persistChanges = "Discard" #Also: OnLocal, OnPvD
$provType = "MCS" #Also: Manual, PVS
$sessionSupport = "SingleSession" #Also: MultiSession
$masterImage ="WIN81*"
$vCPUs = 2
$VRAM = 2048
# ----------

# Change to SilentlyContinue to avoid verbose output
$VerbosePreference = "Continue"

# Load the Citrix PowerShell modules
Write-Verbose "Loading Citrix XenDesktop modules."
Add-PSSnapin Citrix*

# Get information from the hosting environment via the XD Controller
# Get the storage resource
Write-Verbose "Gathering storage and hypervisor connections from the XenDesktop infrastructure."
$hostingUnit = Get-ChildItem -AdminAddress $adminAddress "XDHyp:\HostingUnits" | Where-Object { $_.PSChildName -like $storageResource } | Select-Object PSChildName, PsPath
# Get the hypervisor management resources
$hostConnection = Get-ChildItem -AdminAddress $adminAddress "XDHyp:\Connections" | Where-Object { $_.PSChildName -like $hostResource }
$brokerHypConnection = Get-BrokerHypervisorConnection -AdminAddress $adminAddress -HypHypervisorConnectionUid $hostConnection.HypervisorConnectionUid
$brokerServiceGroup = Get-ConfigServiceGroup -AdminAddress $adminAddress -ServiceType 'Broker' -MaxRecordCount 2147483647

# Create a Machine Catalog. In this case a catalog with randomly assigned desktops
Write-Verbose "Creating machine catalog. Name: $machineCatalogName; Description: $machineCatalogDesc; Allocation: $allocType"
$brokerCatalog = New-BrokerCatalog -AdminAddress $adminAddress -AllocationType $allocType -Description $machineCatalogDesc -Name $machineCatalogName -PersistUserChanges $persistChanges -ProvisioningType $provType -SessionSupport $sessionSupport
# The identity pool is used to store AD machine accounts
Write-Verbose "Creating a new identity pool for machine accounts."
$identPool = New-AcctIdentityPool -AdminAddress $adminAddress -Domain $domain -IdentityPoolName $machineCatalogName -NamingScheme $namingScheme -NamingSchemeType $namingSchemeType -OU $orgUnit

# Creates/Updates metadata key-value pairs for the catalog (no idea why).
Write-Verbose "Retrieving the newly created machine catalog."
$catalogUid = Get-BrokerCatalog | Where-Object { $_.Name -eq $machineCatalogName } | Select-Object Uid
$guid = [guid]::NewGuid()
Write-Verbose "Updating metadata key-value pairs for the catalog."
Set-BrokerCatalogMetadata -AdminAddress $adminAddress -CatalogId $catalogUid.Uid -Name 'Citrix_DesktopStudio_IdentityPoolUid' -Value $guid

# Check to see whether a provisioning scheme is already available
Write-Verbose "Checking whether the provisioning scheme name is unused."
If (Test-ProvSchemeNameAvailable -AdminAddress $adminAddress -ProvisioningSchemeName @($machineCatalogName))
{
  Write-Verbose "Success."

  # Get the master VM image from the same storage resource we're going to deploy to. Could pull this from another storage resource available to the host
  Write-Verbose "Getting the master image details for the new catalog: $masterImage"
  $VM = Get-ChildItem -AdminAddress $adminAddress "XDHyp:\HostingUnits\$storageResource" | Where-Object { $_.ObjectType -eq "VM" -and $_.PSChildName -like $masterImage }
  # Get the snapshot details. This code will assume a single snapshot exists - could add additional checking to grab last snapshot or check for no snapshots.
  $VMDetails = Get-ChildItem -AdminAddress $adminAddress $VM.FullPath
  
  # Create a new provisioning scheme - the configuration of VMs to deploy. This will copy the master image to the target datastore.
  Write-Verbose "Creating new provisioning scheme using $VMDetails.FullPath"
  # Provision VMs based on the selected snapshot.
  $provTaskId = New-ProvScheme -AdminAddress $adminAddress -ProvisioningSchemeName $machineCatalogName -HostingUnitName $storageResource -MasterImageVM $VMDetails.FullPath -CleanOnBoot -IdentityPoolName $identPool.IdentityPoolName -VMCpuCount $vCPUs -VMMemoryMB $vRAM -RunAsynchronously
  $provTask = Get-ProvTask -AdminAddress $adminAddress -TaskId $provTaskId

  # Track the progress of copying the master image
  Write-Verbose "Tracking progress of provisioning scheme creation task."
  $totalPercent = 0
  While ( $provTask.Active -eq $True ) {
    Try { $totalPercent = If ( $provTask.TaskProgress ) { $provTask.TaskProgress } Else {0} } Catch { }

    Write-Progress -Activity "Creating Provisioning Scheme (copying and composing master image):" -Status "$totalPercent% Complete:" -percentcomplete $totalPercent
    Sleep 15
    $provTask = Get-ProvTask -AdminAddress $adminAddress -TaskID $provTaskId
  }

  # If provisioning task fails, there's no point in continuing further.
  If ( $provTask.WorkflowStatus -eq "Completed" )
  { 
      # Apply the provisioning scheme to the machine catalog
      Write-Verbose "Binding provisioning scheme to the new machine catalog"
      $provScheme = Get-ProvScheme | Where-Object { $_.ProvisioningSchemeName -eq $machineCatalogName }
      Set-BrokerCatalog -AdminAddress $adminAddress -Name $provScheme.ProvisioningSchemeName -ProvisioningSchemeId $provScheme.ProvisioningSchemeUid

      # Associate a specific set of controllers to the provisioning scheme. This steps appears to be optional.
      Write-Verbose "Associating controllers $xdControllers to the provisioning scheme."
      Add-ProvSchemeControllerAddress -AdminAddress $adminAddress -ControllerAddress @($xdControllers) -ProvisioningSchemeName $provScheme.ProvisioningSchemeName

      # Provisiong the actual machines and map them to AD accounts, track the progress while this is happening
      Write-Verbose "Creating the machine accounts in AD."
      $adAccounts = New-AcctADAccount -AdminAddress $adminAddress -Count 5 -IdentityPoolUid $identPool.IdentityPoolUid
      Write-Verbose "Creating the virtual machines."
      $provTaskId = New-ProvVM -AdminAddress $adminAddress -ADAccountName @($adAccounts.SuccessfulAccounts) -ProvisioningSchemeName $provScheme.ProvisioningSchemeName -RunAsynchronously
      $provTask = Get-ProvTask -AdminAddress $adminAddress -TaskId $provTaskId

      Write-Verbose "Tracking progress of the machine creation task."
      $totalPercent = 0
      While ( $provTask.Active -eq $True ) {
        Try { $totalPercent = If ( $provTask.TaskProgress ) { $provTask.TaskProgress } Else {0} } Catch { }

        Write-Progress -Activity "Creating Virtual Machines:" -Status "$totalPercent% Complete:" -percentcomplete $totalPercent
        Sleep 15
        $ProvTask = Get-ProvTask -AdminAddress $adminAddress -TaskID $provTaskId
      }

      # Assign the newly created virtual machines to the machine catalog
      $provVMs = Get-ProvVM -AdminAddress $adminAddress -ProvisioningSchemeUid $provScheme.ProvisioningSchemeUid
      Write-Verbose "Assigning the virtual machines to the new machine catalog."
      ForEach ( $provVM in $provVMs ) {
        Write-Verbose "Locking VM $provVM.ADAccountName"
        Lock-ProvVM -AdminAddress $adminAddress -ProvisioningSchemeName $provScheme.ProvisioningSchemeName -Tag 'Brokered' -VMID @($provVM.VMId)
        Write-Verbose "Adding VM $provVM.ADAccountName"
        New-BrokerMachine -AdminAddress $adminAddress -CatalogUid $catalogUid.Uid -MachineName $provVM.ADAccountName
      }
      Write-Verbose "Machine catalog creation complete."

   } Else {
    # If provisioning task fails, provide error
    # Check that the hypervisor management and storage resources do no have errors. Run 'Test Connection', 'Test Resources' in Citrix Studio
    Write-Error "Provisioning task failed with error: [$provTask.TaskState] $provTask.TerminatingError"
   }
}

Comments or feedback on bugs, better ways to do things or additional steps is welcome.

Creative Commons LicenseCreating an MCS-based XenDesktop Machine Catalog with PowerShell is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2014 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

Creating a XenDesktop Delivery Group with PowerShell

$
0
0

My last article was on creating a XenDesktop machine catalog with PowerShell – in this article I’m going to create a Delivery Group which provides access to the virtual machines that a part of that catalog.

Like the last article, I’ve taken the PowerShell generated by Citrix Studio, banged my head against the wall a few times, and improved it to create the code presented in this article.

Linking the Code to the UI

To help explain the code, I’ll first run through the Create Delivery Group wizard and show how the code relates to options in the wizard and the Delivery Group properties.

Add-BrokerMachinesToDesktopGroup assigns virtual machines from a specified Machine Catalog to the new Delivery Group.

Selecting the Machine Catalog and the number of desktops - Add-BrokerMachinesToDesktopGroup -Catalog "Windows 8 x86" -Count 5

Selecting the Machine Catalog and the number of desktops – Add-BrokerMachinesToDesktopGroup -Catalog “Windows 8 x86″ -Count 5

Specify the delivery type for this Delivery Group when using New-BrokerDesktopGroup.

Selecting the delivery type - New-BrokerDesktopGroup  -DeliveryType 'DesktopsOnly'

Selecting the delivery type – New-BrokerDesktopGroup -DeliveryType ‘DesktopsOnly’

New-BrokerEntitlementPolicyRule is used to assign user or group accounts to the Delivery Group.

Assigning users to the Desktop Group - New-BrokerEntitlementPolicyRule -Name "Windows 8 x86_1" -IncludedUsers $brokerUsers -DesktopGroupUid 11

Assigning users to the Desktop Group – New-BrokerEntitlementPolicyRule -Name “Windows 8 x86_1″ -IncludedUsers “HOME\Domain Users” -DesktopGroupUid 11

Add-BrokerMachineConfiguration adds StoreFront and UPM configurations to a Delivery Group. The function just adds a machine configuration – the configuration is setup separately. To avoid selecting a StoreFront server for the Delivery Group, don’t use this function.

Selecting a StoreFront server - Add-BrokerMachineConfiguration -DesktopGroup "Windows 8 x86" -InputObject @(1005)

Selecting a StoreFront server – Add-BrokerMachineConfiguration -DesktopGroup “Windows 8 x86″ -InputObject @(1005)

When calling New-BrokerDesktopGroup, the Delivery Group name, display or published name and description is specified.

Group name, Display name and description - New-BrokerDesktopGroup -Name "Windows 8 x86" -PublishedName "Windows 8 x86" -Description "Windows 8 x86 with Office 2013, Pooled desktops"

Group name, Display name and description – New-BrokerDesktopGroup -Name “Windows 8 x86″ -PublishedName “Windows 8 x86″ -Description “Windows 8 x86 with Office 2013, Pooled desktops”

The wizard does not expose all settings for the Delivery Group, so additional settings require opening the properties of the new group. These can be set during creation of the group when using PowerShell.

The same call to New-BrokerDesktopGroup is used to specify user settings including colour depth and time zone preferences.

Controlling various user settings - New-BrokerDesktopGroup -ColorDepth TwentyFourBit -TimeZone "AUS Eastern Standard Time" -SecureIcaRequired $False

Controlling various user settings – New-BrokerDesktopGroup -ColorDepth TwentyFourBit -TimeZone “AUS Eastern Standard Time” -SecureIcaRequired $False

New-BrokerDesktopGroup and New-BrokerPowerTimeScheme are both used to manage virtual machine power management settings. Setting or modifying the peak and off peak hours isn’t friendly either.

Virtual machine power management settings - New-BrokerPowerTimeScheme -DisplayName 'Weekdays' -DaysOfWeek 'Weekdays' -DesktopGroupUid 11; New-BrokerDesktopGroup -OffPeakDisconnectAction Suspend -OffPeakDisconnectTimeout 15

Virtual machine power management settings – New-BrokerPowerTimeScheme -DisplayName ‘Weekdays’ -DaysOfWeek ‘Weekdays’ -DesktopGroupUid 11; New-BrokerDesktopGroup -OffPeakDisconnectAction Suspend -OffPeakDisconnectTimeout 15

New-BrokerAccessPolicyRule modifies the access policies. This is called twice – once for connections through NetScaler Gateway and once for direct connections.

Modifying access policies - New-BrokerAccessPolicyRule -Name "Windows 8 x86_AG" -AllowedConnections 'ViaAG' -AllowedProtocols @('HDX','RDP') -DesktopGroupUid 11 -Enabled $True -IncludedSmartAccessFilterEnabled $True -IncludedSmartAccessTags @() -IncludedUserFilterEnabled $True

Modifying access policies – New-BrokerAccessPolicyRule -Name “Windows 8 x86_AG” -AllowedConnections ‘ViaAG’ -AllowedProtocols @(‘HDX’,’RDP’) -DesktopGroupUid 11 -Enabled $True -IncludedSmartAccessFilterEnabled $True -IncludedSmartAccessTags @() -IncludedUserFilterEnabled $True

Creating the Delivery Group is relatively straight-forward; however there are some additional steps, such as creating a StoreFront server and working out how to manage peak and off peak times, that require a bit more investigation.

The Code

Below is the full code listing with comments inline that should provide some detail on the process the code follows. At this point the code provides some error checking for the most important steps. There are still some additional steps and error checking that could be integrated into the code.

#---------------------------------------------------------------------------
# Author: Aaron Parker
# Desc:   Using PowerShell to create a XenDesktop 7.x Delivery Group 
# Date:   Aug 23, 2014
# Site:   http://stealthpuppy.com
#---------------------------------------------------------------------------
# 

# Set variables for the target infrastructure
# ----------
$adminAddress = 'xd71.home.stealthpuppy.com' #The XD Controller we're going to execute against
$xdControllers = 'xd71.home.stealthpuppy.com'

# Desktop Group properties
$desktopGroupName = "Windows 8 desktops"
$desktopGroupPublishedName = "Windows 8 desktops"
$desktopGroupDesc = "Windows 8 x86 with Office 2013, Pooled desktops"
$colorDepth = 'TwentyFourBit'
$deliveryType = 'DesktopsOnly'
$desktopKind = 'Shared'
$sessionSupport = "SingleSession" #Also: MultiSession
$functionalLevel = 'L7'
$timeZone = 'AUS Eastern Standard Time'
$offPeakBuffer = 10
$peakBuffer = 10
$assignedGroup = "HOME\Domain Users"

#Machine Catalog
$machineCatalogName = "Windows 8 x86"
# ----------

# Change to SilentlyContinue to avoid verbose output
$VerbosePreference = "Continue"

# Create the Desktop Group
# http://support.citrix.com/proddocs/topic/citrix-broker-admin-v2-xd75/new-brokerdesktopgroup-xd75.html
If (!(Get-BrokerDesktopGroup -Name $desktopGroupName -ErrorAction SilentlyContinue)) {
    Write-Verbose "Creating new Desktop Group: $desktopGroupName"
    $desktopGroup = New-BrokerDesktopGroup -ErrorAction SilentlyContinue -AdminAddress $adminAddress -Name $desktopGroupName -DesktopKind $desktopKind -DeliveryType $deliveryType -Description $desktopGroupPublishedName -PublishedName $desktopGroupPublishedName  -MinimumFunctionalLevel $functionalLevel -ColorDepth $colorDepth -SessionSupport $sessionSupport -ShutdownDesktopsAfterUse $True -TimeZone $timeZone -InMaintenanceMode $False -IsRemotePC $False -OffPeakBufferSizePercent $offPeakBuffer -PeakBufferSizePercent $peakBuffer -SecureIcaRequired $False -TurnOnAddedMachine $False -OffPeakDisconnectAction Suspend -OffPeakDisconnectTimeout 15 -Scope @() 
}

# At this point, we have a Desktop Group, but no users or desktops assigned to it, no power management etc.
# Open the properties of the new Desktop Group to see what's missing.

# If creation of the desktop group was successful, continue modifying its properties
If ($desktopGroup) {

    # Add a machine configuration to the new desktop group; This line adds an existing StoreFront server to the desktop group
    # Where does Input Object 1005 come from?
    # http://support.citrix.com/proddocs/topic/citrix-broker-admin-v2-xd75/add-brokermachineconfiguration-xd75.html
    # Write-Verbose "Adding machine configuration to the Desktop Group: $desktopGroupName"
    # Add-BrokerMachineConfiguration -AdminAddress $adminAddress -DesktopGroup $desktopGroup -InputObject @(1005)

    # Add machines to the new desktop group. Uses the number of machines available in the target machine catalog
    # http://support.citrix.com/proddocs/topic/citrix-broker-admin-v2-xd75/add-brokermachinestodesktopgroup-xd75.html
    Write-Verbose "Getting details for the Machine Catalog: $machineCatalogName"
    $machineCatalog = Get-BrokerCatalog -AdminAddress $adminAddress -Name $machineCatalogName
    Write-Verbose "Adding $machineCatalog.UnassignedCount machines to the Desktop Group: $desktopGroupName"
    $machinesCount = Add-BrokerMachinesToDesktopGroup -AdminAddress $adminAddress -Catalog $machineCatalog -Count $machineCatalog.UnassignedCount -DesktopGroup $desktopGroup

    # Create a new broker user/group object if it doesn't already exist
    # http://support.citrix.com/proddocs/topic/citrix-broker-admin-v2-xd75/new-brokeruser-xd75.html
    Write-Verbose "Creating user/group object in the broker for $assignedGroup"
    If (!(Get-BrokerUser -AdminAddress $adminAddress -Name $assignedGroup -ErrorAction SilentlyContinue)) {
        $brokerUsers = New-BrokerUser -AdminAddress $adminAddress -Name $assignedGroup
    } Else {
        $brokerUsers = Get-BrokerUser -AdminAddress $adminAddress -Name $assignedGroup
    }

    # Create an entitlement policy for the new desktop group. Assigned users to the desktop group
    # First check that we have an entitlement name available. Increment until we do.
    $Num = 1
    Do {
        # http://support.citrix.com/proddocs/topic/citrix-broker-admin-v2-xd75/test-brokerentitlementpolicyrulenameavailable-xd75.html
        $Test = Test-BrokerEntitlementPolicyRuleNameAvailable -AdminAddress $adminAddress -Name @($desktopGroupName + "_" + $Num.ToString()) -ErrorAction SilentlyContinue
        If ($Test.Available -eq $False) { $Num = $Num + 1 }
    } While ($Test.Available -eq $False)
    #http://support.citrix.com/proddocs/topic/citrix-broker-admin-v2-xd75/new-brokerentitlementpolicyrule-xd75.html
    Write-Verbose "Assigning $brokerUsers.Name to Desktop Catalog: $machineCatalogName"
    $EntPolicyRule = New-BrokerEntitlementPolicyRule -AdminAddress $adminAddress  -Name ($desktopGroupName + "_" + $Num.ToString()) -IncludedUsers $brokerUsers -DesktopGroupUid $desktopGroup.Uid -Enabled $True -IncludedUserFilterEnabled $False

    # Check whether access rules exist and then create rules for direct access and via Access Gateway
    # http://support.citrix.com/proddocs/topic/citrix-broker-admin-v2-xd75/new-brokeraccesspolicyrule-xd75.html
    $accessPolicyRule = $desktopGroupName + "_Direct"
    If (Test-BrokerAccessPolicyRuleNameAvailable -AdminAddress $adminAddress -Name @($accessPolicyRule) -ErrorAction SilentlyContinue) {
        Write-Verbose "Allowing direct access rule to the Desktop Catalog: $machineCatalogName"
        New-BrokerAccessPolicyRule -AdminAddress $adminAddress -Name $accessPolicyRule  -IncludedUsers @($brokerUsers.Name) -AllowedConnections 'NotViaAG' -AllowedProtocols @('HDX','RDP') -AllowRestart $True -DesktopGroupUid $desktopGroup.Uid -Enabled $True -IncludedSmartAccessFilterEnabled $True -IncludedUserFilterEnabled $True
    } Else {
        Write-Error "Failed to add direct access rule $accessPolicyRule. It already exists."
    }
    $accessPolicyRule = $desktopGroupName + "_AG"
    If (Test-BrokerAccessPolicyRuleNameAvailable -AdminAddress $adminAddress -Name @($accessPolicyRule) -ErrorAction SilentlyContinue) {
        Write-Verbose "Allowing access via Access Gateway rule to the Desktop Catalog: $machineCatalogName"
        New-BrokerAccessPolicyRule -AdminAddress $adminAddress -Name $accessPolicyRule -IncludedUsers @($brokerUsers.Name) -AllowedConnections 'ViaAG' -AllowedProtocols @('HDX','RDP') -AllowRestart $True -DesktopGroupUid $desktopGroup.Uid -Enabled $True -IncludedSmartAccessFilterEnabled $True -IncludedSmartAccessTags @() -IncludedUserFilterEnabled $True
    } Else {
        Write-Error "Failed to add Access Gateway rule $accessPolicyRule. It already exists."
    }

    # Create weekday and weekend access rules
    # http://support.citrix.com/proddocs/topic/citrix-broker-admin-v2-xd75/new-brokerpowertimescheme-xd75.html
    $powerTimeScheme = "Windows 8 Pooled Desktop_Weekdays"
    If (Test-BrokerPowerTimeSchemeNameAvailable -AdminAddress $adminAddress -Name @($powerTimeScheme) -ErrorAction SilentlyContinue) {
        Write-Verbose "Adding new power scheme $powerTimeScheme"
        New-BrokerPowerTimeScheme -AdminAddress $adminAddress -DisplayName 'Weekdays' -Name $powerTimeScheme -DaysOfWeek 'Weekdays' -DesktopGroupUid $desktopGroup.Uid -PeakHours @($False,$False,$False,$False,$False,$False,$False,$True,$True,$True,$True,$True,$True,$True,$True,$True,$True,$True,$True,$False,$False,$False,$False,$False) -PoolSize @(0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0)
    } Else {
        Write-Error "Failed to add power scheme rule $powerTimeScheme. It already exists."
    }
    $powerTimeScheme = "Windows 8 Pooled Desktop_Weekend"
    If (Test-BrokerPowerTimeSchemeNameAvailable -AdminAddress $adminAddress -Name @($powerTimeScheme) -ErrorAction SilentlyContinue) {
        Write-Verbose "Adding new power scheme $powerTimeScheme"
        New-BrokerPowerTimeScheme -AdminAddress $adminAddress -DisplayName 'Weekend' -Name $powerTimeScheme -DaysOfWeek 'Weekend' -DesktopGroupUid $desktopGroup.Uid -PeakHours @($False,$False,$False,$False,$False,$False,$False,$True,$True,$True,$True,$True,$True,$True,$True,$True,$True,$True,$True,$False,$False,$False,$False,$False) -PoolSize @(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
    } Else {
        Write-Error "Failed to add power scheme rule $powerTimeScheme. It already exists."
    }

} #End If DesktopGroup

Comments or feedback on bugs, better ways to do things or additional steps is welcome.

Creative Commons LicenseCreating a XenDesktop Delivery Group with PowerShell is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2014 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

View Memory Stats on a Hyper-V Server

$
0
0

I’ve got a very simple setup in my home lab with a couple of machine running either Hyper-V or ESXi. I typically don’t have monitoring solutions running and manage each host directly, rather than part of a cluster or with SCVMM or vCenter. For Hyper-V, I try to manage it remotely via PowerShell as much as I can and so it’s handy to be able to see memory utilisation on the remote host to understand how much capacity I’ve got before powering on a VM. I’ve written a PowerShell function to return various memory stats:

  • Total RAM available in the host – using Get-VMHost.
  • Total memory in use by running VMs – by returning the running VMs and finding the current amount of RAM assigned to each VM with Get-VM. This works with dynamic memory.
  • Available memory to run additional VMs – using Get-Counter to gather the ‘\Memory\Available Bytes’ performance counter
  • How much memory is used by the system – this is calculated by adding what’s in use by VMs, to the available memory and subtracting the results from the physical RAM in the host. This is a rough calculation, but an interesting metric to view.

The function returns an array that includes each stat. Here’s an example of what the function returns. All values are in gigabytes and multiple hosts can be specified to gather details from.

PS C:\> Get-HvMem -ComputerName hv1


Name         : hv1
HostRAMGB    : 11.904224395752
VMInUseGB    : 7.12890625
SystemUsedGB : 1.46017837524414
AvailableGB  : 3.31513977050781

Here’s the code listing for the Get-HvMem function:

Function Get-HvMem {
    <#
        .SYNOPSIS
            Return Hyper-V host RAM details.
 
        .DESCRIPTION
            This function returns the total available RAM, RAM in use by VMs and the available RAM on a Hyper-V host.
 
        .PARAMETER ComputerName
            Specifies one or more Hyper-V hosts to retrieve stats from.
 
        .EXAMPLE
            Get-HvRAM -ComputerName hyperv1

        .NOTES
 
        .LINK
            http://stealthpuppy.com/hyperv-memory-powershell
 
    #>
    param(
        [Parameter(Mandatory=$true, Position=0,HelpMessage="Hyper-V host.")]
        [string[]]$ComputerName = $(throw = "Please specify a remote Hyper-V host to gather memory details from.")
    )

    # Create an array to return
    $allStats = @()

    ForEach ( $computer in $ComputerName ) {

        # Create an array to contain this computer's metrics
        $a = @()

        # Get details for Hyper-V host
        $vmHost = Get-VMHost -ComputerName $computer

        If ($vmHost) {

            # Get total RAM consumed by running VMs.
            $total = 0
            Get-VM -ComputerName $computer | Where-Object { $_.State -eq "Running" } | Select-Object Name, MemoryAssigned | ForEach-Object { $total = $total + $_.MemoryAssigned }

            #Get available RAM via performance counters
            $Bytes = Get-Counter -ComputerName $computer -Counter "\Memory\Available Bytes"

            # Convert values to GB
            $availGB = ($Bytes[0].CounterSamples.CookedValue / 1GB)
            $hostGB = ($vmhost.MemoryCapacity / 1GB)
            $vmInUse = ($total / 1GB)

            # Construct an array of properties to return
            $item = New-Object PSObject

            # Add host name
            $item | Add-Member -type NoteProperty -Name 'Name' -Value $vmHost.Name

            # Host RAM in GB
            $item | Add-Member -type NoteProperty -Name 'HostRAMGB' -Value $hostGB

            # In use RAM in GB
            $item | Add-Member -type NoteProperty -Name 'VMInUseGB' -Value $vmInUse

            # System used in GB
            $item | Add-Member -type NoteProperty -Name 'SystemUsedGB' -Value ($hostGB - ($vmInUse + $availGB))

            # Available RAM in GB
            $item | Add-Member -type NoteProperty -Name 'AvailableGB' -Value $availGB
            $a += $item    
        }

        # Add the current machine details to the array to return
        $allStats += $a
    }
    Return $allStats
}

Comments or feedback on bugs, better ways to do things or additional steps is welcome.

Creative Commons LicenseView Memory Stats on a Hyper-V Server is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2014 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

Configuring IIS Prerequisites for the App-V 5 Server with PowerShell

$
0
0
App-V Server 5.0 Setup with missing prerequisites

App-V Server 5.0 Setup with missing prerequisites

While I’d much rather recommend that you configure a Windows Server that will host the App-V 5.0 server components via a solution such as MDT with the required IIS components enabled in an automated build, here’s how to add the components with PowerShell.

The following code uses the Add-WindowsFeature to add the IIS components that are required to support the App-V 5.0 Management and Publishing Servers. These are the minimum required components as requested by the setup application.

# Import the ServerManager module which we will need to use the Add-WindowsFeature cmdlet
Import-Module ServerManager

# Add the required IIS features with the Add-WindowsFeature cmdletw 
$Features = Add-WindowsFeature –Name Web-Server,Web-Windows-Auth,Web-Mgmt-Tools,Web-ISAPI-Ext,Web-ISAPI-Filter,NET-Framework-45-ASPNET,Web-Asp-Net45,Web-Net-Ext45

# Report the results of adding the features
If ($Features.Success -eq $True) {
    If ($Features.RestartNeeded -eq $True) { 
        Write-Host -ForegroundColor Green "IIS features added successfully and reboot required."
    } Else {
        Write-Host -ForegroundColor Green "IIS features added successfully."
    }
} Else {
    Write-Error "Adding IIS features failed with error: $Features.ExitCode"
}

To keep an App-V 5.0 environment as simple as possible, you should be use port 80 for the Publishing Server. This ensures that the standard HTTP port is used for publishing and no-one has to remember or configure an obscure port on the App-V client.

As an added bonus, I’ve created some PowerShell code to change the IIS configuration to move an existing web site off port 80 to another port. In most cases that will be the Default Web Site.

The following code will find any web site currently bound to port 80, calculate the next available port by adding 1 to the highest port in use and then set the site to use that port.

# Import the WebAdministration module required for managing IIS
Import-Module WebAdministration

# Find whether any web sites are bound to port 80
$port80 = $false
Get-WebSite | ForEach-Object { If ($_.Bindings.Collection.bindingInformation -like "*:80:*") { $port80 = $True } }
If ( $port80 ) {

    # Find all bindings and add 1 to the highest binding to create a new port to bind the web site to
    $binds = @()
    Get-WebBinding | ForEach-Object { $binds += $_.bindingInformation.Split(":") }
    $binds = $binds | Sort-Object
    $port = ($binds[($binds.Count-1)] -as [int]) + 1

    # Change the web bindings for the site bound to port 80 to the new calculated port number
    Get-WebSite | ForEach-Object { If ($_.Bindings.Collection.bindingInformation -like "*:80:*") { Set-WebBinding -Name $_.Name -BindingInformation "*:80:" -PropertyName Port -Value $port } }
}

Once you’ve run the code, you can then install the App-V 5.0 server components and use port 80 for the Publishing Server.

Creative Commons LicenseConfiguring IIS Prerequisites for the App-V 5 Server with PowerShell is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2014 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.

Does Horizon View RDS stack up against XenApp?

$
0
0

Is VMware Horizon View 6 RDS a viable replacement or competitor to Citrix XenApp? A competitor, most certainly. View RDS as a replacement for XenApp deserves further investigation and I recommend no assumptions be made as to the suitability of View RDS, especially if you are a current Citrix customer, or a VMware partner.

One of the most interesting plays that VMware has with Horizon 6, is the ability to present resources through Horizon Workspace from Citrix XenApp. My initial knee jerk reaction was “why would you want to move from XenApp/XenDesktop to View?”, but it’s ultimately an excellent salvo in the fight to win customers away from Citrix.

This feature enables XenApp customers to implement View into existing environments and provide users with access to resources from XenApp and View from a single workspace. The aim is to create an on-ramp for the entire Horizon suite and ultimately a migration away from XenApp and/or XenDesktop.

Horizon View 6 RDS is really a first entry (or v2 depending on how you look at it) into published applications for VMware, so surely it can’t win in a head-to-head fight against XenApp? If you compare the two products in detail, what features of XenApp could you just not do without, or what features of View RDS would not be good enough?

I’ve put together a table in this article to compare features of XenApp and Horizon View RDS. This is not intended to be as feature complete or provide as much detail as the VDI Smackdown, instead I wanted to look at a handful of I what I see as the most important features and provide a quick a dirty reference.

There are a few things to keep in mind while reading this – a tick/star against a feature does not necessarily indicate that feature is directly comparable. Due to differences in approach and architecture, it’s very difficult to draw direct comparisons against some features.

I’ve added the VDI components of XenDesktop and View to provide reference.  The heading in the table “XenDesktop VDI” refers to the VDI features of XenDesktop, not the XenDesktop VDI edition. Any XenApp version between 6.5 and 7.6 should be applicable to this comparison.

This comparison is intended as a starting point for looking at both solutions. Your mileage will vary and I encourage performing your own due diligence. VMware has already improved View RDS with printing functionality within months of the original 6.0 release.

Feature Comparison

FeatureXenAppXenDesktop VDIView RDSHView VDI
Session Desktops. Multiple user sessions sharing a single Windows Server instance**
Published or Seamless Applications. Published applications delivered from Windows Server or client as seamless windows***
Virtual desktops. Single user sessions connecting to Windows desktop operating systems (8, 7 etc.)**
Supports physical deployments from the data centre - for hosted shared servers or hosted desktops****
Remote PC access. Provide users with remote access to their physical PCs using the same virtual desktop infrastructure**
Single image management through OS streaming**
Single image management via linked-clones***
Hypervisor-based vDisk solution to provide a persistent storage space for virtual desktops**
Client-side virtualization, syncronisation or physical desktop image managementXenClient (client-side hypervisor); DesktopPlayer for MacMirage (layering and sync); VMware Player
Hypervisor supportESXi, Hyper-V, XenServerESXi, Hyper-V, XenServerESXiESXi
Gateway / remote accessNetScaler Gateway (2 nodes for HA)NetScaler Gateway (2 nodes for HA)View Security Server (2 nodes plus load balancer for HAView Security Server (2 nodes plus load balancer for HA
Clientless access with HTML 5 browser support***
Load BalancingNetScalerNetScalerNSXNSX
WAN optimizationCloud BridgeCloud Bridge3rd party3rd party
2D and 3D graphics acceleration - software/CPU****
2D and 3D graphics acceleration - bare metal****
2D and 3D graphics acceleration - pass-through / vDGA****
2D and 3D graphics acceleration - vGPU**
2D and 3D graphics acceleration - vSGA (vSphere only)****
Flash redirection. May be client and OS dependant**~ (requires web page change)~ (requires web page change)
Multimedia redirection. May be client and OS dependant**?*
Microsoft Lync optimization to reduce latency with local voice and video processing****
Real-Time Audio-Video support for webcams and microphones***
USB redirection. Low level redirection of USB devices from client to virtual desktop~ (limited devices)*?*
Webcam support. Client webcam accessed from remote desktop or application***
Microphone support. Client microphone access from remote desktop or application***
Local client drive connection. Client drive mapping over a virtual channel**
Printer redirection/virtual printers****
Driver-less printing with server component to support network printing**
Location-based / Proximity printing. E.g. based on client subnet***
Smart card authentication***
Profile management or optimization***
Direct application virtualization integrationApp-VApp-VThinAppThinApp
Application compatibility testing and migration toolsAppDNAAppDNA
Microsoft System Center integration**
Monitoring solutionXenDesktop Director, EdgeSightXenDesktop Director, EdgeSightVMware vCOPsVMware vCOPs

Here’s a set of additional XenApp and XenDesktop features that I’ll move into the table as time permits. In the meantime some of them are significant features that can’t be taken for granted.

  • Session Pre-launch – improve the perceived time to launch remote applications
  • Session Linger – keep a remote session open for a period of time after closing all remote applications
  • Anonymous Logon – allow access to remote applications without requiring authentication
  • Advanced Policy Control and SmartAccess – Citrix has provided a flexible access control and policy solution within XenApp and XenDesktop, especially in conjunction with NetScaler
  • User shadowing – remote controlling user sessions for support purposes
  • Hypervisor-based read cache (IntelliCache, CSV Cache, CBRC) – how do these features fit into your storage requirements?

I’ve made every effort to ensure this comparison is accurate at the time of posting; however this is subject to change and I’ll update as new information comes to light.

So, is Horizon View RDS ready to go head-to-head with XenApp? I have my own view, tempered by many years of working with Citrix products, but it’s great to see VMware taking a seat at the application delivering table. Whether Horizon View RDS wins out over XenApp, will of course depend on your own business and technical requirements.

Acknowledgements

I’d like to thank the following people (in no particular order) for taking a look at the table and providing some initial feedback:

Comments and feedback, as always, are welcome.

Updates

  • Oct 1. 2014 – removed HTML5 clientless support check mark from Horizon View RDS
  • Oct 27. 2014 – added NSX to load balancing option for Horizon View

Creative Commons LicenseDoes Horizon View RDS stack up against XenApp? is post from stealthpuppy.com. Except as noted otherwise, this work is © 2005-2014 Aaron Parker and is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.
Viewing all 177 articles
Browse latest View live