Wednesday, February 29, 2012

Issue with Folder Redirection (Error %%267)

So we were having an issue with Folder Redirection today with a user. We were moving them from a fileshare to a UNC path. The difference is a file share is explicitly shared, the userdirs$ is a share that then has a folder within.

This was the error in fdeploy.log (enabled here).

16:32:10:116 Homedir redirection path %HOMESHARE%%HOMEPATH% expanded to \\newserver\userdirs$\user1.
16:32:10:116 Redirecting folder My Documents to \\%HOMESHARE%%HOMEPATH%.
16:32:10:116 Previous folder path \\oldserver\user1$ expanded to \\oldserver\user1$.
16:32:10:116 New folder path \\%HOMESHARE%%HOMEPATH% expanded to \\newserver\userdirs$\user1.
16:32:11:007 Failed to perform redirection of folder My Documents.
The folder is configured to be redirected from <\\oldserver\user1$> to <\\newserver\userdirs$\user1>.
The following error occurred:

%%267. After some brief investigation it was found this users had a huge My Docs and it was copied to the new server. The old directory was then renamed (user1.old) and a new directory was created called user1 and reshared as user1$ on the old server. Then this issue occurred. The reason this issue occurred was because the user wasn't assigned any permissions on the old directory so it was erroring out. I don't know if %%267 is a permission code or not but that's what we found. By adding the user to the folder \\oldserver\user1$ as full control did it then proceed and migrate his My Docs correctly.

Thursday, February 16, 2012

Registry keys needed to set a default server Exchange server for Outlook

We recently upgraded our Exchange infrastructure from 2007 to 2010. During this we changed the host name of the server from an internal name to a nice, easy to remember one ( But, we did not update our Outlook's defaults to this server, so when you open Outlook for the first time you are presented with this message:

Microsoft Exchange is unavailable.

With the options:
Retry, Work Offline, and Cancel. If you choose Work Offline you are given this error message:

Microsoft Office Outlook
Outlook cannot log on. Verify you are connected to the network and are using the proper server and mailbox name. The connection to Microsoft Exchange is unavailable. Outlook must be online or connected to complete this action.

then the opportunity to enter the server name to connect to:

If you correct the name here you will get an error where you can close Outlook then reopen it for it to operate. Another option is to change the default of that server to the correct one. I figured out the registry keys to do those so you can place in a GPO object.

Here are the keys:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\ttye\8fa3465791d2b746a2c7d11ca063b282]

[HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\ttye\406169da1432914e8075fa26cbcdc53a]

[HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\ttye\1e8559cf990bb44792093b0cdfca0186]

[HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\ttye\13dbb0c8aa05101a9bb000aa002fc45a]

[HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\ttye\dca740c8c042101ab4b908002b2fe182]

The last key is a REG_BINARY of the server name ( If we make this into a GPO object then these keys can be placed in and users can connect to Exchange without the messages above.

The GPO object needs to look like so:

Notice the %LogonUser% variable.

Each "Key Path" requires your username substituted for the %LogonUser% variable as well:

Set this GPO with a loopback processing setting and you're rolling. The negative that I've seen with this approach is that it will set the registry keys on a new login, but launching Outlook for the first time will overwrite them with the defaults set in the PRF. If you cancel out and relaunch the registry keys will apply again and the server you specified in them will work.

Or you can setup a DNS Alias, but this was an interesting exercise anyways :)

Wednesday, February 15, 2012

Purposeful limitations

I have a Citrix environment without a provisioning server. This means that since I'm going to build my VM's out as opposed to up I need to script a method to automate deployment of Citrix servers within the VM environment. Fortunately, VMWare gives us the PowerCLI. A PowerShell that you can use to manipulate VMWare.

While I was working on this I ran into some some weird issues while working with VMWare and deploying OS Customizations.

