Wednesday, May 8, 2024
HomePowershellMaking a Powershell Automation Scheduling App With Azure and Microsoft Powerapps

Making a Powershell Automation Scheduling App With Azure and Microsoft Powerapps


For me, one of the vital annoying sorts of tickets you possibly can obtain at a helpdesk is a request for momentary permissions. You obtain a ticket stating that “this person” must be granted entry to this SharePoint website, and the permission must be eliminated after 1 week. Or “this outdated mailbox” must be restored, and “that person”, ought to solely have entry for the following couple of days.

The Tickets are simple sufficient to finish, however the annoying half is to schedule that it is advisable to carry out a activity two instances, one for granting the permissions, then wait. After which the second time to take away the permission, earlier than you possibly can really shut the ticket.

This led me to consider how I may use an Azure Automation Account, a PowerApp, and PowerShell to create an automation framework for simple scheduling of all these automation.

You’ll find all code associated to this challenge in my Github Repo

Overview of the challenge

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/application-diagram.png

Creating the Azure useful resource

For the challenge you will want the next useful resource:

  • Azure Automation Account
  • Storage Account
  • Azure Capabilities App
  • Azure API Administration

for creating the sources you need to use the next cli instructions;

Creating useful resource group:

1
2
3
4
$rg = "rg-test-automation"
$location = "North Europe"

az group create --resource-group $rg --location $location

Azure Automations Account:

1
2
3
$aaccountname = "aa-test-automations"

az automation account create --automation-account-name $aaccountname --location $location --sku "Free" --resource-group $rg

Storage Account:

1
2
3
$storageaccountname = "scriptingchrisstorage"

az storage account create --name $storageaccountname --resource-group $rg --location $location --sku Standard_LRS

Azure Operate App:

1
2
3
4
$appname = "fa-test-automations"
$consumptionLocation = "northeurope"

az functionapp create --resource-group $rg --consumption-plan-location "northeurope" --name $appname --os-type Linux --runtime powershell --storage-account $storageaccountname --runtime-version 7.2 --functions-version 4

Azure API Administration:

1
2
3
$apimname = "test-automation-api"

az apim create --name $apimname --resource-group $rg --publisher-name "ScriptingChris" --publisher-email "[email protected]" --no-wait

Making a service principal for working the Azure Operate integration into the Azure Automation Account

You will have a service principal for connecting from you Azure Operate App to your Automation Account. To create the service principal you need to use the next command:

1
az advert sp create-for-rbac --name "sp-test-automation" --role "contributor" --scopes "/subscriptions/<subscription-id>/resourceGroups/rg-test-automation/suppliers/Microsoft.Automation/automationAccounts/aa-test-automation"

The command will give an output just like under. Right here it is very important be aware down the “appId”, “password” and the “tenant”, since you’ll use the data later.

1
2
3
4
5
6
{
  "appId": "2fe6c698-15f2-4b19-9c1d-99beb94777af",
  "displayName": "sp-test-automation",
  "password": "R6asdsAQs6H_MPO2Xs414emKsdsuW-APOMas~i",
  "tenant": "<tenant-id>"
}

Creating the Azure Operate

The Azure perform will likely be a fairly easy PowerShell script. The script will be capable to take totally different parameters supplied by the PowerApp. These parameters then outline which runbook must be scheduled and supply the parameters to that particular Runbook.

When creating this setup, and the runbooks for this setup it is extremely vital to consider which kinds of Automation scripts run and which kinds of parameters these runbooks want to have the ability to run.

Setting the Appsettings for passing credentials to the perform

Should you use the Azure Operate extension in vscode, you possibly can open the file native.settings.json and add within the following variables:

Setting Worth
SP_APP_ID Service Principal App id
SP_APP_SECRET Service Principal Secret
TENANT_ID Azure Tenant id
RESOURCE_GROUP Title of the useful resource group
AUTOMATION_ACCOUNT Title of the automation account

your native.settings.json ought to look just like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME_VERSION": "~7",
    "FUNCTIONS_WORKER_RUNTIME": "powershell",
    "SP_APP_ID": "ServicePrincipalAppId",
    "SP_APP_SECRET": "<ServicePrincipalSecret>",
    "TENANT_ID": "<TenantId>",
    "RESOURCE_GROUP": "rg-test-automation",
    "AUTOMATION_ACCOUNT": "aa-test-automation"
  }
}

