A Technique to Run Scripts Asynchronously via AppSense Environment Manager

Whilst AppSense Environment Manager (EM) has a rich set of trigger points, such as logon and reconnect, where you can run built-in actions or scripts, until very recently there was no built-in way of running something say five minutes after logon or every thirty minutes.

I’ve seen techniques that create scheduled tasks, which you can do directly in a PowerShell script rather than having to modify XML task templates, but with these you still have to get the script you want to run onto the local file system. Whilst I came up with a method of embedding any arbitrary file into an AppSense EM configuration, such as image files (see here), that approach is a little cumbersome, particularly if you need to change the embedded script.

I find an easier way to achieve this goal is to write a script inside an EM logon action that takes a copy of itself to a local file and then invokes powershell.exe to run it so that it runs outside of EM thus allowing the logon to finish but the newly launched script is still running as it is hosted inside an asynchronous powershell.exe process. Inside this script you can then wait for any period of time and then perform an action and either exit or loop around ad infinitum, or at least until logoff.

It works by looking to see if the -async option has been specified when the script was run. When EM runs the script, it won’t specify any options so we detect this and make it fire off a copy of the same script, since EM will delete the original when the script it invoked finishes, via powershell.exe which will take a different path through the code because the -async parameter is specified this time.

There’s an example version 10 EM configuration available for download here although the technique will work with any EM version. You will need to put your code into the PowerShell custom action, after the comment line reading “we are now outside of EM so can trigger later”, to perform whatever you need it to do. You might just want it to do something every few minutes or hours or you could put a file system or registry watcher in to trigger when something specifically changes (now there’s an idea for a future post if ever there was one!).

If you need the script to run elevated then simply set the action to run as System in the configuration but remember that environment variables and HKCU will not be for the logged on user but for the System account.

If you are also using AppSense Application Manager to prohibit powershell.exe then as long as you have configured it to ignore restrictions during logon then  it should be ok but you could always add a Process rule for EMUser.exe to allow powershell.exe child processes.

Updated Hyper-V Clone from Disk Script

Back in 2015 I wrote a PowerShell script, which has a GUI, to create new Hyper-V VMs from existing VHD and VHDX files. The original blog post, “Poor man’s Hyper-V cloning from VHD/VHDX”, is available here.

Now that I’ve finally got a Windows 10 laptop with Hyper-V capability, I’ve made a few additions to the script since I’m using Hyper-V, and thus the script, pretty much daily now. For example, I have SysPrep’d Windows 10 and Server 2016 disks so I can quickly create new fresh VMs simply by right or double clicking on the relevant VHDX file in explorer. If you select the linked clone option, so the whole source disk does not have to be copied, the creation, and optional automatic starting, takes only a few seconds.

These enhancements include:

  1. Install (and uninstall) option to integrate into explorer’s right click menu without having to go near the registry yourself (apparently it scares some people!).
  2. Addition of a notes field which will go into the notes for the VM, if specified.
  3. Option to hide the parent PowerShell script window so it looks cleaner although may make any errors more difficult to track down.

I hope you find it as useful as I do.

The updated script is available here.

Fixing missing Outlook reminders

Ever found that you’ve missed a meeting because Outlook didn’t remind you? It has certainly happened to me and seems linked to copying and pasting appointments via dragon drop or if someone sends you a meeting request which doesn’t have a reminder set in it. So rather than risking missing something which might be vaguely important and incurring a colleague’s or customer’s wrath, I’ve written a VBA macro that will find and fix calendar items that do not have a reminder.

If it finds any non-all day appointments without reminders, it will prompt you once for the reminder time to set, in minutes with a default of 10, and then apply that too all appointments it found.

reminder prompt

One it has finished it will inform you what appointments it changed:

reminder fixer

You can run it manually from the VBA window or I like to add macros to the ribbon which you can do by right clicking on the ribbon and selecting “Customize the Ribbon”.

reminder macro in ribbon

The code can be downloaded here. I hope it will help you never unintentionally miss a meeting again!

Please note that I haven’t tested it when running in a US locale, as the macro constructs a date string to restrict appointments to those in the future, but I hope that the mechanism I’ve used will work. It will write debug to the Immediate window (view by pressing Ctrl G) in the VBA console.

Regrecent comes to PowerShell

About 20 years ago, after I found out that registry keys had last modified timestamps, I wrote a tool in C++ called regrecent which showed keys that had been modified in a given time window. If you can still find it, this tool does work today although being 32 bit will only show changes in Wow6432Node on 64 bit systems.

