New Tool: Chocolatey Application Wrapper for MDT

Update: Updated script location

I’ve been spending some time recently working on my own private Deployment Share, one of the downsides is the overhead of keeping my application packages up to date. The worst offenders are of course Google Chrome, and the Adobe Flash and PDF readers, seems like these packages are constantly changing, and I need to find and update frequently. If only there was a better way, something to make adding packages easier like my Dell Driver Pack Update tool, or the ZTIWindowsUpdate.wsf script found in MDT to run Windows Update/WSUS. Any way to keep my environment up to date without the manual hassle. :^)

There are several tools out there on the internet that help and assist you with application package management. At first I started looking at, however their tools are designed for End Users, and if you want to have an automated solution (like I need), then you must pay a per-machine licensing fee. (yuck)

Then I started looking at Chocolatey, which provides a command line interface for installing programs similar to without the UI fluff. I come across a couple of packages that were found in Ninite but not found in Chocolatey, but that list is small: (Google Talk, AIM, Yahoo!, KMPlayer, Winamp, K-Lite Codecs, Mozy, RealVNC) and the list of packages found in Chocolatey is very large. Cool!

Anther advantage of Chocolatey is that it’s in alignment with future Microsoft plans around packaging (see OneGet). However Oneget still requires some installation overhead that I didn’t want to deal with for this release, so something for the future.

So I spent some time experimenting, reverse engineering Chocolatey and scripting a workable solution, and I think I have something ready for use.

The Script

The script is fairly straight forwards. When calling the script, we pass in a list of parameters in through the command line, if no parameters are passed in, then we will default to the Chocolatey001 … Chocolatey00n variables you may be familiar with when using MDT and adding variables into your CustomSettings.ini file.

    [string[]]$Packages = $TSEnvList:Chocolatey

Then we determine a local path for the Chocolatey install, looking to see if it was already installed, then forcing it to use the local MDT temp directory (C:\MININT) if present. This means that Chocolatey won’t be available after MDT installation, great for image capture.

write-verbose "Construct a local path for Chocolatey"
if ($env:ChocolateyInstall -eq $Null)
    $env:ChocolateyInstall = [Environment]::GetEnvironmentVariable( "ChocolateyInstall" , [System.EnvironmentVariableTarget]::User)
    if ($env:ChocolateyInstall -eq $Null)
        $env:ChocolateyInstall = join-path ([System.Environment]::GetFolderPath("CommonApplicationData")) "Chocolatey"
        if ($tsenv:LogPath -ne $null)
            $env:ChocolateyInstall = join-path $tsenv:LogPath "Chocolatey"

We look to see if the Choco.exe program is found locally, and if not we will install Chocolatey from the internet.

$ChocoExe = join-path $env:ChocolateyInstall "bin\choco.exe"

write-verbose "Chocolatey Program: $ChocoExe"
if ( ! (test-path $ChocoExe ) )
    write-verbose "Install Chocolatey..."
    Invoke-Expression ((new-object net.webclient).DownloadString(''))
    if (!(test-path $ChocoExe))
        throw "Chocolatey Install not found!"

Finally, we will go through all the packages requested, and kick off the installation. The list of requested packages will come from the command line

write-verbose "Install Chocolatey packages from within MDT"
foreach ( $Package in $Packages ) 
    write-verbose "Install Chocolatey Package: $ChocoExe $Package"
    & $ChocoExe install $Package 2>&1 | out-string

write-verbose "Chocolatey install done"

Had some problems with Chocolatey and the MDT PowerShell provider with some overly verbose output, so I redirect all errors to the Standard Console, that’s what the weird 2>&1 is all about.

Integration with MDT LiteTouch

To add into your MDT LiteTouch environment, simply download the ZTIChocolatey-Wrapper.ps1 into your \\Server\DeploymentShare$\Scripts folder.

Then add a new step into your task sequence pointing to the powershell script: %ScriptRoot%\ZTIChocolatey-Wrapper.ps1

You can add entries into your CustomSettings.ini file, here is a snippet from my server:



The Install Applications step will install the Applications001 and Applications002 Guid I selected above, and the Chocolatey install will install the VLC, 7zip, speccy, and WindowsADK steps above.

Adding the Chocolatey wrapper as an Application

Alternatively you can create an application package (without source files), and use the following command:

powershell.exe -NoProfile -ExecutionPolicy unrestricted "%ScriptRoot%\ZTICHocolatey-Wrapper.ps1" -verbose -Packages "AdobeReader"


