Create your own Software Deployment Repository with Azure and Intune

As you might know, within Intune you can only install applications on devices, if they are coming as an MSI. If you want to deploy anything else, this blog might be helpful for you.
Let me talk about the requirements:

  • Azure Subscription for Storage
  • Intune Subscription (obviously)
  • This blog will provide the information how you can achieve this, and at the end, you will get a sample implementation from my LAB.

    Yes, that’s it. Now let us start creating the Azure Storage, and how you can access it. Go to the Azure portal, and open the storage accounts section. You can use the classic storage account as well, but I would recommend the newer ones:

    Click on Add, to add a storage account, if you don’t want to use an existent one. The creation process of a new storage account is straight forward, mind to select the appropriate replication model:

    After the storage Account is created, you can go ahead and get the access token, which we need afterwards. Click on your newly created storage account, and click on “Shared access signature” afterwards, the following screen should appear:

    Within this page, you can select how long the generated access token is valid, or for which access it will allow. This is the most restrict version I figured out to use, for downloading the files within the repository.
    Allowed Services: Blob
    Allowed Resource Types: Service, Container, Object
    Allowed Permissions: Read, List

    Afterwards you can click on generate SAS and connection string, and copy the SAS token string, thus it’s the only one we require:

    As said before, copy the “SAS token” string.

    Now go ahead to your storage account and add a blog beyond the container option:

    Afterwards you can simply upload files from your installation package to your container, my example shows the 7-zip Installation:

    Now everything is set up, and you can test the download of the file through a browser. For this, you will need those three informations:

  • URL from Container (will see that shortly)
  • FileName (defined from you)
  • SAS Token (as above)
  • Getting the Container URL is that simple, just click on Properties of your recently created Container, and copy the URL from there:

    Now just put those thing together, in my case:$herecomestheSAStoken

    Putting this in your browser URL-bar should start the download of the file, and if it’s working, we only need a script, which will trigger the installation. Here comes my created script in action, it will download the required files, and will start an installation afterwards. The script is not yet golden, it is missing an option to download the files through BITS. And also some Variables inside the Script could be replaced with Input Parameters. Time will tell if I can upgrade the script.
    Mind to adjust the line 15-17 and 20-21 to your needs. You can also install MSI files, if so, you will need to adjust line 19, beside 20-21.
    The script expects a file called “fileinfo.txt” in the root of the Container, conataining all the files required to download on a separate line. The file should lool like follows:

    And this is the used script:

    If ($ENV:PROCESSOR_ARCHITEW6432 -eq "AMD64") {
    Try {
    &"$ENV:WINDIR\SysNative\WindowsPowershell\v1.0\PowerShell.exe" -File $PSCOMMANDPATH
    Catch {
    Throw "Failed to start $PSCOMMANDPATH"

    function Get-DLFileInfo {
    $webrequest = Invoke-WebRequest -Uri ($ContainerUrl + "/fileinfo.txt" + $SASToken) -UseBasicParsing -ErrorAction Continue

    #return content of file
    return $webrequest.Content

    function Download-File {
    try {
    $fileDownload = Invoke-WebRequest -Uri $fileDLURL -UseBasicParsing -Method Head -ErrorAction Continue
    catch {
    $returnError = $_.Exception.Message

    finally {
    $fileDownload = Invoke-WebRequest -Uri $fileDLURL -OutFile ($AppTempDLPath + "\" + $file) -UseBasicParsing -ErrorAction SilentlyContinue
    #return status of download
    return $returnError

    #adjustable Variables (you SHOULD CHANGE THOSE :)
    $SASToken = "?sv=2011-11-09&ss=b&srt=sco&sp=rwl&se=2019-09-18T22:24:51Z&st=2008-09-17T14:24:51Z&spr=https&sig=4pYCjCt7%2B%2B1nCXrHex7NnGJO3242342BybvYR5kSQN521Fk%3D" #todo: as input variable
    $ContainerUrl = "" #todo: as input variable
    $ClientTempLocation = $env:TEMP
    #Application Installation
    $MSIInstall = $true # set to true, and use the $installexecutable parameter for your MSI
    $InstallExecutable = "KeePass-2.40.msi" #if using MSI, name the MSI here. e.g: "7zipinstall.msi"
    $InstallParameters = "/qn"

    ##Main Script
    $bContinue = $false

    #create temp folder for download, if existent delete it before
    #get Application Name from ContainerURL
    $ApplicationName = $ContainerUrl.Split("/")[$ContainerUrl.Split("/").Count - 1]
    #Setup Temp path for Application
    $AppTempDLPath = ($ClientTempLocation + "\" + $ApplicationName)
    #check for temp folder
    if(Test-Path $AppTempDLPath) {
    Remove-Item -Path $AppTempDLPath -Recurse
    $silentcreate = New-Item -Path $AppTempDLPath -ItemType Directory
    else {
    $silentcreate = New-Item -Path $AppTempDLPath -ItemType Directory

    #Get File info for downloading files afterwards
    $DLFileContent = Get-DLFileInfo

    if($DLFileContent) {
    #download instruction file found, nothing to do here

    #set continue script to true
    $bContinue = $true
    } else {
    Write-Warning "Download File not found"

    #set continue script to false
    $bContinue = $false

    #split input file
    $DLFileContent = $DLFileContent.Split()

    #download the files
    if($bContinue -eq $true) {
    $bDLContinue = $true
    #download file was found, now download all the files
    foreach($file in $DLFileContent) {
    #filter empty lines
    if($file) {
    #setup DL URL
    $fileDLURL = $ContainerUrl + "/" + $file + $SASToken
    #download the file
    $DownloadedFile = Download-File
    If($DownloadedFile) {
    #if a file was not correctly downloaded, set variable to false
    $bDLContinue = $false
    Write-Warning ("Download error: " + $DownloadedFile)
    Write-Warning ("The following file could not be downloaded: " + $file)

    else {
    #if the file was successfully downloaded, notihn to do here

    #check if script can continue
    if($bDLContinue -eq $false) {
    Write-Warning "A file was not successfully downloaded, Script will not execute further"

    #set continue script to false
    $bContinue = $false

    #execute the installation
    if($bContinue -eq $true) {
    if($MSIInstall -eq $false) {
    start ($AppTempDLPath + "\" + $InstallExecutable) -ArgumentList $InstallParameters -Wait
    else {
    $msiexec = $env:SystemRoot + "\system32\msiexec.exe"
    #Write-Host $msiexec -ArgumentList $InstallParameters -Wait
    $PathToMSI = $AppTempDLPath + "\" + $InstallExecutable
    Start-Process $msiexec -ArgumentList ("/i " + $PathToMSI + " " + $InstallParameters +" /L*vx C:\windows\temp\" + $ApplicationName + ".log") -Wait

    After your adjustments, you can test the script on a computer manually, and afterwards you can upload it to Intune. Go to Microsoft Intune -> Device configuration -> PowerShell scripts:

    After adding your script, you can assign it to different users or groups.

    Let me know if this was helpful, and if you would like to get a more advanced script, including a Logging Function.

    /Update 19.09.2018: Script adjusted, errors removed, MSI improved

    3 thoughts on “Create your own Software Deployment Repository with Azure and Intune

    1. Hi,

      Thanks a lot for these inputs. I’d like to give a feedback on the way to download files from Azure you’re using (Invoke-WebRequest cmdlet). It may be too slow to use as part of a Powershell script launched through Intune as there a timeout of 10mn for a script to run once triggered by the Intune Management extension.
      Depending of the Internet bandwidth, you may face issues.
      I would recommend to use a System.Net.WebClient object which is more efficient :

      $uri = “”
      $Path = “c:\Tools”

      $of = “$Path\”

      $wc = New-Object System.Net.WebClient
      $wc.DownloadFile($uri, $of)

      Hope this helps !

    2. […] PowerShell Script Last but not least, you can create a PowerShell script, which will do all the required modification on the client. But I would highly recommend to avoid PowerShell scripts as much as possible, as the settings are not really managed with this solution. It is more a Fire and Forget solution, which might be valid for some use-cases, no doubt about that. But in general, try to configure the required Windows 10 settings through the different Intune blade Options. So as mentioned before, I will set the HiberBoot option through a PowerShell script, and I’m quited confident, that it should work. I think this will be my next blog, where I can tell, if it worked or not 🙂 But see this previous blog, where I described the Application deployment with Intune and PowerShell (with the new Win32 wrapper of Intune, the process in this blog is no longer needed): Create your own Software Deployment Repository with Azure and Intune […]

    Leave a Reply to Martin Wüthrich Cancel 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

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