Whilst you might like to use Process Monitor, and before that regmon, or similar, to look for registry changes, that approach needs you to know that you need to monitor the registry so what do you do if you need to look back at what changed in the registry yesterday, when you weren’t running these great tools, because your system or an application has started to misbehave since then? Hence the need for a tool that can show you the timestamps, although you can actually do this from regedit by exporting a key as a .txt file which will include the modification time for each key in the output.

The PowerShell script I wrote to replace the venerable regrecent.exe, available here, can be used in a number of different ways:

The simplest form is to show keys changed in the last n seconds/minutes/hours/days/weeks/years by specifying the number followed by the first letter of the unit. For example, the following shows all keys modified in the last two hours:

.\Regrecent.ps1' -key HKLM:\System\CurrentControlSet -last 2h

We can specify the time range with a start date/time and an optional end date/time where the current time is used if no end is specified.

.\Regrecent.ps1' -key HKLM:\Software -start "25/01/17 04:05:00"

If just a date is specified then midnight is assumed and if no date is given then the current date is used.

We can also exclude (and include) a list of keys based on matching a regular expression to filter out (or in) keys that we are not interested in:

.\regrecent.ps1 -key HKLM:\System\CurrentControlSet -last 36h -exclude '\\Enum','\\Linkage'

Notice that we have to escape the backslashes in the key names above because they have special meaning in regular expressions. You don’t need to specify backslashes but then the search strings would match text anywhere in the key name rather than at the start (which may of course be what you actually want).

To specify a negation on the time range, so show keys not changed in the given time window, use the -notin argument.

If you want to capture the output to a csv file for further manipulation, use the following options:

.\regrecent.ps1 -key HKCU:\Software-last 1d -delimiter ',' -escape | Out-File registry.changes.csv -Encoding ASCIII

I hope you find this as useful as I do for troubleshooting.

Send To Mail recipient replacement

It has bugged me for years that Outlook, up to and including 2016, blocks the main Outlook window if you right-click on files in explorer and choose “Mail recipient” from the Send To menu. So if you leave this draft email open, you won’t get any new emails (which isn’t necessarily a bad thing, for a while!). I therefore decided to fix it, or rather provide an alternative, by writing a PowerShell script.

The script is available here and it can be used to install itself into the running user’s SendTo menu by creating a shortcut that invokes powershell.exe on the script:

& '.\Send Outlook Email.ps1' -install "Mail recipient"

This will replace the existing “Mail recipient” shortcut, as long as you also specify the -overwrite option, but you can leave it in place and create a new shortcut for this script simply by giving a different name to the -install argument.

Should you want to, the original shortcut can be restored thus:

& '.\Send Outlook Email.ps1' -install "Mail recipient" -restore

or if you’ve created an additional shortcut, rather than replacing the default one, use -delete instead of -restore.

The additional features it provides are:

  1. It will make copies to “.txt” files of scripts, which would normally be blocked, such as .vbs or .cmd (the list of file types can be changed in the script)
  2. It will put binary files such as .exe files, which would normally be blocked, into a zip file and attach the zip file instead (these may still be blocked though)
  3. It will warn you if your total size of all attachments exceeds 20MB (this limit can be changed in the script) which may cause the send to fail depending on your mail server’s limits

The script can take various other parameters such as -subject, -body and -recipients but these can only be used when calling the script manually from a PowerShell session or another script since using it from explorer just calls the script with a list of file names to attach. However, you can change the default values of these variables in the script so that they will work when you use the send to menu item within explorer. There are comments in the script explaining how to achieve this.

By default, it uses the same subject and body text as the built-in “Email recipient” shortcut but if you don’t like this text, find the declaration of the “$noBody” variable in the script and change it from “$false” to “$true”. Here’s a screenshot of the email generated with that tweak made and with three files selected, an .exe, .txt and .ps1, when the Send To option was invoked:

outlook-send-to-email

Note that the .ps1 file has been morphed into a .txt file and the .exe has been placed into a zip file.

Oh, and my Outlook main window is fully operational whilst you add whatever body text, etc you want to this email before sending it.

 

 

When even Process Monitor isn’t enough

I was recently tasked to investigate why an App-V 5.1 application was giving a license error at launch on XenApp 7.8 (on Server 2008R2) when the same application installed locally worked fine. I therefore ran up the trusty Process Monitor (procmon) tool to get traces on the working and non-working systems so I could look for differences. As I knew what the licence file was called, I honed in quickly on this in the traces. In the working trace, you could see it open the licence file, via a CreateFile operation, and then read from the file. However, in the App-V version it wasn’t reading from the file (a ReadFile operation) but no CreateFile operation was failing so I couldn’t understand why it wasn’t even attempting to read from the file when it didn’t appear to be unable to access it. The same happened when running as an administrator so it didn’t look like a file permission issue.

