Extracting files from an .APPV file with PowerShell

Whilst doing a lot of work with App-V 5.0 we have come across the requirement to look inside the .appv file with PowerShell. In our particular instance we’re after the package VersionId which is contained in the AppxManifest.xml file. As previously championed, we love automating and this should be easy!

The .appv file extension is a compressed archive and therefore, should be simple to crack open. After scouring the interweb, there is very little information on how to achieve this in code. We could use the built-in Shell32.dll functionality but this requires us to rename the file to .zip first. Ideally we want to avoid copying or renaming the source files. I did find one reference over on the Login Consultants forum which pointed me in the right direction.

Disclaimer: the following code requires the .Net Framework 4.5. The System.IO.Compression.FileSystem object is not available in previous releases. You can check in the C:\Windows\Microsoft.NET\assembly\GAC_MSIL\ folder and if you have the System.IO.Compression.FileSystem folder you should be good to go Smile with tongue out.

To get this new .Net functionality to work within PowerShell we will be calling the .Net assemblies directly and therefore need to create a couple of references. In our example we’ll be using both the System.IO.Compression and System.IO.Compression.FileSystem assemblies (two different DLLs hence the two references):

[code]### The System.IO.Compression.FileSystem requires at least .Net Framework 4.5
[System.Reflection.Assembly]::LoadWithPartialName(“System.IO.Compression”) | Out-Null;
[System.Reflection.Assembly]::LoadWithPartialName(“System.IO.Compression.FileSystem”) | Out-Null;[/code]

Next we can create our FileStream object (with read only access) required by the ZipArchive object class.

[code]### Open the ZipArchive with read access
$FileStream = New-Object System.IO.FileStream($SourceAppV5Archive, [System.IO.FileMode]::Open);
$AppV5Archive = New-Object System.IO.Compression.ZipArchive($FileStream);[/code]

In fact we can shorten this down to a single line:

[code]### Open the ZipArchive with read access
$AppV5Archive = New-Object System.IO.Compression.ZipArchive(New-Object System.IO.FileStream($SourceAppV, [System.IO.FileMode]::Open));[/code]

Once we have opened our .ZIP (.appv) file we can retrieve the AppXManifest.xml file entry:

[code]### Locate the AppxManifest.xml file
$AppxManifestEntry = $AppV5Archive.GetEntry(“AppxManifest.xml”);[/code]

Having the ZipArchiveEntry object we can extract it with the ExtractToFile method:

[code]### Extract the $ZipArchiveEntry
$ZipArchiveEntry.ExtractToFile($SaveAs);[/code]

Unfortunately this does work and reports the following error:

[code]Method invocation failed because [System.IO.Compression.ZipArchiveEntry] doesn’t contain a method named ‘ExtractToFile’.[/code]

Eh!? WT… Looking on the ZipArchiveEntry reference page on MSDN, the ExtractToFile is an Extension Method. Therefore, we need to utilise the underlying object method, the ZipFileExtensions.ExtractToFile method. For more information on Extension Methods in PowerShell see here and here. Now our code should look like this:

[code]### Extract the ZipArchiveEntry (ZipArchiveEntry.ExtractToFile is an extension method)
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($AppxManifestEntry, $SaveAs, $Overwrite);[/code]

Finally we need to ensure that we correctly dispose of the ZipArchive object otherwise we’ll leave it open:

[code]### Ensure we close the file handle otherwise the file will be left open
$AppV5Archive.Dispose();[/code]

That’s it! It you want a simpler way of doing this, just download the Virtual Engine App-V 5.0 Package PowerShell CmdLets. You can achieve all this in just a single command:

[code]Save-AppV5FileXml -AppV c:\package.appv -XML AppxManifest[/code]

Full PowerShell Code Snippet

Here is the full code listing:

[code]### The System.IO.Compression.FileSystem requires at least .Net Framework 4.5
[System.Reflection.Assembly]::LoadWithPartialName(“System.IO.Compression”) | Out-Null;
[System.Reflection.Assembly]::LoadWithPartialName(“System.IO.Compression.FileSystem”) | Out-Null;

