Site icon TheWindowsUpdate.com

PowerApp meets MECM: Modern Software Deployment

This post has been republished via RSS; it originally appeared at: Microsoft Tech Community - Latest Blogs - .

Hi everyone!


My Name is Fabian Schlagenhaufer (formerly known as Scherer), Customer Engineer at Microsoft Germany for Microsoft Endpoint Manager related topics. At nearly all my previous engagements we came to the same point facing one question:

 

How can we improve the Software Deployment Process?

 

The most IMAC (Install Move Add Change) software order processes require a first and second level customer contact and therefore consume a lot of time and money as well. Therefore, we started our journey to find a new solution to simplify this whole process handled by the end user – away from time and money consuming processes.

We defined our possibilities and dependencies and identified Microsoft Teams as the ‘Place to be’ for our End users, who start their day within the Teams Platform (including Chat, Telephony, Meetings, Viva, Company Communicator, Channels etc.) Instead of creating another Web Interface/GUI/Tool we planned to include the new application within that already very familiar platform.


Once the location has been defined the dependencies for our Solution had to be clarified:

 

It was necessary to ensure that client based licensed software still needs to be approved by the responsible units and that future concepts are still manageable within our solution. The final solution was a conglomerate of the following tools:

 

The outcome, a simple Low-Code/No-Code solution based on Powerplatform that is built in less than a day is more than satisfying and exactly what we were looking for.

 


But before we start, I would like to address some personal words.

A project like this wouldn’t be possible without a great team. Of all the people I am grateful to,  
I would like to highlight Thomas Hantsch, Erkan Grueschow, Sandrine Manel, Christian Puetz, Stefan Wentingmann, Chris Niebuhr and Robin Mueller – without these great colleagues this would never have been possible.

 

 

Dataverse | Softwarecatalog

Like everything at IT, it starts with the correct Collection of Data. For a complete Software catalogue solution there might be subjects like Vendor, Owner, Language etc. required, but for this Application the following points were enough:

 

With this Kind of Datasource I had everything which is needed to start with the PowerApp.

 

PowerApp

Due to the fact that the PowerApp itself is published in Microsoft Teams I didn’t want any kind of Landing Page which would just annoy the User after the second or third time they use it.
Therefore, I just show the User a Collection based on my Dataverse Table, One Text Bar to Search a specific Product, another one to enter the DeviceName and a third to enter a reason if the software requires an approval.

The Logic is quite simple:

The User selects a Software Product and enters a Device Name to enable the Order Button. In addition, if an selected application needs an approval, the text field for the justification gets enabled and the User has to enter a valid reason to enable the Order Button.

This Button will start the PowerAutomate Flow with specified information.

You can find some ‘Code’ Examples at the end of the Blog.

 

PowerAutomate

By hitting the ‘Order’ Button we start the PowerAutomate Flow. We will start one PowerAutomate Flow for every item which is selected:

 

We select DeviceName, The Full Name of the User, The E-Mail of the User, DataverseID and the Reason (optional) and use this information as Trigger at the Flow:

 

The next step is to get the related information out of the Dataverse. This will be realized by ‘Get a row by ID’:

 

Now we got all related information to our selected software product. This Information will now be sent to a dedicated Teams Channel:

 

Now the first of our three PowerShell Scripts will take over and evaluate the Data provided by the User (More information will be provided at the Section ‘Azure Automation’):

 

This Powershell Script will check if the Client exists at the environment. If not, the User will be informed by Flow Bot the entered DeviceName does not exist:

 

If the DeviceName is correct, a second Runbook will start to check if the Client is already part of the collection. After this Check is completed the final Approval Check starts:

 

So according to our Dataverse Table we will check if an approval is needed. If yes, the first and second approver will get a request via Approvals App and Mail:

 

Once this is approved, the client will be added to the Install Collection using the third PowerShell Script.

 

Azure Automation Hybrid Runbook Worker

If you want to know more about Azure Automation Hybrid Runbook Worker please follow this Link: Azure Automation Hybrid Runbook Worker overview | Microsoft Docs but for our use case it’s good to understand that this enables you to run Azure Runbooks local on your On-Prem Server.

 

All you need is:

 

New-OnPremiseHybridWorker.ps1 -WorkspaceName $WorkspaceName -AutomationAccountName $AutomationAccount -SubscriptionID $SubscriptionID -HybridGroupName $HybridWorkerGroup -ResourceGroupName $ResourceGroup

 

 

For this workflow I added three different Runbooks (PowerShell code is added to the End) to my Hybrid Worker Account:

  1. Check if Client Exists (PA_SoftwareOrder_CheckClient)
  2. Check if Direct Rule Exists (PA_SoftwareOrder_CheckCollection)
  3. Place the Order (PA_SoftwareOrder_Order)

Once the workflow is completed, the Built-In Mechanism of MECM will take over and deploy the Software to the Client.

 