The native.settings.json is just for testing domestically, you will want to set the appsettings for the FunctionApp both in Azure or by way of vscode, earlier than you deploy the capabilities.

Setting the Route Parameter

To have the ability to choose which runbook you wish to schedule simply by passing within the runbook title immediately into the URL, you will want to set the route parameter in your perform.json file

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "Request",
      "methods": [
        "post"
      ],
      "route": "{RunbookName}"
    },
    {
      "sort": "http",
      "route": "out",
      "title": "Response"
    }
  ]
}

with the route parameter {RunbookName}, now you can go the title of the runbook, to the Azure perform by passing it into the URL

Right here is an instance: http://localhost:7071/api/test-runbook

Creating the PowerShell perform which creates the schedules

I’ve created the PowerShell perform proven under. I received’t go an excessive amount of in-depth in regards to the logic, however mainly, the perform accepts the beginning time, description, and the runbook parameters by way of an HTTP request physique.

An instance of the physique could possibly be:

1
2
3
4
5
6
{
    "StartTime": "2022-05-20 09:45:00",
    "Parameters": {
        "Title": "Christian"
    }
}

The perform then checks to see if the requested runbook exists. If it exists then it’ll attempt to create a brand new schedule after which assign the schedule to the required runbook.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
utilizing namespace System.Internet

# Enter bindings are handed in through param block.
param($Request, $TriggerMetadata)

$physique = $Request.Physique # Saving request physique into variable
$params = $Request.Params # Saving route parameter into variable

Write-Output "StartTime: $($physique.StartTime)"
Write-Output "RunbookName: $($params.RunbookName)"

# Connecting to Azure with service principal
Write-Output "Creating the credential object for the service principal: $($env:APP_ID)"
$Credential = New-Object System.Administration.Automation.PSCredential `
    -ArgumentList $env:SP_APP_ID, `
    (ConvertTo-SecureString $env:SP_APP_SECRET -AsPlainText -Power)

Write-Output "Connecting to Azure with service principal"
Join-AzAccount -ServicePrincipal -TenantId $env:TENANT_ID -Credential $Credential


# Checking if the runbook exists
Write-Output "Checking that Runbook exists"
attempt {
    $Runbook = Get-AzAutomationRunbook `
        -ResourceGroupName $env:RESOURCE_GROUP `
        -AutomationAccountName $env:AUTOMATION_ACCOUNT `
        -Title $params.RunbookName
    Write-Output "Runbook discovered!"
}
catch {
    $Runbook = $false
}


# If the runbook exists, then create a brand new schedule
if($Runbook -ne $false) {
    # Scheduling the PowerShell Runbook in Azure
    # To Discover your timezone you need to use: ([System.TimeZoneInfo]::Native).Id
    $TimeZone = "Romance Normal Time" # Set the timezone to your atmosphere
    $ScheduleId = "automation-" + (New-Guid).Guid.break up("-")[0] #  Provides an id wanting like: automation-b0736aa1

    attempt {
        Write-Output "Creating Runbook schedule with id: $($ScheduleId)"
        $output = New-AzAutomationSchedule `
            -AutomationAccountName $env:AUTOMATION_ACCOUNT `
            -Title $ScheduleId `
            -StartTime (Get-Date $physique.StartTime) `
            -Description $physique.Description `
            -OneTime `
            -ResourceGroupName $env:RESOURCE_GROUP `
            -TimeZone $TimeZone
        
        Write-Output "Registering the brand new schedule with a runbook"
        $Registration = Register-AzAutomationScheduledRunbook `
            -AutomationAccountName $env:AUTOMATION_ACCOUNT `
            -Parameters $physique.Parameters `
            -RunbookName $Runbook.Title `
            -ScheduleName $ScheduleId `
            -ResourceGroupName $env:RESOURCE_GROUP
    }
    catch {
        Write-Error -Message "$($_)"
    }
}
else {
    Push-OutputBinding -Title Response -Worth ([HttpResponseContext]@{
        StatusCode = 404 # If the runbook would not exists then present a 404 error
        Physique = "404 - Runbook: $($physique.RunbookName), was not discovered"
    })
}


if($Registration) {
    Push-OutputBinding -Title Response -Worth ([HttpResponseContext]@ ConvertTo-Json
    )
}
else {
    Push-OutputBinding -Title Response -Worth ([HttpResponseContext]@{
        StatusCode = 500 # if the creation of the schedule failed, then present a 500 error
        Physique = "$($Error[0])"
    })
}

Creating the PowerShell perform which get present scheduled runbooks

The second perform i’ve created is made for retrieving all of the scheduled runbooks. This fashion you will get a superb overview within the app of which runbooks are already scheduled and ready to be executed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
utilizing namespace System.Internet

# Enter bindings are handed in through param block.
param($Request, $TriggerMetadata)

# Connecting to Azure with service principal
Write-Output "Creating the credential object for the service principal: $($env:APP_ID)"
$Credential = New-Object System.Administration.Automation.PSCredential `
    -ArgumentList $env:SP_APP_ID, `
    (ConvertTo-SecureString $env:SP_APP_SECRET -AsPlainText -Power)

Write-Output "Connecting to Azure with service principal"
Join-AzAccount -ServicePrincipal -TenantId $env:TENANT_ID -Credential $Credential

attempt {
    $Schedules = Get-AzAutomationSchedule `
        -ResourceGroupName $env:RESOURCE_GROUP `
        -AutomationAccountName $env:AUTOMATION_ACCOUNT | `
        The place-Object {$null -ne $_.NextRun} | `
        Choose-Object Title, CreationTime, NextRun, TimeZone, Description | `
        ConvertTo-Json

        Push-OutputBinding -Title Response -Worth ([HttpResponseContext]@{
            StatusCode = 200 # If the runbook would not exists then present a 404 error
            Physique = $Schedules
        })
}
catch {
    Push-OutputBinding -Title Response -Worth ([HttpResponseContext]@{
        StatusCode = 500 # if the creation of the schedule failed, then present a 500 error
        Physique = "$($Error[0])"
    })
}