### Open the ZipArchive with read access
$AppV5Archive = New-Object System.IO.Compression.ZipArchive(New-Object System.IO.FileStream($SourceAppV5Archive, [System.IO.FileMode]::Open));

### Locate the AppxManifest.xml file
$AppxManifestEntry = $AppV5Archive.GetEntry(“AppxManifest.xml”);
### ZipArchiveEntry.ExtractToFile is an extension method
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($AppxManifestEntry, $SaveAs, $true);

### Ensure we close the file handle otherwise the file will be left open
$AppV5Archive.Dispose();[/code]

VET v1.3 Released!

Virtual Engine are pleased to announce the general availability of version 1.3 of the Virtual Engine Toolkit (VET). The latest Windows installer and documentation is available for download now on the Virtual Engine web site. New in this release is the addition of the WSUS Integration Management Pack (WiMP).

There’s no “What’s New” video this time but to view existing videos on the Virtual Engine Toolkit, please check out our YouTube channel.

VET v1.2 Group Policy Import Bug

This post is just a heads-up on some errors we’ve seen importing Group Policy Objects into RES Workspace Manager with the latest Virtual Engine Toolkit v1.2 release. In version v1.2 we introduced the ability to convert GPO permissions and OU links. To achieve this we needed to alter the way in which we enumerated the Group Policy Objects present within the source Active Directory domain.

VET v1.2 directly scans the SYSVOL volume (this approach has changed in VET v2.0). Unfortunately, if there is an errant folder that persists in the SYSVOL (but is no longer present in Active Directory) this error is not correctly trapped. The net result is a spectacular .NET exception error!

Internally we have code that fixes this issue, but it’ll be a few days before @nathan_sperry has digitally signed the new executable and built a new MSI installer. When this update is available, you will receive an update notification informing you that there’s an update available.

SNAGHTML2c21ba

In the meantime, if you receive a crash when importing GPOs, you’ll need to track down the errant policy folder and either delete the redundant GPO folder or remove the \USER\registry.pol or \MACHINE\registry.pol file.

Whilst the VET v1.3 is primarily a bug fix we are introducing something completely new, e.g. it’s nothing to do with VET, PuU, JET or JETCMD. It’s something we have been using internally and at customers for a long time. Stay tuned for more information…

Virtual Engine Receives RES Recognition

Virtual Engine are honoured to have been highlighted by RES Software in their 5 year milestone of the RES Software Valued Professional programme. Having two RSVP members is in itself a privilege, but to have received recognition for our efforts with the Virtual Engine Toolkit is also important to us.

Needless to say we are already working on the next major version of VET which incorporates a complete overhaul of the user interface. Thank you to Bob de K and the RES team for publically recognising the time and effort we contribute to the community.

The Anywhere Home Drive

I thought I’d put pen to paper to discuss a topic that was raised during the most recent UK Citrix User Group meeting. Discussions in the afternoon session were focused around user data, mobility and possibly the end of the user home drive as we know it. There has been lots of talk about how insecure DropBox is and the desire for businesses to implement an on premise solution. Obviously there are other commercial and open source services/products in market today that were not covered, e.g. Box, Google Drive and SkyDrive etc.

Ultimately we had AppSense, Citrix and RES in the same room demonstrating their respective products; DataNow, ShareFile and HyperDrive.

The ways in which these products are implemented varies significantly and they’re seemingly targeted at different markets or are trying to solve slightly different problems (some of which I’m not convinced really exist). For example, AppSense take a data aggregation perspective whereas RES are outwardly targeting DropBox with their current release.

From a UEM perspective there is obviously the desire for both AppSense and RES that the users’ personalisation is moved to a solution that also enables ubiquitous access within their respective UEM solutions. Synchronisation of favourites and signatures etc. regardless of device would be a massive boon for corporate users. Microsoft are doing some of this with Windows 8 today via SkyDrive.

