Monthly Archives: September 2011

Quickly delete and re-stream an App-V application with Powershell

I get this problem quite a bit in our environment so threw together a quick Powershell script.

A tech will add revision after revision to an App-V package in the development lifecycle, but when it goes live to production the revisions are so far apart the application rarely works using the cached version even after an sfttray /loadall.

Here’s a quick Powershell script to cleanly remove and read an application:

The usage is below:

update-appvpackage -path "servercontentshare" -package "packagename"

This script assumes you use the best practices on your content share. .e.g. contentshareappnameappname_manifest.xml. If you don’t use this practice, this script wont work for you.

function update-appvpackage{
    param(
        [string]$path,
        [string]$packagename)

    if (test-path $path$packagename){
            pushd $path
            write-host "deleting $packagename"
            start-process -wait sftmime.exe -argumentlist "delete package:$packagename /global"
            write-host "Re-Adding $packagename"
            start-process -wait sftmime.exe -argumentlist "add package:$packagename /manifest .$packagename$packagename`_manifest.xml /global"
            write-host "Loading $packagename"
            start-process -wait sftmime.exe -argumentlist "load package:$packagename"
            popd
          }#end path if
     Else {
        write-warning "package directory / path not found"}
}#end function

Powershell Script to add all applications to a RES Workspace Container.

As Part of a recent Proof of concept, I needed to move all of my applications from one workspace to another. With 50 + applications in just the proof of concept environment, the idea of opening each and modifying them individually did not excite me.

Upon starting my investigation, I found an interesting article by the PepperCrew’s @IngmarVerheij where he exported all building blocks, then used a find and replace command to add the workspace to the application, then added all building blocks back in again.

This approach worked great for his implementation, but I wanted to further automate my process while giving me the ability to amend a workspace without removing any currently configured workspaces.

My search continued to the following article on the RESGURU Blog, Where the RESGURU has kindly documented the usage of Powertech to automate (Certain) commands in the powerfuse / Workspace manager world. Sadly as they document, exporting from the database is not currently supported, but there was a glimmer of hope, they do support importing building blocks… result!

So the first task is to create your workspace and add one application to it, in my case I used notepad:

Next step is to export all applications to building blocks, this can be done easily by simply right clicking start icon and choosing building blocks > create…

Choose the directory you wish to work from (I Chose c:temp) and click ok, I’ll later refer to this directory as your “scratch directory”.

Step three is to find the GUID of the workspace you wish to add all your applications to. Of the building blocks you’ve exported, find the application you added to the workspace. The workspaceGUID can be found as below, take a copy of this value for later:

Now that you have all the building blocks and the guid, the fun can begin!

Below you will find the automated script to add a workspace to each xml file, then load them back into workspace manager using the powertech.exe command line interface. Below is a quick screen shot of how it looks:

Although I’ve written this for Applications, this could just as easily work for printers, user registry, anything so long as you ammend the XML path correctly. If you do have a requirement for other components or building blocks, drop me a commend and I’ll see what I can do.

Two Values will need to amended for this script to work in your environment, I’ve highlighted them bold in the script

  • The workspace GUID
  • the scratch directory
$WorkspaceGUID="{D3DC6EFF-BA8C-4A8A-A6DC-C5039DCC9F46}"
$scratchdirectory="c:temp*.xml"

foreach ($process in (gwmi win32_process | where {$_.name -eq "pwrtech.exe"})){
    $owner = ($process.getowner()).user
    if ($owner -eq "$env:username") {
        Write-warning "pwrtech.exe is currently running in your session and can cause issues, close it now, I'll wait 20 seconds."
        start-sleep 20
    }#end if
}#end for

$blocks = get-childitem $scratchdirectory
foreach ($block in $blocks) {
 $i++
 Write-Progress -activity "Adding Workspace to Applications and importing the building blocks:" -status "Currently working on: $($Block.name)  ($i of $($blocks.length))" -PercentComplete (($i / $blocks.length) * 100)

   [xml]$XMLBlock = get-content $block.fullname

    if (!($XMLBlock.respowerfuse.buildingblock.application.workspacecontrol)){
        #did not find a reference to Workspace Control,
        #write-host "Adding Workspacecontrol and Workspace element to $block"
        $workspacecontrolelement = $XMLBlock.CreateElement("workspacecontrol")

        #create individual workspace entry
        $WorkspaceElement = $XMLBlock.CreateElement("workspace")
        $WorkspaceElement.psbase.innertext=$WorkspaceGUID

        #append both elements
        $workspacecontrolelement.appendchild($WorkspaceElement) | out-null

        #append elements to xml
        $XMLBlock.respowerfuse.buildingblock.application.appendchild($workspacecontrolelement)  | out-null

        #saving XML file:
        $XMLBlock.save($block.fullname)

        #committing to database
        start-process "C:Program Files (x86)RES SoftwareWorkspace Managerpwrtech.exe" -wait -argumentlist "/add /overwrite ""$($block.fullname)"""
    }#end IF
    Else{
        #Found a reference of workspace control, checking if our building block already contains the workspace we wish to add:
        if ($XMLBlock.respowerfuse.buildingblock.application.workspacecontrol.workspace -notcontains $WorkspaceGUID){
            #create a new workspace element to add to a current workspace control element
            #write-host "appending workspace in $block"
            $WorkspaceElement = $XMLBlock.CreateElement("workspace")
            $WorkspaceElement.psbase.innertext=$WorkspaceGUID
            $XMLBlock.respowerfuse.buildingblock.application.workspacecontrol.appendchild($WorkspaceElement) | out-null
            #saving XML file:
            $XMLBlock.save($block.fullname)

            #committing to database
            start-process "C:Program Files (x86)RES SoftwareWorkspace Managerpwrtech.exe" -wait -argumentlist "/add /overwrite ""$($block.fullname)"""        
         }#end If
        Else {
            Write-warning "$block contains this workspace container already, skipping."
        }#end else
    }#end Else

}#end for