It turns out if you burn your 3 activations VMWare cannot customize the OS anymore from VMWare. BUT(!) there is a dirty little trick that works for Server 2008 R2 (only one I've tested anyhow) that can allow you to work around the issue. The issue is VMWare's OS Customizations does a Generalize pass using Sysprep. If you exceed the 3 activations, sysprep will fail because it will notice this at the Generalize pass. The solution that I've read is to add this line to the sysprep.xml file:


Unfortunately, VMWare does not appear to have a way to allow you to add the SkipRearm to the XML that it generates through the OS Customization GUI. But you can add a couple of registry keys that appear to have the same effect. They are:

REG ADD "HKEY_LOCAL_MACHINE\SYSTEM\Setup\Status\SysprepStatus" /v "GeneralizationState" /t REG_DWORD /d 0x7 /f"
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform" /v "SkipRearm" /t REG_DWORD /d 0x1 /f"

These two keys will signal to sysprep that this image can be generalized even though it has exceeded its activation count.

So, what I've found is you need to set these registry keys *prior* to shutting it down to convert into a template. Then when you deploy from template and it starts up and engages sysprep, sysprep will run without issue.

So how do you put this all together? Here is my scenario:
We do NOT have a golden image template of our Citrix environment. This is because it is incredibly fluid. Changes occur to applications on the servers fairly regularly and documentation/memory is difficult to ensure that when we commit to putting these changes into the template that they are actually done. So how are we going to do this? We are going to take a 3 prong approach:
1) We have a dev environment where developers can modify/change and generally mess up their VM's to their hearts content. The whole goal of this environment is to get their application working at 100%. The developers do not need to answer to anyone and have free reign to modify and experiment.
2) We have a test environment where, when the developers think the application is tweaked/modified/configured exactly right; will pass off documentation to me to install in this environment. Any errors or modifications that happen outside of their documentation will be further documented and verified.
3) Once step two is validated we can then push on to install on the production servers.

The issues we encounter is some of our application installs are huge, multi-step non-automated processes with large configuration tweaks post install. Once we get a solid install on one of the production servers our perferred method of redployment (because I've automated this process thus eliminating possible failure points) will be to template and redeploy with VMWare. This is the script I've written to accomplish this:

function Clone-List{

HelpMessage="Insert Message")]
HelpMessage="Insert Preferred Folder")]
HelpMessage="Insert Preferred Target Datastore")]
HelpMessage="Insert Preferred Target Host")]
HelpMessage="Insert Preferred Disk Storage Format")]
$format = "Thin"