My feeling is that regardless of what solution is implemented the vendors need to make using their product easier to use than “free” consumer products. I’m sure the majority of corporate users will happily utilise an alternative solution if it’s as easy or easier to use then their existing tool of choice. Key to this process is ensuring that a user does not have to move their data to a new solution and that their existing workflows continue to work. How many linked spread sheets are entrenched within businesses today?

Out of the solutions demonstrated the other week AppSense appear to have a head start. DataNow will currently (only) make a user’s existing home drive/directory available via the DataNow client on iOS and Android devices. This will be extended to other SMB shares and SharePoint in the future with the DataNow Enterprise product. You never know, it might actually make using SharePoint bearable!

Contrary to the DataNow product, the HyperDrive appliance is targeted directly at replacing DropBox with an on premise alternative. The caveat here is that data still needs to be moved from its existing location to a secured area managed by HyperDrive. Now don’t get me wrong; DropBox users do this already so this should not be huge undertaking. However, moving and duplicating data is not a long term solution.

Citrix announced at Synergy in Barcelona that the “Control Plane” that federates authentication and management for it’s ShareFile product is now available within the EU (Germany). For European organisations that was always going to be necessary requirement. One can only assume that this will be extended to further geographies in the near future?

The introduction of Storage Zones for ShareFile enabling on-premise data storage is something of a (welcome) surprise considering the relationship Citrix have with both AppSense and RES. OK; I’m not really surprised but it has happened quicker than I thought it would. Unfortunately for Citrix, until the Control Plane is able to run on-site it is likely there will still be some reluctance from enterprises as you’re still reliant on Citrix data centres for access to your data.

In summary all three of the products still need some development before they’re adopted by enterprises en masse, if at all.

  • The DataNow Enterprise product isn’t currently shipping (the Essentials version is) so it’s hard to recommend but looks promising.
  • HyperDrive is functional although a “little rough around the edges” but this should be expected for a v1 product. As a direct replacement for DropBox it is workable.
  • ShareFile has some fantastic opportunities with the Citrix Receiver integration but you’ll need both ShareFile Enterprise and CloudGateway Enterprise to the get the most out it. Would a smaller “point” solution be cheaper and easier to implement?

So who can deliver first…?

RES Workspace Manager – JETCMD Example Use Case

We recently announced the release of our new free Job Execution Tool (JET). If you haven’t had chance to read the announcement yet you can find it here. In this post, I’m going to detail one of the various use cases for JETCMD. This should give you an idea why we developed it in the first place and how powerful it can be.

My use case is going to focus around using JETCMD in conjunction with RES Workspace Manager to invoke a RES Automation Manager job at logoff time. The purposes of this job is to delete the locally cached user’s profile from the machine which the user has just logged off from. With the constant debate raging on whether we should be using mandatory or local (temporary) profiles, we now have a way of deleting local profiles at log off without fudging HKLM settings in the registry (perhaps another blog post?!). Regardless of how or why we should or shouldn’t be doing this, your immediate reaction at this point might be that RES Workspace Manager already integrates with RES Automation Manager! You would be correct, however we have the following restrictions:

  1. The integration only allows job scheduling at user login or when launching a managed application; not at logoff ;
  2. Run Books can’t be invoked – only Projects and Modules;
  3. You cannot dynamically pass job parameters at runtime, i.e. they are embedded into the Automation Task in RES Workspace Manager.

So how can JETCMD help us? As you’ve probably guessed JETCMD will allow us to both invoke the appropriate RES Automation Manager job at log off and pass the required parameter(s) to delete the relevant profile. The following are the outline steps involved to accomplish this task:

  1. Create a Module, Project or Run Book in the RES Automation Manager console that will be invoked by JETCMD (making note of the job GUID);
  2. As JETCMD is part of the free Virtual Engine Toolkit (VET) you’ll need to download from here and install it;
  3. Add the JETCMD.exe as a “Custom Resource” within RES Workspace Manager. Note: JETCMD.EXE can found in the “%ProgramFiles%\Virtual Engine\JETCMD” or “%ProgramFiles(x86)%\Virtual Engine\JETCMD”, depending whether it was installed on a 32 or 64-bit system;
  4. Optionally create “Environment Variables” within RES Workspace Manager, which will hold various command line parameters to pass to JETCMD such as TYPE, JOBGUID, USER and PASSWORD. Using this method makes the task you create in RES Workspace Manager extremely powerful and flexible;
  5. Create the “Execute Command” in RES Workspace Manager that runs JETCMD at logoff. Ultimately this will invoke and schedule the target RES Automation Manager job.

