Category Archives: Automation

Invoke-WebRequest: The response content cannot be parsed when adapting a local powershell script for Azure Automation.

I have been recently adapting a PowerShell script that collects the Microsoft 365 Service Health using the Office 365 Service Communication API publishing the information into ServiceNow to log a support ticket to make the helpdesk aware of a potential issue in the service. The script was working is no issues when run manually out of PowerShell ISE but failed when ran by Azure Automation.

The focus of this post is to show two specific steps for adapting a locally executed PowerShell script for an Azure Automation runbook. In addition to standard work in Automation to add credentials/connections and create parameters where needed, the following changes were required to adapt a local script for my runbook.

1) Add -UseBasicParsing to Web Requests

The Management API script is filled with various requests using Invoke-WebRequest. Initially, I received numerous errors stating that the Internet Explorer engine is not available.

Invoke-WebRequest : The response content cannot be parsed because the Internet Explorer engine is not available, or 
Internet Explorer's first-launch configuration is not complete. Specify the UseBasicParsing parameter and try again. 
At line:46 char:9
+ $subs = Invoke-WebRequest -Headers $headerParams -Uri "https://manage ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotImplemented: (:) [Invoke-WebRequest], NotSupportedException
    + FullyQualifiedErrorId : WebCmdletIEDomNotSupportedException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

To overcome this, I needed to add the parameter UseBasicParsing.

Original: $oauth = Invoke-RestMethod -Method Post -Uri $loginURL/$tenantdomain/oauth2/token?api-version=1.0 -Body $body
Adapted: $oauth = Invoke-RestMethod -Method Post -Uri $loginURL/$tenantdomain/oauth2/token?api-version=1.0 -Body $body –UseBasicParsing

2) Alter $ProgressPreference

PowerShell shows progress using $ProgressPreference, which defaults to “continue”. For Automation, I needed to change the option to “silently continue” and suppress progress bars. Locally, the progress can be convenient to see, but it was causing issues with

Automation.Adapted: $ProgressPreference = “silentlyContinue”

Regards
The Author – Blogabout.Cloud

Publishing your Microsoft 365 Service Messages to a SharePoint List.

I have been recently working on a solution for a customer whereby they required Microsoft 365 Service Messages to be logged as an incident using a Service Desk tool and publish to Microsoft Teams Channel.

Microsoft Teams – This was the simple bit as a nice person in the community built a PowerShell script available on GitHub.

Now for the publishing the information to SharePoint Online, this has caused quite a few headaches from banging my head on my desk but it now working. The reason for publishing to SharePoint List is so that it can be used / reference as a data source to pulling the information into ServiceNow.

You can bit with Power Automate however the information required and provided is lacking so the route I am going to demostrate provide a lot more details. Just like the Microsoft Teams post

I have been recently working on a solution for a customer whereby they required Microsoft 365 Service Messages to be logged as an incident using a Service Desk tool and publish to Microsoft Teams Channel.

Microsoft Teams – This was the simple bit as a nice person in the community built a PowerShell script available on GitHub.

https://github.com/einast/PS_M365_scripts/blob/master/AzureAutomation/AzO365ServiceHealth.ps1

Now for publishing the information to SharePoint Online, this has caused quite a few headaches from banging my head on my desk but it now works. The reason for publishing to SharePoint List is so that it can be used / reference as a data source to pulling the information into ServiceNow.

You can bit with Power Automate however the information required and provided is lacking so the route I am going to demonstrate provide a lot more details. Just like the Microsoft Teams post

Create the SharePoint Site

The first thing to do is create a SharePoint Site that can be used as the location for the data. This can be simply done by connecting to SharePoint via PowerShell and running the following command.

You will need the following PowerShell Module
https://www.powershellgallery.com/packages/PnP.PowerShell

$URL =  "blogabout.sharepoint.com"
$Admin = "thewatcher@blogabout.cloud"

$cred = (Get-Credential)

Connect-AzureAD -Credential $cred

Connect-PnPOnline -UseWebLogin -Url $url
New-PnPTenantSite -Url $URL -Title "Health Status" -Owner "$Admin" -TimeZone "2"     