Summary

I would like to show you Step by Step what’s happening when we order Software:

 

The User requests the software at the PowerApp pinned in Teams

 

At the dedicated IT Department Microsoft Teams Channel a new post will be generated (just an example of documentation – you could also generate a Ticket via REST API for Documentation, send a mail or generate a new Row at a defined Dataverse ‘Softwareorders’)

 

The Runbook will work in sequence defined tasks parallel for every Product we have added to our order.

 

Approval Flow will be triggered to all defined Approvers

 

After the Request is Approved the Requestor gets a Teams Message

Complete Flow Time (it depends how long the Approver needs to approve the Request)

 

The Client will be added to the Config Manager Software Collection (I have never tested it but I am pretty sure that other Client Management tools can be addressed the same way)

 

After the next Scan Cycle is finished, the user will see the Software at the Software Center – if it’s a required Installation the Install process will start immediately.

 

And that’s it – the user will now get informed by the Toast Notifications of Config Manager and there is no need for any human resource to write a mail or make a call.

 

Code Snippets

PowerApp:

Start the PowerAutomate Flow:

 

ForAll(Selection.AllItems,SoftwareOrder.Run(DeviceName.Text,User().FullName,User().Email,ThisRecord.Softwarecatalog,Reason.Text));Clear(col_Software);Clear(MyOrder);Collect(col_Software,Softwarecatalogs);Reset(DeviceName);Reset(Reason);Reset(Productsearch)

 

 

Disable/Enable the Order Button:

 

If(
    Or(
        IsBlank(DeviceName.Text),
        CountRows(MyOrder)<1,
            And(
                CountRows(Filter(MyOrder,Approval = 'Approval (Softwarecatalogs)'.Yes))>0,
                IsBlank(Reason.Text)
            )
    ),
    DisplayMode.Disabled,
    DisplayMode.Edit
)

 

 

Disable/Enable the Reason Textfield:

 

If(
    CountRows(
        Filter(MyOrder, Approval = 'Approval (Softwarecatalogs)' .Yes
        )
    ) > 0, DisplayMode.Edit, Disabled
)

 

 

Collect all Data when the PowerApp gets started:

 

Collect(col_Software,Softwarecatalogs)

 

 

PowerShell:

  1. PASoftwareOrder_CheckClient
    This runbook will check if the Client exists in your Environment

 

[CMDletBinding()]
param
(
    [String]
    $DeviceName
)
$SiteCode = "xxx"
$ProviderMachineName = "xxx.contoso.com"
$initParams = @{}
if((Get-Module ConfigurationManager) -eq $null) {
    Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams 
}
if((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) {
    New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams
}
Set-Location "$($SiteCode):\" @initParams

$Device = Get-CMDevice -Name $DeviceName
$ResourceID = $Device.ResourceID
if ($ResourceID)
{
}

else
{
    $ErrorActionPreference = "Stop"
    Write-Error -Message "This Device $DeviceName does not Exist at your Environment"
}

 

 

2. PA_SoftwareOrder_CheckCollection
This runbook will check if the Client is already got an direct rule on the collection

 

[CMDletBinding()]
param
(
    [String]
    $DeviceName,
    [String]
    $CollectionID
)
$SiteCode = "xxx"
$ProviderMachineName = "xxx.contoso.com"
$initParams = @{}
if((Get-Module ConfigurationManager) -eq $null) {
    Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams 
}
if((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) {
    New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams
}
Set-Location "$($SiteCode):\" @initParams

$Device = Get-CMDevice -Name $DeviceName
$ResourceID = $Device.ResourceID
$DirectRules = Get-CMCollectionDirectMembershipRule -CollectionId $CollectionID
foreach ($item in $DirectRules)
{
    if ($item.RuleName -eq $DeviceName)
    {
    $ErrorActionPreference = "Stop"
    Write-Error -Message "The Device is already part of this Collection"
    }
    else
    {
    }
}​

 

 

  1. PA_SoftwareOrder_Order
    This Runbook will create an Direct Rule for the Device

 

[CMDletBinding()]
param
(
    [String]
    $DeviceName,
    [String]
    $CollectionID
)
$SiteCode = "xxx"
$ProviderMachineName = "xxx.contoso.com"
$initParams = @{}
if((Get-Module ConfigurationManager) -eq $null) {
    Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams 
}
if((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) {
    New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams
}

Set-Location "$($SiteCode):\" @initParams

$Device = Get-CMDevice -Name $DeviceName
$ResourceID = $Device.ResourceID
Add-CMDeviceCollectionDirectMembershipRule -CollectionId $CollectionID -ResourceId $ResourceID

 

 

If you got any questions left please feel free to contact me and if you need some help to implement a solution like this please contact your CSAM :)

 

Fabian Schlagenhaufer
CE

Disclaimer 

 

The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages. 

 

Exit mobile version