Now lets cover each step in slightly more detail:

STEP 1

I’m not going to cover how you create a Module, Project or Run Book in the RES Automation Manager console in detail. Rather, I am assuming that you have already created one that you would like to be invoked by JETCMD (and have noted down the relevant job GUID!). For the sake of my use case, I’m using a great tool called DelProf2 from Helge Klein (@HelgeKlein) within a RES Automation Manager module. I’ve used the following “Command (Execute)” task.

image

What you see above might look a little cryptic so I’ll briefly explain:

  1. The $Workspace{E2EBA027-FA6B-42AB-9358-C7656E99822E} reference is just a resource link that points to the DELPROF2.EXE that has been added as a resource within the RES Automation Manager console. When the RES Automation Manager task executes it will download the executable and run it;
  2. The /U switch will be passed to DELPROF2 and signifies that we would like it to run unattended, i.e. with no confirmation;
  3. To only delete a particular user profile, the /id switch is used to include only profile directories whose name matches this pattern;
  4. Used in conjunction with the /id switch, the $[UserName] is the RES Automation Manager parameter used to hold the user’s name of the profile I wish to delete (refer to JET_PARAMNAME in Step 5 for more details).

STEP 2

Nothing really to explain here other than download and install VET on your machine – simples! Smile.

STEP 3

Before we carry on with this step lets quickly describe what a “Custom Resource” is. This is an abstract from the RES Workspace Manager Administration Guide:

image

To import JETCMD as a custom resource, just follow these steps:

  1. In the RES Workspace Manager console, click on “Administration” in the navigation pane;
  2. Click on the “Custom Resources” node in the same left hand pane;
  3. Right click in the right hand pane, select “New” and browse to the location of the JETCMD.exe;
  4. The JETCMD.exe should now appear as a “Custom Resource” in the RES Workspace Manager console as shown below: image

STEP 4

Now while I did say this step was optional, I would highly recommend using “Environment Variables” to hold the parameters that JETCMD will use. This allows more visibility of these values and the potential to change them dynamically depending in the ACL’s used behind the “Environment Variables“. For example, utilising environment variables will allow you change the target RES Automation Manager job based on location or security group without having to create additional tasks!

  1. In the RES Workspace Manager console, click on “Composition” in the navigation pane;
  2. Click on the “Environment Variables” node in the same left hand pane;
  3. Right click in the right hand pane, select “New”;image
  4. Give the “Environment Variable” a suitable Name, Administrative Note and Value and change the ACLs etc. accordingly. In my instance I’ll accept the defaults;image
  5. I’m going to create 6 “Environment Variables” to make managing my “Execute Command” as simple and flexible as possible, as you can see below;image
  • JET_TYPE = RES Automation Job type to invoke i.e. Module, Project or RunBook;
  • JET_JOBGUID = The Module, Project or Run Book GUID that can be found in RES Automation Manager console;
  • JET_RESAMUSER = The RES Automation Manager console user to authenticate as;
  • JET_RESAMPWD = The password for the user as specified in JET_RESAMUSER;
  • JET_PARAMNAME = Parameter name(s) that’s specified with the RES Automation Manager job;
  • JET_PARAMVALUE = Parameter value(s) that’s used in-conjunction with JET_PARAMNAME (Refer to $[UserName] in Step 1).

STEP 5