Testing the Azure Operate

Now I’ve created a quite simple Automation Runbook, which takes a parameter “Title” and writes out a message.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
param (
	[Parameter(Mandatory=$true)]
	[String]$Title
)

$now = (Get-Date).ToString("yyyy-MM-dd HH:mm")
Write-Output "PowerShell Runbook was said at: $($now)"

Begin-Sleep -s 2

Write-Output "Hiya $($Title)!"

I can check the primary perform, by including a brand new schedule, with the next PowerShell script:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$physique = @{
	"StartTime" = "2022-05-20 16:50:00";
	"Description" = "That is only a check schedule";
	"Parameters" = @{
		"Title" = "Christian"
	}
} | ConvertTo-Json

$headers = @{
    "Content material-Kind" = "utility/json"
}

$RunbookName = "test-runbook"
$uri = "http://localhost:7071/api/" + $RunbookName


Invoke-RestMethod -Technique "POST" -Uri $uri -Physique $physique -Headers $headers

The script ought to return the next output:

1
201 - Runbook schedule: automation-3d2a0864, has been registered

I can then check the second perform, to see which schedules I’ve already created with the script under:

1
2
3
4
5
6
7
$headers = @{
    "Content material-Kind" = "utility/json"
}

$uri = "http://localhost:7071/api/RetrieveCurrentScheduledRunbooks"

Invoke-RestMethod -Technique "GET" -Uri $uri -Headers $headers

The perform ought to return an output just like under:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Title         : automation-64f218cc
CreationTime : 20/05/2022 16.25.35
NextRun      : 20/05/2022 16.55.00
TimeZone     : Europe/Paris
Description  : This is simply a check schedule

Title         : automation-9a3de384
CreationTime : 20/05/2022 16.25.25
NextRun      : 20/05/2022 16.50.00
TimeZone     : Europe/Paris
Description  : This is simply a check schedule

Title         : automation-f001ee3c
CreationTime : 20/05/2022 16.25.52
NextRun      : 20/05/2022 17.03.00
TimeZone     : Europe/Paris
Description  : This is simply a check schedule

If I then test my schedules in my Azure Automation account, i can see that the schedule has been created an are able to be executed.

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/scheduling-powershell-automations.png

Including the Azure Operate to Azure API Administration

Earlier than you possibly can make the most of the Azure Operate inside PowerApps, you will want to offer the perform by way of API Administration.

You do that by going into apim after which clicking on APIs. Then click on on “Create from Azure useful resource” and select “Operate App”