Remove Citrix Web Interface 5.4 IIS recycling via a script.

Ever notice that the first login to the web interface in the morning takes quite some time? This is because the citrix application pool in IIS is, by default, set to recycle nightly at 02:00. After the recycle the web-interface is rebuilt causing a delay to the first user to attempt to log in.

This delay can result in users logging tickets for a slow login process. For this reason I like to disable this value where I can.

It’s always irked me that with previous versions of IIS, this pool recycling was unavailable for scripting (at least to my meager brain) via wmi, regedit or other method.

During my XenApp 6.0 testing i noted that with IIS 7, there’s now a powershell module you can import to tackle this value.

To remove the default 02:00 recycle from the Citrix 5.4 web interface pool, use the below script:

Please note, this will set your powershell execution policy to unrestricted, this is a side affect of the WebAdministration calling a script. To revert at the end of the script, run the following command after utilizing this script “set-executionpolicy restricted”

if (!(get-module | where {$_.name -eq "webadministration"})){

    if (!(get-module -listavailable | where {$_.name -eq "webadministration"})){
    write-error "WebAdministration snapin not available, failing"
    break}

    #this is needed as the module is seen as a script in some cases
    set-executionpolicy unrestricted -force

    #add the module
    write-host "adding IIS Powershell Module"
    import-module webadministration    
}#end if

$CitrixPool = get-childitem "IIS:AppPools" | where {$_.name -eq "CitrixWebInterface5.4.0AppPool"}

$schedulePath = $CitrixPool.ItemXPath + "/recycling/periodicRestart"

$count = $CitrixPool.recycling.periodicRestart.schedule.Collection.Count

#remove scheduled time(s)
Do {
   Remove-WebconfigurationProperty $schedulePath -Name schedule.collection -AtIndex ($count - 1) -Force
   $count--
}

Until ($count -eq "0")

Strange “Recent Places” issue in windows 7 / Server 2008 R2.

Just a quick post about a funny little issue I saw recently.

First to give some background on this wonderful little folder. The recent places folder you see in the windows explorer Favorites menu is a collaboration of all the folders you have saved to recently. Windows compiles this folder view by first looking at your “Recent Files” in %userprofile%AppDataRoamingMicrosoftWindowsRecent and then filtering the results by directory. Leaving you with a view of all the folders you have worked in recently.

In my case, when using mandatory profiles in Server 2008 R2 and Windows 7, the Recent Places Folder in windows Explorer is spelled incorrectly. Instead of being “Recent Places”, it’s listed as “RecentPlaces” without the space.

When this issue occurs, the folder will correctly list the folders you have recently worked in, but the name will be incorrect for the duration of your session.

This will occur if active setup has not run on your profile, or as part of your profile creation. It seems despite following the Microsoft guide to the letter, active setup still needs to run on a Mandatory profile each time a user logs in…

The individual component of active setup responsible for many things including this profile adjustment is {89820200-ECBD-11cf-8B85-00AA005B4340} found in these registry locations:

HKEY_LOCAL_MACHINESOFTWAREMicrosoftActive SetupInstalled Components
HKEY_LOCAL_MACHINESOFTWAREWow6432NodeMicrosoftActive SetupInstalled Components

This active setup component run’s the following command:

C:WindowsSystem32regsvr32.exe /s /n /i:U shell32.dll

To fix the issue, reinstate the active setup keys you wrongfully deleted (bad admin) or run the above command.

Once you’ve done this the folder will be displayed correctly.

For a great explanation of Active setup, check out Helge’s write up over here.

If you still hate active setup (like I do) the above command can be run on  as part of a login script or better yet as part of a RES Workspace Manager “Execute Command” without the annoying active setup pause. This will then fix this issue each login before the user see’s it.

This command is actually really useful to be aware of and I’ll blog about this a little later in the week about some other applications of this seemingly routine command.

Unique portgroup fiddling with #Powercli.

As my peers seem to like to flout convention, particularly naming conventions. I was left with a strange automation challenge this week.

with a new service coming online in my company, I had 12 vlan portgroups to add to over 30 ESXi machines. Simple you say, just pipe your hosts into a new virtualswitch query then into a new virtual port group command.

Did i mention the virtual switch has a different name per host? Its vswitch0 on some, vswitch1 on others, and even vswitch2 on one.Arse.

after a few hours of various queries, below is the little scripty I was left with. I did consider putting this into a function, but I didnt know where to begin when it came to a name…

add-PortGroupInSwitchWhereOtherPortGroupExists? … bleh.

Below the variables are pretty self explanatory and it works flawlessly. Remember to install the powercli commands, import the module and connect to the vi server first!

#Variables
 $findportgroupname="GWA4"
 $NewPortGroupName="Citrix7"
 $NewPortGroupVlanId="306"

foreach ($portgroup in get-virtualportgroup | where {$_.name -eq $findportgroupname}){
 get-vmhost -id $portgroup.vmhostid |
  get-virtualswitch -name $portgroup.virtualswitchname |
   new-virtualportgroup -name $NewPortGroupName -Vlanid $NewPortGroupVlanId
 }