Now whilst procmon is a simply awesome tool, such that life without it would be an unimaginably difficult place, it does unfortunately only tell you about a few of the myriad of Microsoft API calls. In order to understand even more of what a process is doing under the hood, you need to use an API monitor program that has the ability to hook any API call available. To this end I used WinAPIOverride (available here). What I wanted was to find the calls to CreateFile for the licence file and then see what happened after that, again comparing good and bad procmon traces.

WinAPIOverride can launch a process but it needs to be inside the App-V bubble for the app in order for it to be able to function correctly. We therefore run the following PowerShell to get a PowerShell prompt inside the bubble for our application which is called “Medallion”:

$app = Get-AppvClientPackage | ?{ $_.Name -eq 'Medallion' };
Start-AppvVirtualProcess -AppvClientObject $app powershell.exe

We can then launch WinAPIOverride64.exe in this new PowerShell prompt, tell it what executable to run and then run it:

winapioverride-launch

Note that you may not be able to browse to the executable name so you may have to type it in manually.

Once we tell it to run, it will allow us to specify what APIs we want to get details on by clicking on the “Monitoring Files Library” button before we click “Resume”.

api-monitor-hook

You need to know the module (dll) which contains the API that you want to monitor. In this case it is kernel32.dll which we can glean from the MSDN manual page for the CreateFile API call (see here).

api-monitor-kernel32

Whilst you can use the search facility to find the specific APIs that you want to monitor and just tick those, I decided initially to monitor everything in kernel32.dll, knowing that it would generate a lot of data but we can search for what we want if necessary.

So I resumed the process, saw the usual error about the licence file being corrupt, stopped the API monitor trace and set about finding the CreateFile API call for the licence file to see what it revealed. What I actually found was that CreateFile was not being called for the licence file but when I searched for the licence file in the trace, it revealed that it was being opened by a legacy API called OpenFile instead. Looking at the details for this API (here), it says the following:

you cannot use the OpenFile function to open a file with a path length that exceeds 128 characters

Guess how long the full path for our licence file is? 130 characters! So we’re doomed it would seem with this API call which we could see was failing in API monitor anyway:

medallion-open-file

I suspect that we don’t see this in procmon as the OpenFile call fails before it gets converted to a CreateFile call and thence hits the procmon filter driver.

The workaround, as we found that the installation wouldn’t work in any other folder than c:\Medallion so we couldn’t install it to say C:\M, was to shorten the package installation root by running the following as an admin:

Set-AppvClientConfiguration -PackageInstallationRoot '%SystemDrive\A'

This changes the folder where App-V packages are cached from “C:\ProgramData\App-V” to “C:\A” which saves us 18 characters. The C:\A folder needed to be created and given the same permissions and owner (system) as the original folder. I then unloaded and reloaded the App-V package so it got cached to the \A folder whereupon it all worked properly.

Manipulating autorun logon entries with PowerShell

As I came to manually create a registry value for a script I wanted to run at logon, I thought that I may as well write a script that would ass the item to save people having to remember where to create the entries. It then morphed into something that would list or remove entries too, depending on the command line parameters specified.

The script is available here and can be run in a number of different ways, e.g.:

  • Show all existing autorun entries in the registry for the current user (if -registry is not specified then the file system will be used):
& "C:\Scripts\Autorun.ps1" -list -registry
  • Delete an existing autorun entry for the current user that runs calc.exe either by the name of the entry (the shortcut name or registry value name) or by regular expression matching on the command run:
& "C:\Scripts\Autorun.ps1" -name "Calculator" -remove
& "C:\Scripts\Autorun.ps1" -run Calc.* -remove
  • Add a new autorun entry to the file system that runs calc.exe for the current user:
& "C:\Scripts\Autorun.ps1" -name "Calculator" -run "calc.exe" -description "Calculator" 

The -allusers flag can be used with any of the above to make them operate for all users but the user running the script must have administrative rights.

When creating an autorun item in the file system, the icon for the shortcut can be specified via the -icon option.

Deletions will prompt for confirmation unless you specify -Confirm:$false and it will also prompt for confirmation when creating a new entry if the name of the entry already exists.

Specifying -verify will generate an error if the executable does not exist when creating a new entry.

If you are on a 64 bit system then you can specify the -wow6432node option when using -registry to work in the wow6432node area of the registry.