Then you possibly can import the capabilities you simply created.

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/azure-api-management-azure-function.png

Setting the right HTTP response for the APIs

Now for the API to work with Microsoft PowerApps, it is very important set the right response. If the request-response just isn’t set accurately PowerApps, don’t know find out how to deal with the API.

Begin by choosing the primary perform “POST AzureAutomationIntegration”, then within the “Frontend part” click on on the edit emblem.

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/editing-azure-api.png

Then go to Responses and click on on “+ Add response”, and choose 201 Created.

Then for the Content material-Kind choose: utility/json

for the pattern you possibly can enter the next JSON:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  "StartTime": "2022-05-20T17:15:00+02:00",
  "ExpiryTime": "2022-05-20T17:15:00+02:00",
  "IsEnabled": true,
  "NextRun": "2022-05-20T17:15:00+02:00",
  "Interval": null,
  "Frequency": 0,
  "MonthlyScheduleOptions": null,
  "WeeklyScheduleOptions": null,
  "TimeZone": "Europe/Paris",
  "ResourceGroupName": "rg-test-automation",
  "AutomationAccountName": "aa-test-automation",
  "Title": "automation-2ab008f0",
  "CreationTime": "2022-05-20T16:53:04.447+02:00",
  "LastModifiedTime": "2022-05-20T16:53:04.447+02:00",
  "Description": "That is only a check schedule"
}

Then press Save

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/editing-azure-api-2.png

then do the identical for the second perform, besides the response must be 200 OK, and the pattern JSON must be:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
[
  {
    "Name": "automation-2ab008f0",
    "CreationTime": "2022-05-20T16:53:04.447+02:00",
    "NextRun": "2022-05-20T17:15:00+02:00",
    "TimeZone": "Europe/Paris",
    "Description": "This is just a test schedule"
  },
  {
    "Name": "automation-56dfaaa2",
    "CreationTime": "2022-05-20T16:52:00.453+02:00",
    "NextRun": "2022-05-20T17:15:00+02:00",
    "TimeZone": "Europe/Paris",
    "Description": "This is just a test schedule"
  }
]

Importing the API into PowerApps as a customized connector

To make it simple to make use of the API, you possibly can import it as a customized connector inside PowerApps. This fashion you possibly can outline the request enter and output to make it simpler to make use of in PowerApps and Energy Automate.

Begin by going to https://powerapps.microsoft.com then click on on “Knowledge” –> “Customized Connectors”. Then click on on “+ New customized connector” and select “Create from Azure Companies”. Then simply choose your subscription, service, service title, and the title of the API.

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/powerapps-custom-connector.png

Now for configuring the customized connector you possibly can go to part “3. Definition”. That is the place you’ll outline you precise requests utilized by PowerApps, for connecting to your API.

To make it simple, you possibly can import a pattern output from a request, then PowerApps will likely be good sufficient to generate the best output.

Scroll down till you discover the “Response” right here click on on the white area.

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/custom-connector-response.png

Then click on on “+ Import from pattern”, right here you need to paste a pattern output into the sector. To get a pattern output you possibly can simply make a request to the API, and copy-paste the output you get.

Instance output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
  "StartTime": "2022-05-22T19:15:00+02:00",
  "ExpiryTime": "2022-05-22T19:15:00+02:00",
  "IsEnabled": true,
  "NextRun": "2022-05-22T19:15:00+02:00",
  "Interval": null,
  "Frequency": 0,
  "MonthlyScheduleOptions": null,
  "WeeklyScheduleOptions": null,
  "TimeZone": "Europe/Copenhagen",
  "ResourceGroupName": "rg-test-automation",
  "AutomationAccountName": "aa-test-automation",
  "Title": "automation-6ee43b79",
  "CreationTime": "2022-05-22T13:40:06.693+00:00",
  "LastModifiedTime": "2022-05-22T13:40:06.693+00:00",
  "Description": "That is only a check schedule"
}

Then click on on the second API endpoint to create an output for it.

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/powerapps-creating-a-custom-connector.png

Once more scroll right down to “Response” and click on on the white discipline. Then click on on “+ Import from pattern”, then paste a pattern of the output from that API endpoint.