The last step involves creating an “Execute Command” in the RES Workspace Manager console that will be executed upon logoff time.

  1. In the RES Workspace Manager console, click on “Composition” from the left hand pane;
  2. Click on the “Execute Command” node in the same left hand pane;
  3. Right click in the right hand pane, select “New”;image
  4. Adjust the “Execute Command” options so “Run Hidden” and “Run Task At Logoff” are selected as shown below:image
  5. The next most import factor here is obviously the command line specified. As I’m using “Environment Variables” my command line looks like this. [code]%RESCUSTOMRESOURCES%\JETCMD.EXE /type:%JET_TYPE% /jobguid:%JET_JOBGUID% /agent:LOCAL /user:%JET_RESAMUSER% /password:%JET_RESAMPWD% /encrypted /paramname:%JET_PARAMNAME% /paramvalue:%JET_PARAMVALUE%[/code]You’ll notice I’m also using the %RESCUSTOMRESOURCES%Environment variable” – which is used internally by RES Workspace Manager to resolve the location of the “Custom Resources” folder.

And there you have it, a common use case for JETCMD with RES Workspace Manager. I hope by now you can see how flexible and powerful JETCMD can be Smile.

We’d love to hear you comments!!.

Nathan.

Virtual Engine will be presenting at IP EXPO 2012 – London

Virtual Engine’s founder and co-owner Iain Brighton (@Iainbrighton) will demonstrate how using RES Software can help transform the lifecycle of your users in this practical, under the hood demonstration titled “Transforming the lifecycle of a user – from on-boarding to delivery of services and finally off-boarding”.

Please join us there on Thursday 18th October, 11:30 – 12:15 in the Desktop Lab Theatre.

VET v1.2 Released!

Virtual Engine are pleased to announce the general availability of version 1.2 of the Virtual Engine Toolkit (VET). The latest Windows installer and documentation is available for download now on the Virtual Engine web site.

We’ve put together a series of short videos demonstrating each new feature. In the “What’s New” video series we cover the following features:

  • Job Execution Tool (including JETCMD and JETPWD);
  • Migrating Group Policy Security Permissions (VET);
  • Group Policy Objects Wizard Search (VET);
  • Group Policy Migration Report (VET);
  • Enabling the Aero theme (PuU);
  • Importing International Settings (PuU).

For more videos on the Virtual Engine Toolkit, please check out our YouTube channel.

RES Automation Manager Quick Tip – appending to existing registry values

I was recently asked (by one of our existing RES Automation Manager customers) how they go about adding to an existing registry value using RES Automation Manager. Well the answer is simple really – by using the @REGISTRY function. I’ll detail how you go about using this function in this blog post.

  1. Firstly start the RES Automation Manager console;
  2. Select “Modules” from the left hand pane, Right Click and select “Add”;
  3. Give the module a suitable name then select the “Tasks” Tab, Right Click and select “Add”.
  4. Select the task “Registry Setting (Apply,Query)” and select “Apply”.
  5. You will now be presented with a dialogue where you can select various methods to add the required registry value you wish to append too. In my example I’m going to APPEND a new string to the START of the existing USERINIT registry value. Select “HKEY_LOCAL_MACHINE” from the left hand pane, Right Click and select “Open HKEY_LOCAL_MACHINE…”.
  6. Browse to “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon” and select “Userinit”, this will add this value to the current dialog box. image
  7. Now we are going to add the @REGISTRY function to the Userinit value by Right Clicking on “Userinit” in the right hand pane and selecting “Modify”.
  8. In the “Value Data” field, Right Click and select “Insert Functions” >; “@[REGISTRY(;)]”.image
  9. RES Automation Manager now provides you with a nice GUI that allows you to browse to the registry value you wish to retrieve, when the job is executed on the agent. In my case this is going to be the registry value I selected in Step 6, as this is the value I’d like to append too.
  10. Now I simply add the new value that I wish to append, before the @REGISTRY function or after, depending where I’d like my value to appear – in my case this value is “MyNewValuetoAppend” [code]MyNewValuetoAppend,@[REGISTRY(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon)][/code]
  11. The resulted registry value now looks like this, once the job has been scheduled and completed [code]MyNewValuetoAppend,C:\Windows\system32\userinit.exe[/code]

