The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,854 other subscribers

Getting the Chocolatey shimgen generated shim target

Posted by jpluimers on 2023/10/10

For tomorrow’s post Ookla speedtest CLI for Windows has some undocumented arguments to accept license and GDPR I neede the full path to the speedtest.exe which I had installed using Chocolatey.

I know chocolatey uses a shim that redirects to the actual executable, so a simple where speedtest.exe would not cut it.

My guess would be that the generated shim allowed to either get the target pathname out, or have the target pathname encoded in it.

Luckily the first applies: a few of the shim command-line parameters are in [Wayback/Archive] Chocolatey Software Docs | Executable shimming (like symlinks but better):

You pass these arguments to an executable that is a shim (e.g. executables in the bin directory of your Chocolatey install, not choco.exe):

  • --shimgen-help – shows this help menu and exits without running the target
  • --shimgen-log – logging is shown on command line
  • --shimgen-waitforexit – explicitly tell the shim to wait for target to exit – useful when something is calling a gui and wanting to block – command line programs explicitly have waitforexit already set.
  • --shimgen-exit – explicitly tell the shim to exit immediately.
  • --shimgen-gui – explicitly behave as if the target is a GUI application. This is helpful in situations where the package did not have a proper .gui file.
  • --shimgen-usetargetworkingdirectory – set the working directory to the target path. Useful when programs need to be running from where they are located (usually indicates programs that have issues being run globally).
  • --shimgen-noop – Do not actually call the target. Useful to see what would happen if you ran the command.

But the below dumps show more more (using [Wayback/Archive] Strings – Windows Sysinternals | Microsoft Docs, [Wayback/Archive] clip | Microsoft Docs and post-processing in [Wayback/Archive] Notepad++).

Back to the second solution,

strings C:\ProgramData\chocolatey\bin\speedtest.exe | findstr speedtest.exe

showed

speedtest.exe
..\\lib\speedtest\tools\speedtest.exe
Cannot find file at '..\\lib\speedtest\tools\speedtest.exe' (
speedtest.exe
speedtest.exe

And towards the first,

strings C:\ProgramData\chocolatey\bin\speedtest.exe | clip

resulted in this fragment:

==============
Shim Arguments
==============
You can pass the following arguments to a shim:
 * shimgen-help - shows this help menu and exits without running the 
   target
 * shimgen-log - logging is shown on command line
 * shimgen-waitforexit - explicitly tell the shim to wait for target to
   exit - useful when something is calling a gui and wanting to block
   - command line programs explicitly have waitforexit already set
 * shimgen-exit - explicitly tell the shim to exit immediately. 
 * shimgen-gui - explicitly behave as if the target is a GUI 
   application. This is helpful in situations where the package did not
   have a proper .gui file.
 * shimgen-usetargetworkingdirectory - set the working directory to the
   target path. Useful when programs need to be running from where they
   are located (usually indicates programs that have issues being run
   globally)
 * shimgen-noop - Do not actually call the target. Useful to see what
   would happen if you ran the command.

Based on it, I found the source code at [Wayback/Archive] shimgen/ShimProgram.cs at master · chocolatey/shimgen in repository [Wayback/Archive] chocolatey/shimgen: This repository exists to file issues against shimgen (despite there being no possibilities to report issues).

That confirmed I could just use shimgen-noop without slashes or dashes, which got me this output:

C:\temp> speedtest shimgen-noop
[shim]: Set up Shim to run with the following parameters:
  path to executable: C:\ProgramData\chocolatey\lib\speedtest\tools\speedtest.exe
  working directory: C:\bin
  is gui? False
  wait for exit? True
  command (optional):
[shim]: Command line 'speedtest  shimgen-noop'
[shim]: Current process '"C:\ProgramData\chocolatey\bin\speedtest.exe"'
[shim]: Command line after removing process 'speedtest  shimgen-noop'
[shim]: Shifting off the first argument since process didn't catch it
[shim]: Arguments after removing shimgen args - 'shimgen-noop'
[shim]: Arguments are 'shimgen-noop'

So I wrote this short batch-file choco-get-shim-target-path.bat:

:: https://wiert.wordpress.com/?p=103228
:: https://wiert.wordpress.com/?p=75096
:: https://stackoverflow.com/questions/2541767/what-is-the-proper-way-to-test-if-a-parameter-is-empty-in-a-batch-file/2544545#2544545
:: https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/for
:: https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/findstr
:: https://superuser.com/questions/1373772/batch-file-dir-findstr-within-a-for-loop/1373793#1373793
@echo off
  if "%~1" == "" goto :help
  :: get the line starting with "path", then take everything starting from the 4th space separated word
  for /f "tokens=4*" %%o IN ('"%~1" shimgen-noop ^| findstr ^^path') do echo %%o
  goto :eof
:help
  echo Executes a Chocolatey shimgen generated shim with parameter "shimgen-noop"
  echo to get the referring path.
  echo Requires one parameter: shim
  echo This parameter is the shim to execute and get the target path from.
  echo See also: https://github.com/chocolatey/shimgen

Since I keep forgetting how to:

handle empty parameters, windows – What is the proper way to test if a parameter is empty in a batch file? – Stack Overflow:

You can use:

IF "%~1" == "" GOTO MyLabel

to strip the outer set of quotes. In general, this is a more reliable method than using square brackets because it will work even if the variable has spaces in it.

escape pipe (|) characters with a caret (^) as ^|, Get the full exe path name of running processes.:

PowerShell Get-Process %* ^| Format-List Path

Some more tricks used are documented in:

–jeroen

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.