The next logical step is to create a Litetouch Wizard page for Chocolatey, allowing you to select packages from a list in the GUI. But I’m a bit stumped on the best way to get a list of all available packages ( clist.exe ), *and* get the package metadata in a graceful way. Right now, I only know how to download each package from the server as *.zip file, extract out the *.xml file and display. If you know how to use PowerShell to get the list of packages *and* get a list of descriptions, versions, and icons, please let me know.


36 thoughts on “New Tool: Chocolatey Application Wrapper for MDT

  1. Nice one! I wasn’t event heard about Chocolatey before this. There is also free PatchMyPC updater that is free and has commandline support. We are using PatchMyPC SCUP catalog with ConfigMgr and we have been quite satisfied with it.

  2. I followed your steps for Chocolatey in MDT and I got the following error message:

    Failed to run the last action: Chocolatey Install.
    DNS Server not authoritative for zone (Error: 00002331)

  3. Pingback: How To Use Chocolatey with MDT 2013 - xenappblog

  4. Hello,

    This script used to work fine, but it seems now we have to push enter after each line (we do the installations separatly), so the script can execute. Is there any option to force the execution of each line, so the installation can be done silently without any action from us ?

  5. Thanks for this solution Keith. I am using it now also in my MDT tasks. There is however a little error in the script. At line 69 it says $ChocoExe feature enable -n allowGlobalConfirmation this should be & $ChocoExe feature enable -n allowGlobalConfirmation. Just like you do in line 76.

  6. A file named ZTICHocolatey-Wrapper.ps1 is mentionned but the downloable script file is named Install-Chocolatey.ps1. Did you just rename Install-Chocolatey.ps1 to ZTIChocolatey-Wrapper.ps1 or is it a different file ?

  7. Hi!
    Awesome script!
    Just did som Chocolatey applications for our migration to Windows 10.
    The applications installs just fine, however “Choco.exe” does not register itself in the global environment path. How do I acomplish that?
    I have a GPO that hits all machines migratet to windows 10, that will automatically update all Chocolatey apps (choco -upgrade all -y)

  8. How should i format my command for an install that requires an additional parameter?
    ie –
    This was my most recent attempt running it as an application.
    powershell.exe -NoProfile -ExecutionPolicy unrestricted “%ScriptRoot%\ZTIChocolatey-Wrapper.ps1” -verbose -Packages jre8 -PackageParameters “/exclude:64” -y

  9. This looks like it’s exactly what I need, but for whatever reason, the link to the PowerShell script mentioned in your article is not working (CodePlex shows an error instead of the source). Any chance I can get this script from you another way?? Thanks a million… Nate

  10. Hi, great script. Does this work with MDT 2013 update 2? as i am getting the following errors:

    “batch file could not be found” is also safe to ignore
    “the system could not find the file specified” – also safe

    the term ‘out-verbose’ is not recognized as the name of a cmdlet, function, script file or operable program. check the spelling of the name, or if a path was included, verify that the path is correct and try again.

    it then references location of the install-chocolatey.ps1:77 char:88
    + invoke-expression “cmd.exe /c $chocoExe Install $package -y -v 2>&1” | out-verbose
    objectnotfound: (out-verbose:String) [], commandnotfoundexception

    any help/advice on this would be appreciated.

    • I just dropped the string “| out-verbose” from the end of line 77, and it seemed to work okay. I’m sure it means I’m losing logging information, but for right now I’m okay with that.

  11. “Right now, I only know how to download each package from the server as *.zip file, extract out the *.xml file and display. If you know how to use PowerShell to get the list of packages *and* get a list of descriptions, versions, and icons, please let me know.”

    One thing you can do is call the nuget API for whatever chocolatey feed you’re using. For example: (Feed url)/Packages() (i.e.: )

    It is subject to pagination, but it contains all the XML metadata you want, without having to download each package.

    As you can see in

    $url = ‘$filter=((Id%20eq%20%27chocolatey%27)%20and%20(not%20IsPrerelease))%20and%20IsLatestVersion’
    [xml]$result = Download-String $url
    $url = $result.feed.entry.content.src

    This gets the xml data for the latest chocolatey package, but I’m sure you can do other creative filtering. If you’re hosting an internal feed, you can just take the feed url and add

    I hope that was helpful do you. I was wondering how you would go about creating the wizard page that populates based on the current packages available in a given chocolatey repo.

    I’m extremely new to MDT, but not powershell/chocolatey :P.

  12. Hi i could well be doing this all wrong, but I can’t seem to find “ZTIChocolatey-Wrapper.ps1” in your link on codeplex, just “install-chocolatey.ps1”. Where am I going wrong? Cheers

  13. Found it in here I assume its the same thing… It seems i’m missing a switch someplace as the TS is waiting for some input – found this in the log?

    2017-04-18 14:59:04,747 [INFO ] – The package Silverlight wants to run ‘chocolateyInstall.ps1’.
    2017-04-18 14:59:04,751 [INFO ] – Note: If you don’t run this script, the installation will fail.
    2017-04-18 14:59:04,756 [INFO ] – Note: To confirm automatically next time, use ‘-y’ or consider:
    2017-04-18 14:59:04,761 [INFO ] – choco feature enable -n allowGlobalConfirmation
    2017-04-18 14:59:04,787 [INFO ] – Do you want to run the script?
    2017-04-18 14:59:04,794 [INFO ] – 1) yes
    2017-04-18 14:59:04,798 [INFO ] – 2) no
    2017-04-18 14:59:04,803 [INFO ] – 3) print

    any ideas?

  14. Nice work! However ..
    I imported your script (from …) into my Scripts directory, created an MDT application that runs this command:
    powershell.exe -NoProfile -ExecutionPolicy unrestricted “%ScriptRoot%\Install-Chocolatey.ps1” -verbose -Packages “vcredist2005”
    , but when I execute this as part of a task sequence to deploy Windows 7, it asks me for confirmation:

    Security Warning
    Run only scripts that you trust. While scripts from the Internet can be useful,
    this script can potentially harm your computer. Do you want to run
    [D] Do not run [R] Run once [S] Suspend [?] Help (default is “D”):

    Why it asks me to confirm to run the script?

      • Thanks for your time. I did find the script “Install-Chocolatey.ps1” which was committed 7 months ago. Has there been any change?
        It is strange that, when I copy the script from the deployment share to a local drive, i.e. %Temp% , it runs fine. However when I run the script straight from the deployment share , it asks me to confirm running it. Even while the executionpolicy was set to RemoteSigned , in both scopes CurrentUser and LocalMachine. I have run this by opening cmd shell while the task sequence was halting. Then I ran this commandscript:

        Powershell.exe -ExecutionPolicy Unrestricted -Command “Get-ExecutionPolicy -List”
        set SCRIPTROOT=\\bcmdt1\mdtbuildlab$\scripts
        :: this asks the user to run …
        powershell.exe -ExecutionPolicy Unrestricted -File “%SCRIPTROOT%\Install-Chocolatey.ps1” -Packages vcredist2005
        copy %SCRIPTROOT%\Install-Chocolatey.ps1 %TEMP%\Install-Chocolatey.ps1
        :: this just runs!
        powershell.exe -ExecutionPolicy Unrestricted -File “%TEMP%\Install-Chocolatey.ps1” -Packages vcredist2005

        I had to set Scriptroot env variable because this was not run as a sequenced task. Surely running an cmd-script defeats the whole ease of user of running the PowerShell-script from a command line task. If you know why this behavior exists, I would be very happy to hear about it..

      • … and you can see I am trying to run your script on Windows 7. In fact Windows 7 Enterprise x86 SP1 Dutch. I did try your script on a deployment of Windows 10 Pro x64 and it ran just fine … Important difference here of course: Windows 7 has PowerShell v2.0, Windows 10 has PowerShell v5

  15. The script isn’t blocked. I tried to install Windows Management Framework 5.1 prior to running the chocolatey install task, and had to install .NET Framework 4.6.2 first. Still no luck

  16. Alright .. I searched a little further and found This stackoverflow post.
    It turns out running scripts from the deploymentshare using the commandline
    Powershell.exe -executionPolicy Unrestricted -File "...."
    will sometimes trigger the security warning and the “Do you want to run this script?” question because the path is considered something from the bad internet. To fix this, use executionpolicy Bypass. So the recommended way to invoke the for example to install vcredist2005 is like this:
    Powershell.exe -executionPolicy Bypass -File "%ScriptRoot%\Install-Chocolatey.ps1" -Verbose -Packages "vcredist2005" -y
    I am apparently the first one to stumble across this..

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s