That’s all there is to it! Smile

Nathan

Introducing JETCMD

Complimentary to recently announced Job Execution Tool (JET) there is also a command line version. The purpose of this is tool is slightly different to the GUI version. Whilst the GUI version is all about passing parameters to modules, projects or run books chosen by the end user at run time, JETCMD is all about automation! Note: Just like JET, the RES Automation Manager (WMC.EXE) console must be installed to schedule jobs with JETCMD.

image

So how is JETCMD.EXE different from the standard WMC.EXE?! There are three big differences:

  1. To schedule a job via WMC.EXE you have to specify the target RES Automation Manager agent or team GUID. If you just want to schedule a job on the local agent there is no way to specify this. JETCMD allows you to simply specify the local agent without knowing its GUID or name in advance.
  2. There is no way to pass an encrypted password to WMC.EXE. JETCMD allows you to pass an encrypted password so it’s relatively safe to include in scripts.
  3. Parameters cannot be passed to a RES Automation Manager dispatcher without the use of a .CSV file. Therefore, it’s difficult to pass parameter values via the command line.

So why and where would you use it?! As always, we only develop additions to the Virtual Engine Toolkit when we or our customers need them! We primarily use JETCMD during Windows 7 (soon to be Windows 8) builds but I’m sure there are many other use cases…

As an example, during Windows 7 deployment we might wish to automatically schedule a RES Automation Manager module, project or run book post setup, e.g. in SetupComplete.cmd. Unfortunately, we have no way of specifying the job to run on the local agent via WMC.EXE as we don’t know its GUID – DOH! To get around this restriction we can just use JETCMD as a wrapper for WMC.

Another great example is when you’d like to schedule a RES Automation Manager module, project or run book as a logoff task in RES Workspace Manager i.e. delete any cached local profiles. The RES Automation Manager integration in RES Workspace Manager only allows for tasks to be scheduled at login or when launching managed applications – using JETCMD as an Execute Command at logoff can get around this drawback.

Here are some examples. To schedule a run book on the local agent using pass-through authentication we can use something like this (obviously the run book needs to exist!):

[code]JETCMD.EXE /type:runbook /jobguid:{5E5906A7-00D5-49E4-909B-CEB1810BF37} /agent:local[/code]

Or if you want/need to use RES Automation Manager authentication we could specify this instead:

[code]JETCMD.EXE /type:runbook /jobguid:{5E5906A7-00D5-49E4-909B-CEB1810BF37} /agent:local /username:RESAMUser /password:RESAMPassword[/code]

If you want to pass parameters to the same run book the command line would look something like this:

[code]JETCMD.EXE /type:runbook /jobguid:{5E5906A7-00D5-49E4-909B-CEB1810BF37} /agent:local /username:RESAMUser /password:RESAMPassword /paramname:”””MessageTitle”””,”””MessageBody””” /paramvalue:”””Job Successful”””,”””The target job has finished”””[/code]

You may ask why we don’t utilise team membership for this? The simple answer is if the RES Automation Manager agent is installed within an image (or how you identify RES AM agents), automatically invoking a job can be problematic. The detailed answer is that team membership rules won’t necessarily be triggered if the agent is not seen as a “new” agent. A classic example of this is when a machine is re-imaged and it’s already a member of the target team. Humans are rubbish at having to remember to remove a RES Automation Manager agent from a team before re-imaging (as well as removing a computer’s AD account!).

As we’re security conscious we also don’t like specifying the RES Automation Manager console username password in clear text if we can avoid it. Therefore, we allow you to obfuscate the password so users cannot manually open the RES Automation Manager console with credentials embedded in any scripts. Encoding the password is optional so the choice is entirely down to you.

If you do wish to obfuscate the password then you’ll need to use JETPWD.EXE (yet another tool!). This tool is used to generate obfuscated passwords for both JET and JETCMD.

These new tools will be included in the upcoming Virtual Engine Toolkit v1.2 release. Until then, if you’d like a copy please complete the Contact Us form or email me and we’ll happily send you a copy!