$InputObject | %{
$vm = Get-VM $_
$name = $
$newname = -join("clone-",$name)
$templatename = -join("template-",$name)
If ($datastore -eq $null){
$datastore = Get-Datastore -VM $vm
If ($folder -eq $null){
$folder = $vm.Folder
If ($vmhost -eq $null){
$vmhost = Get-Cluster -VM $vm | Get-VMHost | Get-Random | Where{$_ -ne $null}
Write-Host "VM = $vm"
Write-Host "Name = $name"
Write-Host "NewName = $newname"
Write-Host "DataStore = $datastore"
Write-Host "Folder = $folder"
Write-Host "VMHost = $vmhost"

Write-Host "Setting up domain unjoin script..."
Remove-Item "\\$name\c$\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\remove.cmd"
Add-Content "\\$name\c$\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\remove.cmd" "netdom remove $name /Force"
Add-Content "\\$name\c$\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\remove.cmd" "netdom renamecomputer $name /newname:XA6TEMPLATE /Force"
Add-Content "\\$name\c$\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\remove.cmd" "REG ADD `"HKEY_LOCAL_MACHINE\SYSTEM\Setup\Status\SysprepStatus`" /v `"GeneralizationState`" /t REG_DWORD /d 0x7 /f"
Add-Content "\\$name\c$\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\remove.cmd" "REG ADD `"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform`" /v `"SkipRearm`" /t REG_DWORD /d 0x1 /f"
Add-Content "\\$name\c$\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\remove.cmd" "shutdown -s -t 20 -f"
Add-Content "\\$name\c$\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\remove.cmd" "del /q `"c:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\remove.cmd"
Write-Host "Setting Autologon..."
REG ADD "\\$name\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v "DefaultUserName" /d Administrator /f
REG ADD "\\$name\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v "DefaultPassword" /d 'password123' /f
REG ADD "\\$name\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v "AutoAdminLogon" /t REG_DWORD /d 0x5 /F
REG ADD "\\$name\HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" /v "AutoLogonCount" /t REG_DWORD /d 0x1 /F

Write-Host "Preparing XenApp for Cloning..."
psexec \\$name "C:\Program Files (x86)\Citrix\XenApp\ServerConfig\XenAppConfigConsole.exe" /ExecutionMode:ImagePrep /PrepMsmq:True

Write-Host "Cloning"
New-VM -Name $newname -VM $vm -Location $folder -Datastore $datastore -VMHost $vmhost -DiskStorageFormat $format
Write-Host "Unplugging NIC..."
get-VM $newname | get-networkadapter | set-networkadapter -startconnected:$false -confirm:$false
Write-Host "Starting VM..."
start-vm $newname

Write-Host "Powering on clone..."

REG ADD "\\$name\HKLM\SYSTEM\Setup\Status\SysprepStatus" /v "GeneralizationState" /t REG_DWORD /d 0x3 /f
Remove-Item "\\$name\c$\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\remove.cmd"
REG DELETE "\\$name\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v "DefaultUserName" /f
REG DELETE "\\$name\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v "DefaultPassword" /f
REG DELETE "\\$name\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v "AutoAdminLogon" /f
REG DELETE "\\$name\HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" /v "AutoLogonCount" /f

Write-Host "We need to wait until the clone is powered off before we can template it..."

do {
sleep 1.0
Write "Waiting for shutdown of VMs"
} until (Get-VM $newname | Where { $_.PowerState -eq "poweredOff" })
write-host "System is powered on"

Write-Host "Creating NIC..."
get-VM $newname | get-networkadapter | set-networkadapter -startconnected:$true -confirm:$false
Write-Host "Removing any stale template-VM's"
remove-template $templatename -confirm:$false
Write-Host "Creating Template VM from clone"
new-template -VM $newname -name $templatename -Location $folder
Write-Host "Removing Clone VM"
remove-vm $newname -DeletePermanently -confirm:$false

Write-Host "Setting up OS customization"
$cs = Get-OSCustomizationSpec PowerCLI
Set-OSCustomizationSpec -OSCustomizationSpec PowerCLI -ChangeSID:$true -Domain CCS.CORP -DomainUsername admin-ttye -DomainPassword password123 -NamingScheme Fixed -NamingPrefix CDCVXAP03P
new-vm -VMHost (Get-Cluster -VM $vm | Get-VMHost | Get-Random | Where{$_ -ne $null}) -name CDCVXAP03P -Template template-CDCVXAP02P -Datastore $datastore -OSCustomizationSpec $cs
get-VM CDCVXAP03P | get-networkadapter | set-networkadapter -startconnected:$true -confirm:$false


I've shamelessly stolen and modified this script from elsewhere. To execute this script, copy and paste it in a PowerGUI prompt then run:

get-vm CDCVXAP02P | Clone-List

It will execute the following:
1) Pull the following parameters from the target VM to reclone:
The VM Object
The VM Objects Name
The New Name for the temp clone
A Template Name
The Datastore the VM resides on
The folder the VM resides in
And the VM Host
2) We then copy a script to our target machine that does the following:
Removes the machine from the domain
Renames the machine
Prepares the addition of our two Sysprep registry key fixes
Prepares a 20 second count down
Deletes the script that executes step 2.
3) We add the default username and password and autologon registry values. As of this writting this is not working for some reason
4) We execute the command that preps the machine for cloning with Citrix. The machine you run this against will need to be rebooted as this will prevent new logons, but existing should continue (I think).
5) We start the cloning process and unplug the NIC on the new machine. We don't want the new machine to come up and unjoin the original machine from the domain. From here, it will auto-power on. Ideally, it will login automatically and run the preconfigured script. (You may have to login manually to get it to do its thing) Once done it should shut itself down.
6) Now VMWare will wait until the machine is powered off. Once it's powered off it will reconnect the NIC and make a template out of the VM and delete the temporary clone.
7) Lastly it will now setup the OS Customization dynmically and create a VM with it.