We now need to gather some information which will be used later in this blog. Using the same PowerShell console run the following cmdlet

Get-PnPList

Make a note of the Id for Health Status as we will need this later on.

We now need to configure the SharePoint List with required columns for receiving the data.

The column used are;

– Title
– Status
– Severity
– Service
– Classification
– Uri
– Message
– Reference

Modifying your Azure Automation Account for SharePoint Lists

In this post, I will make an assumption that you have already implemented pushing messages to Microsoft Teams. If you havent, please visit this article.

First of you all, we need to add PnP.PowerShell module to this Azure Automation account. Go to Modules under Shared Resources and Browse Gallery.

Search for PnP.PowerShell and click on the module

Click Import

The import may take a few minutes to complete and once complete we can go on to the next step.

Select Credentials from Shared Resources

Important Notice

Some of the next steps I have already completed in my environment.

Click “Add a credential” and provide;

-Name – This is important for the PowerShell script to call the credentials
– Username
– Password

You can also provide a description if required.

It is time to now modify the Runbook with the required PowerShell cmdlets for publishing to SharePoint Lists.

Select your run book to edit the script

Under User-Defined Variables I have added the following;

Please note: I am not using Automated Variables in this script but they could be used if you add the variable and use Get-AutomatedVariable -Name

$SpListName = "Health-Status"
$ListName = "Add the Health Status ID you gathered earlier"
$SpSiteUrl = "https://blogabout.sharepoint.com/sites/$SpListName"

https://pnp.github.io/powershell/articles/authentication.html

$myCred = Get-AutomationPSCredential -Name 'MyCredential'
$userName = $myCred.UserName
$securePassword = $myCred.Password
$password = $myCred.GetNetworkCredential().Password

$SpCreds = New-Object System.Management.Automation.PSCredential ($userName,$securePassword)

As you can see from above I am using Get-AutomationPSCredential -Name MyCredential to call stored credentials.

Under the following PowerShell cmdlet in the script

# If any new posts, add to Teams
Invoke-RestMethod -uri $uri -Method Post -body $Payload -ContentType 'application/json; charset=utf-8'

I have added;

# Add news post to Sharepoint Site
Connect-PnPOnline $SpSiteUrl -Credentials $SpCreds
$list =  Get-PnPList -identity $ListName

Add-PnPListItem -List $list -Values @{"Title"=$inc.Title;"Reference"=$inc.Id;"Status"=$inc.Status;"Severity"=$inc.Severity;
                "Service"=$inc.WorkloadDisplayName;"Classification"=$inc.Classification;"Uri"=$inc.PostIncidentDocumentUrl;"Message"=$Message}

This will now allow you to publish the data to SharePoint as shown below,

I am using Power Automate to trigger the Runbook for more detail visit the below post.

Hopefully this post will help you publish the data to SharePoint.

Regards
The Author – Blogabout.Cloud

Pushing Microsoft Health Status to Microsoft Teams using Azure Automation.

In this post I am going to demostrate how to push Microsoft Health Status to Microsoft Teams using Azure Automation

In this post it is expected you have configured Office 365 Service Communications API. If not, visit this blog post https://www.blogabout.cloud/2020/10/1884/

Configuring Microsoft Teams for Incoming Webhook

Launch Microsoft Teams right click a channel within a Team and select Connectors. Search for Incoming Webhook and click Add

Click Add

Specify the name of the Webhook and click Create

Make a note of the URL below as you will need this for the PowerShell script later and click Done

Create Automation Account

Launch your Azure Portal and search for Automation Account to create a new account.

Specify;
– Name
– Subscription
– Resource Group
– Location

No should be selected for “Create Azure Run As Account” as this is will enable the Account to run against Office 365.
Click Create

Once the resources has successful created, go into the resource

First of all we need to create a number of variables, these variables will use within the PowerShell script we are going to add to the Runbook.

You will need to add the following variables

– AzO365ServiceHealthApplicationID = Client ID
– AzO365ServiceHealthApplicationKey = Client Secrey
– AzO365TeamsURI = This is the url we created earlier in the post
– AzO365TenantDomain = Tenant ID

If you unsure how to obtain these values, please visit this blog post for more details

We now need to launch Runbooks

Select Create a runbook
– Provide a name
– Runbook Type should equal PowerShell
– Description (is optional)

Press Create

I am now going to use the following PowerShell script available from GitHub within my Runbook. https://github.com/einast/PS_M365_scripts. This script has been created for the sole purpose of extracting the Microsoft 365 Service Health using the Office Service Communication API, which I demonstrated how to configure in another post.

Under the “User Defined Variables” you will need to edit;

Mintues to reflect the same time as your schedule.

Pushover notifications and Services to monitor as shown below

# ------------------------------------- USER DEFINED VARIABLES -------------------------------------

$ApplicationID = Get-AutomationVariable -Name 'AzO365ServiceHealthApplicationID'
$ApplicationKey = Get-AutomationVariable -Name 'AzO365ServiceHealthApplicationKey'
$TenantDomain = Get-AutomationVariable -Name 'AzO365TenantDomain'
$URI = Get-AutomationVariable -Name 'AzO365TeamsURI'
$Minutes = '1440'

# Pushover notifications in case Teams is down.
# Due to limitations and readability, the script will only send the title of the incident/advisory to Pushover. 
# COMMENT OUT THIS SECTION IF YOU DON'T WANT TO USE PUSHOVER!

#$Pushover = 'yes' # Comment out if you don't want to use Pushover. I use 'yes' for readability.
#$PushoverToken = Get-AutomationVariable -Name 'AzO365PushoverToken' # Your API token. Comment out if you don't want to use Pushover
#$PushoverUser = Get-AutomationVariable -Name 'AzO365PushoverUser' # User/Group token. Comment out if you don't want to use Pushover
#$PushoverURI = 'https://api.pushover.net/1/messages.json' # DO NOT CHANGE! Default Pushover URI. Comment out if you don't want to use Pushover

# Service(s) to monitor
# Leave the one(s) you DON'T want to check empty (with '' ), add a value in the ones you WANT to check (I added 'yes' for readability)

$ExchangeOnline = 'yes'
$MicrosoftForms = 'yes'
$MicrosoftIntune = 'yes'
$MicrosoftKaizala = 'yes'
$SkypeforBusiness = 'yes'
$MicrosoftDefenderATP = 'yes'
$MicrosoftFlow = 'yes'
$FlowinMicrosoft365 = 'yes'
$MicrosoftTeams = 'yes'
$MobileDeviceManagementforOffice365 = 'yes'
$OfficeClientApplications = 'yes'
$Officefortheweb = 'yes'
$OneDriveforBusiness = 'yes'
$IdentityService = 'yes'
$Office365Portal = 'yes'
$OfficeSubscription = 'yes'
$Planner = 'yes'
$PowerApps = 'yes'
$PowerAppsinMicrosoft365 = 'yes'
$PowerBI = 'yes'
$AzureInformationProtection = 'yes'
$SharePointOnline = 'yes'
$MicrosoftStaffHub = 'yes'
$YammerEnterprise = 'yes'

# Classification(s) to monitor
# Leave the one(s) you DON'T want to check empty (with '' ), add a value in the ones you WANT to check (I added 'yes' for readability)

$Incident = 'yes'
$Advisory = 'yes'

# ------------------------------------- END OF USER DEFINED VARIABLES -------------------------------------

You will now need to define a schedule within the Runbook for it to execute.

Once you have done all of the above, you will receive a nice notification in Microsoft Teams about the Service Health Status

In my next article I will show how simple it is too trigger this Runbook using Power Automate.

Regards
The Author – Blogabout.Cloud

Power Automate: Sending an email when a message is posted in Microsoft Teams

Send an email when a new message is added in Microsoft Teams couldnt be any easier. Power Automate has a defined template which allows to connect with Microsoft Teams and Office 365 Outlook connectors to provide the required functionality. So from you Power Automate dashboard look for the template and press continue.

Define which Microsoft Team you would like to target and the required channel.

Define the email address you want to send the messages to

Important Note

The email address must be an active mailbox within your organisation.

Save….

The next time a message is posted, an email will be sent to the defined mailboxes.

Regards

The Author – Blogabout.Cloud

Syncing of OneDrive Shared Librabies automatically using Microsoft Endpoint Manager

First of all, we need to create Configuration Profile within Microsoft Endpoint Manager, you’ll need to gather the SharePoint document library ID or ID), for all the locations you would like to publish to your Windows 10 Devices. In this blog I am going to publish the Blogabout Cloud Library to all my devices.

A window will now appear, (if you receive any prompts to open OneDrive ignore it), click Copy library ID, keep this handy.

Creating the Configuration Profile

In order to apply the configuration to your Windows 10 devices that are enrolled into Microsoft Endpoint Manager. Launch Microsoft Endpoint Manager go to Devices –> Configuration Profiles –> Create Profile

Select Windows 10 and Administrative Templates

Press Next

Provide a Name for the profile and brief description as shown below

Under Computer Configuration and OneDrive, look for the setting Configure team site libraries to sync automatically

Click Enable
Enter the name you would like to be displayed and the Library ID as shown below

I am now going to recommend a number of other Microsoft OneDrive settings

SettingConfiguration
Silently sign in users to the OneDrive sync app with their Windows credentialsEnabled
Silently move Windows known folders to OneDriveEnabled
Use OneDrive Files On-DemandEnabled
Require user to confirm large delete operationsEnabled
Convert synced team site files to online-only filesEnabled

That completes the Configuration Profile setup, deploy this to your test users before deploying to production.

In my next post I am going to be looking leverage Proactive Remediation to decrease the synchronization time of assigned libraries to the Windows 10 device. The Microsoft default is 8 hours before the assigned libraries are published.

Regard
The Author – Blogabout.Cloud

Power Automate and Microsoft Teams Tips: Automated approach to creating new Microsoft Teams Channels

Over the coming weeks I am going to be doing Power Automate post to demostrate the ability to automate workloads within Microsoft 365. Today, I am going look at configuring an Approval process for the creation of a Microsoft Teams Channel

Configuring a SharePoint List

I am no expert when it comes to SharePoint but any expert in “Share Pint” as how does love a good drink now and then. So back on topic within your SharePoint Online Site you need to create a new list as shown in the image below.

This image has an empty alt attribute; its file name is image-34-1024x404.png

Give your SharePoint List a name and description for future reference.

As you can see from the below, I have create a number of columns to capture the information I would like to include into the approval process.

Column NameColumn Type
Title Title used for the Channel Name.
Team NameName of the Microsoft Team
DescriptionDescription of the new Channel
JustificationJustification for the request

Configuring Power Automate

Create a new Flow from the SharePoint List > Automate > Power Automate > See your Flows

Click New > Automated from blank. Provide a Flow name, i.e. “Request – New Microsoft Teams Channel Provisioning”,

Select your Site Address and List Name as shown below.

Modify the Start an approval in line with your requirements, for this post I have included the layout I have created for my own tenant.

We now need a Data Operation in order to gather the Teams ID which is required to identify the Teams where the channel will be created.

first(split(last(split(triggerBody()['webUrl'],'groupId=')),'&tenantId'))

Add connector List teams and no additional

Create Filter array which looks at the Teams List based on the Team Name against the entry in the SharePoint List.

Next step is to create a channel with uses the apply to each array.

We have now completed the flow, so let’s go and create the request. As shown below.

This will now generate a request to create the team channel automatically in the background and as you can see all the new Project Channels have been created.

Regards,
The Author – Blogabout.Cloud

Power Automate and Microsoft Teams Tips: Posting messages on Teams Channel when a RSS feed published

Over the coming weeks I am going to be doing Power Automate post to demostrate the ability to automate workloads within Microsoft 365. Today, I am going look demostrate how I take RSS feeds from Microsoft Blogs and distrube to Microsoft Teams / To-Do. If you have been following my blog for a while you will know I am a big avocate for bringing code important data from Microsoft into Microsoft Teams. As an Architect working within the Microsoft 365 stack, there is always developments, releases and updates coming from Microsoft.

So how do we handle all this information from multiple sources into Microsoft Teams.

So as you can see from below, I have a Microsoft Team called “Microsoft Blogs” in this Teams. I have seperate channels for the areas I am most interested in;

  • Teams
  • Endpoint Manager
  • etc..

I gather this data from https://techcommunity.microsoft.com/t5/custom/page/page-id/Blogs

For the purpose of this post I am going to be looking at the Microsoft Security and Compliance Blog. This is a blog that I follow today and generates the most noise. So I am going create a new channel called Microsoft Security and Compliance Blog within Microsoft Blogs Teams.

So first of, make sure you create the Channel where you wil be publishing this data. Next we need the RSS URL, so if you click on the RSS button it will open a new tab with the required URL in the address bar

https://techcommunity.microsoft.com/plugins/custom/microsoft/o365/custom-blog-rss?tid=-1974032735906843784&board=MicrosoftSecurityandCompliance&label=&messages=&size=10

Configure Power Automate

Create a new Automated Flow

Provide a new for the Flow and select When a feed item is published

Enter the URL for the RSS Feed

Specify the Team and Channel you would like to publish the message. In my message I am providing a link to the Article, the date is was published, the Title and Summary of the post. The reason for this is so that if I am on the move, I can synchronize the content of the blog post to Microsoft Teams or even Microsoft To-Do so I can continue to read on the move.

When there is a new blog post published you will receive a message into your defined channel, just like the below

Why not To-Do?

So as I mentioned, I also push the blog posts to Microsoft To-Do. The reason for this is so I can close the To-Do item once I have read the article so I never miss any important updates.

You dont even how to stop there if you dont want to. You can leverage what ever connector you want in Power Automate to publish the data.

Regards
The Author – Blogabout.Cloud

Power Automate and Microsoft Teams Tips: Approval request process for a new Microsoft Teams Team

Over the coming weeks I am going to be doing Power Automate post to demostrate the ability to automate workloads within Microsoft 365. Today, I am going look at configuring an Approval process for the creation of a Microsoft Teams Team

Configuring a SharePoint List

I am no expert when it comes to SharePoint but any expert in “Share Pint” as how does love a good drink now and then. So back on topic within your SharePoint Online Site you need to create a new list as shown in the image below.


Give your SharePoint List a name and description for future reference.

As you can see from the below, I have create a number of columns to capture the information I would like to include into the approval process.

Column NameColumn Type
TitleTitle used for the Team Name.
DescriptionSingle line of text used to store the project description.
VisibilityChoice with the following options: “Private” and “Public”. Indicates if a team should visible to non-team members.
OwnersPerson or Group with Allow multiple selections enabled.
MembersPerson or Group with Allow multiple selections enabled.
JustifcationMultiple line of text used

Configuring Power Automate

Create a new Flow from the SharePoint List > Automate > Power Automate > See your Flows

Click New > Automated from blank. Provide a Flow name, i.e. “Request – New Microsoft Teams Team Provisioning”,

Select the SharePoint “When an item is created” trigger and click “Create”.

Select your Site Address and List Name from the drop down lists

Create a Start and wait for an approval condition. I have populated the below with information that I required within my own tenant.

Select Apply to each condition and select responses

Select Responses Approver response is equal to Approve

This section is now a bit more complex as I have decided to include an email notification if the request was a approved or rejected. If you follow the screenshot below you will see that I am using the SharePoint List items to provide Team Name, Description, Visiability fields and leveraging the list to include information into the email notification. You dont need to add email notifications into your flow but this is how you would do it.

Now we need to apply each Owner and Member to the new Microsoft Teams and this is completed as followed.

We have now completed the flow, so lets go and create the request. As shown below.

This will now generate a request to the approvers email address and when they click approve the team will be created as shown below with all the Owners and Members you defined.

Regards,
The Author – Blogabout.Cloud

Bringing Power Automate and Office 365 Service Communications API v2 together to deliver Current Status into Microsoft Teams.

I have been recently looking how to provide the Current Status of the Microsoft 365 stack into an automated process so I could quickly identify any outages. The Office 365 Service Communications API v2 does exactly that and also allows additional options like Power Automate and PowerShell to pull the data. So in this particular article I am going to look at pushing the Current Status into Microsoft Teams so not just myself but anyone who is apart of the Teams is able to see the status.

Prerequisites

  • You have configured Azure AD App for Office 365 Service Communications API v2
  • Licensed for Power Automate either;
    • Per user plan
    • Per user plan with attended RPA
    • Per Flow plan

Configuring Power Automate to deliver posts into Microsoft Teams Channel.

You will now need to repeat the above process for client_secret and tenantid

After that, you need to create an HTTP action to query the Office 365 API. Populate the same as below, making sure all 3 variables are used.

Please be aware the HTTP Connector has an associated cost due to being a Premium Connector. This cost can be found at the following link

If you were to run the flow at this point it would return a big output of JSON. It’s best to use the Parse JSON action to make it easier to read. Set the Content as the Body of the previous HTTP action and the Schema below:


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
{
    "type": "object",
    "properties": {
        "@@odata.context": {
            "type": "string"
        },
        "value": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "FeatureStatus": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "FeatureDisplayName": {
                                    "type": "string"
                                },
                                "FeatureName": {
                                    "type": "string"
                                },
                                "FeatureServiceStatus": {
                                    "type": "string"
                                },
                                "FeatureServiceStatusDisplayName": {
                                    "type": "string"
                                }
                            },
                            "required": [
                                "FeatureDisplayName",
                                "FeatureName",
                                "FeatureServiceStatus",
                                "FeatureServiceStatusDisplayName"
                            ]
                        }
                    },
                    "Id": {
                        "type": "string"
                    },
                    "IncidentIds": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "Status": {
                        "type": "string"
                    },
                    "StatusDisplayName": {
                        "type": "string"
                    },
                    "StatusTime": {
                        "type": "string"
                    },
                    "Workload": {
                        "type": "string"
                    },
                    "WorkloadDisplayName": {
                        "type": "string"
                    }
                },
                "required": [
                    "FeatureStatus",
                    "Id",
                    "IncidentIds",
                    "Status",
                    "StatusDisplayName",
                    "StatusTime",
                    "Workload",
                    "WorkloadDisplayName"
                ]
            }
        }
    }
}

Once the data has been parsed, you can loop through each service and check for service status. The next action is to add an Apply to each action for the value variable.

Within the loop, add a Group Condition that Status is equal to ServiceOperational and ServiceRestored.

Under the If No condition, you can add an action because the service is not operational. To demonstrate, I’ve configured steps for posting a message to Microsoft Teams as shown below

This will then be triggered when there is any status that doesn’t match the define ServiceOperational or ServiceRestored within Office 365. As you can see below I have been notified in Microsoft Teams for an issue with Microsoft 365 stack.

Regards
The Author – Blogabout.Cloud

Making your PowerShell script self elevate to run as an Administrator

I have been recently running a number of PowerShell scripts where I required to elevate the session to Administrator. Ideally I didnt want to have to provide logon details everytime, so the following script removed the need to provide Admin credentials.

# Get the ID and security principal of the current user account
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)

# Get the security principal for the Administrator role
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator

# Check to see if we are currently running "as Administrator"
if ($myWindowsPrincipal.IsInRole($adminRole))

   {
   # We are running "as Administrator" - so change the title and background color to indicate this
   $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)"
   $Host.UI.RawUI.BackgroundColor = "DarkBlue"
   clear-host

   }
else
   {
   # We are not running "as Administrator" - so relaunch as administrator

   # Create a new process object that starts PowerShell
   $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";

   # Specify the current script path and name as a parameter
   $newProcess.Arguments = $myInvocation.MyCommand.Definition;

   # Indicate that the process should be elevated
   $newProcess.Verb = "runas";

   # Start the new process
   [System.Diagnostics.Process]::Start($newProcess);

   # Exit from the current, unelevated, process
   exit

   }

Regards
The Author – Blogabout.Cloud