Instance output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[
  {
    "Name": "automation-2cb5a2e0",
    "CreationTime": "2022-05-21T07:18:05.48+00:00",
    "NextRun": "2022-05-23T19:33:00+02:00",
    "TimeZone": "Europe/Paris",
    "Description": "Test Description"
  },
  {
    "Name": "automation-68a21212",
    "CreationTime": "2022-05-21T07:20:24.247+00:00",
    "NextRun": "2022-05-23T19:33:00+02:00",
    "TimeZone": "Europe/Paris",
    "Description": "Second test description"
  },
  {
    "Name": "automation-6ee43b79",
    "CreationTime": "2022-05-22T13:40:06.693+00:00",
    "NextRun": "2022-05-22T19:15:00+02:00",
    "TimeZone": "Europe/Copenhagen",
    "Description": "This is just a test schedule"
  }
]

You then save the Customized connector by clicking on “Create Connector.” Now earlier than you possibly can check the connector it is advisable to create a brand new connection. Click on on “+ New connection”, after you clicked on “Create Connector”.

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/powerapps-creating-a-custom-connector2.png

Right here it is advisable to paste in your API key. To get the API key, it is advisable to head over to the Azure Portal, and into your API Administration Service. Within the Menu click on on “Subscriptions”.

Then click on on “+ Add subscription”, give it a Title and Displayname, for the scope choose “API” after which choose the title of your API.

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/api-managemen-subscription.png

After you may have created the Subscription, you possibly can click on on “Present/conceal keys”. Copy the important thing after which paste it into the PowerApp Customized connector.

Your customized connector is now prepared for use in your PowerApp.

Creating the PowerApp

Now I received’t go in-depth on how I’ve created the PowerApp, this half is pretty easy and you will discover lots of sources on-line showcasing find out how to create all of the logic within the app. As a substitute, i’ll simply shortly stroll over the logic I’ve used.

How does it work ?

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/powerapp-example.png

By urgent the button “Replace Desk”, the app will hook up with the API and retrieve all of the scheduled runbooks.

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/example-powerapp2.png

And if you wish to schedule a brand new automation, you possibly can fill out the shape and press the button “Schedule”. The app will present a part of the HTTP response from the API and present it within the Output display screen.

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/example-powerapp3.png

Schedule a brand new automation button

Since I wish to retrieve output from the HTTP request I must create the HTTP request inside a Energy Automate Circulation. All of the stream does is it takes all of the values from the shape within the PowerApp, and ship the info to the API.

To make use of the info from the PowerApp contained in the Circulation, I’ll create a Variable pr Knowledge entry I want to make use of, then for the worth of the variable I’ll choose “Ask in PowerApps”.

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/powerautomate-flow.png

Since i’ve create the API as a customized connector within the PowerApp, I can create a Customized Job for connecting to the API.

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/powerautomate-flow2.png

I then take the Output from the Customized Connector motion and ship it again to the PowerApp

/images/creating-a-powershell-automation-scheduling-app-with-azure-and-microsoft-powerapps/example-powerautomate-flow3.png

Eventually contained in the PowerApp I might want to use the next code, for calling the Energy Automate stream, and saving the response information from the stream, right into a variable. The explanation I’m saving the info in a variable is to have the ability to present the info within the Outputs textual content field.

1
Set(myOutput, ScheduleAzureAutomation.Run(Dropdown1.SelectedText.Worth,txtStartTime.Textual content,txtDescription.Textual content,txtName.Textual content))

Updating the info desk button

To replace the info desk, with the button, it is so simple as utilizing the next code on the button:

Set(myData, 'fa-test-automation'.getretrievecurrentscheduledrunbooks())

after which the info tables “Gadgets” discipline ought to include:

SortByColumns(myData, "NextRun")

This fashion the info desk will present the response from the API name, and type it by date ascending.

Conclusion

This fashion of utilizing a PowerApp to schedule your automation is a quite simple manner of simplifying scheduling PowerShell scripts. This might allow IT, supporters, in your Staff to carry out actions which will in any other case require, information of Servers, Azure, or PowerShell, to have the ability to full all these duties, releasing up your time for different duties.

This app I showcased right here may be improved in many alternative methods. You may create a menu structure for scheduling totally different duties, you might additionally create a button for working the Runbook immediately as a substitute of scheduling it.

One of many issues with this app is that you probably have a number of Runbooks which require totally different parameters, you will want to create a separate stream for the totally different runbooks, and I’d create a sub-screen (or a popup), which contained all of the enter fields for the totally different runbook parameters.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments