<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>CloudLojik</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/cloudlojik/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/cloudlojik/feed.xml</link>
    <description>CloudLojik</description>
    <lastBuildDate>Tue, 10 Jul 2018 14:47:35 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>How To Install the MSOnline PowerShell Module</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudlojik/how-to-install-the-msonline-powershell-module</link>
      <pubDate>Mon, 02 Jul 2018 22:23:14 GMT</pubDate>
      <dc:creator><![CDATA[PaulKotylo]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudlojik/?p=415</guid>
      <description><![CDATA[Introduction
In recent months, Microsoft has changed the distribution method for the MSOnline...]]></description>
      <content:encoded><![CDATA[<h1>Introduction</h1>
In recent months, Microsoft has changed the distribution method for the MSOnline PowerShell Modules from the use of the .msi self-contained download to exclusively having it installed from the Online Gallery via the Install-Module cmdlets. Unfortunately, not every Windows-based operating system that you might be working from has the latest and greatest version of PowerShell, let alone an even fairly up-to-date version and you may find yourself in a situation where you cannot run Install-Module. The purpose of this article is to help you get going quickly using PowerShellGet/Install-Module Cmdlets on operating system that does not already have it available.
<h1>Pre-requisites</h1>
In order to install any module though the user of the <a href="https://docs.microsoft.com/en-us/powershell/module/powershellget/install-module?view=powershell-6">Install-Module</a> cmdlet you must be running an Operating System that supports PowerShell Version 3.0 or Greater (<span>Windows 7, Windows Server 2008 R2 and later releases of Windows and Windows Server</span>). Depending on the age of your Operating System build, even if it does lie within those parameters, it may not currently have PowerShell Version 3.0+ installed. To check which version of PowerShell you are currently running, open PowerShell and run:
<pre class="brush: java">$PSVersionTable.PSVersion
Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      17134  137
</pre>
The 'Major' is really the primary focus, if it does not say "3" or greater, the Install-Module cmdlets are not available but they can be 'downloaded' or 'installed' through the Windows Management Framework package(s):
<pre class="brush: java"><a href="https://aka.ms/wmf3download">Windows Management Framework 3.0</a>
<a href="https://aka.ms/wmf4download">Windows Management Framework 4.0</a>
<a href="https://aka.ms/wmf5download">Windows Management Framework 5.1</a>
</pre>
<h1>Setup</h1>
<span style="float: none;background-color: transparent;color: #333333;cursor: text;font-family: Georgia,'Times New Roman','Bitstream Charter',Times,serif;font-size: 16px;font-style: normal;font-variant: normal;font-weight: 400;letter-spacing: normal;line-height: 24px;text-align: left;text-decoration: none;text-indent: 0px">Once with Windows Management Framework has been installed, all you simply need to do is open a <strong>new</strong> PowerShell window and execute Install-Module MSOnline, Install-Module AzureAD or any other module that is available through the <a href="https://www.powershellgallery.com/">PowerShell Gallery</a> and you'll be on your way.</span>]]></content:encoded>
    </item>
    <item>
      <title>Connecting to Microsoft Graph with a Native App using PowerShell</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudlojik/connecting-to-microsoft-graph-with-a-native-app-using-powershell</link>
      <pubDate>Fri, 29 Jun 2018 13:09:34 GMT</pubDate>
      <dc:creator><![CDATA[PaulKotylo]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudlojik/?p=285</guid>
      <description><![CDATA[Introduction
Over the last few months, Microsoft has tightened security measures and has (or is at...]]></description>
      <content:encoded><![CDATA[<h1>Introduction</h1>
Over the last few months, Microsoft has tightened security measures and has (or is at least starting to) deprecate the use of the well-known ClientID that many of use have grown accustom to using in our Microsoft Graph scripts. I had spent countless hours trying to figure out exactly how I can create my own app and had a heck of a time trying to find any information. This blog post is designed to disambiguate the creation of your own ClientID for use with Microsoft Graph and execute a Microsoft Graph query using PowerShell and your own ClientID. In addition to this, this script supports querying Microsoft Graph when MFA is enforced in the organization.
<h1>Pre-requisites</h1>
The easy way is to use the PowerShell Gallery to install the Azure module.
<pre class="brush: java">Install-Package Azure</pre>
<strong>Note</strong>: When I was developing this script originally, it ran without any issue with the AccessToken function which was throwing the following error:
<pre class="brush: java">Cannot find an overload for 'AcquireTokenAsync' and the argument count: '4' 
</pre>
After further investigation, the version of the ADAL library that was in the AzureAD modules had a bug in Version 3.18 (version 3.17 worked fine and the current version 3.19 works as well). It was until I removed the AzureAD module and reinstalled it (to pull down the latest version) that I overcame this problem. To determine the version of the ADAL libraries you have installed, you can do the following:
<pre class="brush: java">$AadModule = Get-Module -Name "AzureAD" -ListAvailable
if ($AadModule.count -gt 1) {
    $Latest_Version = ($AadModule | select version | Sort-Object)[-1]
    $aadModule      = $AadModule | ? { $_.version -eq $Latest_Version.version }
    $adal           = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
    }
else {$adal           = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"}
[System.Reflection.Assembly]::LoadFrom($adal) | Select FullName
</pre>
It should output something like this. Take note of the "Version=" value:
<pre class="brush: java">Microsoft.IdentityModel.Clients.ActiveDirectory, Version=3.19.7.16602
</pre>
<h1>Setup</h1>
<h2>Creating a Native App</h2>
First and foremost, you’ll need to log in to <a href="https://portal.azure.com/">https://portal.azure.com</a> and create an <a href="https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps">App registration</a> by going to Azure Active Directory | App registrations | + New application registration:

<a href="https://msdnshared.blob.core.windows.net/media/2018/06/P1.png"><img width="1024" height="969" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/06/P1-1024x969.png" /></a>

&nbsp;

Once you select ‘create’, you will be prompted to set a Name of the app. The App name can be anything you want, its just a friendly name for you to refer to if you need to modify its settings later. The Application type should be “Native” and the Redirect URI can be any URL. It doesn’t matter if you own the domain or if it is an active URL, it can literally be anything you want it to be, you’ll just need to take note of it later when you update the logic in your script.
<ul>
 	<li>Name: MicrosoftGraphNativeApp</li>
 	<li>Application Type: Native</li>
 	<li>Redirect URI: https://redirecturi.com</li>
</ul>
<a href="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphP2.png"><img width="736" height="350" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphP2.png" /></a>

&nbsp;

Once the application is created, you’ll be taken back to the App registration page. If you do not see your newly created app, make sureyou select “All apps” from the drop down and search for it there. Since you are not defined as an owner of the app yet, it may not be displayed. Next, take note of the Application ID, this is the value you’ll use for the ClientID in your script. Note: the ClientID I have listed here is unique for my environment, it will not work for you (in fact, this Application ID will be deleted before this blog is posted).

Now that it is created, select the App so we can configure some additional settings, so you can take advantage of it.

<a href="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphP3.png"><img width="1024" height="969" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphP3-1024x969.png" /></a>

&nbsp;

Select Settings | Owners | + Add owner | add anyone that should be an owner of this App. Setting an “Owner” will allow for it to so up when you filter “My Apps” in the App registration section.

<a href="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphP4.png"><img width="1024" height="713" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphP4-1024x713.png" /></a>

&nbsp;

When an App is created, by default it has rights to access only the data of the user that had signed in with the account though the “Sign in and read user profile” delegated permissions. If you try to execute a script that uses this AppID/ClientID to query Azure AD to get a list of all users in the directory, you would receive an error stating (403) Forbidden because it didn’t have adequate permissions to do that activity.

Invoke-RestMethod : The remote server returned an error: (403) Forbidden.

<a href="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphP5.png"><img width="1024" height="715" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphP5-1024x715.png" /></a>

&nbsp;

Next, we will want to assign permissions to the App so that is has adequate rights to perform the tasks you need to. Depending on what kind of activities (get, post, patch) you will need to do against a specific service, you’ll need to delegate the rights to it accordingly. In this case, we want to query Azure Active Directory (Azure AD) to return a list of all users in the directory and we also want to update a user’s department name. Because we want to query users in Azure AD, we want to select the Microsoft Graph API.

<a href="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphP6.png"><img width="1024" height="717" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphP6-1024x717.png" /></a>

&nbsp;

Next, since we want to query all users and update certain user’s department information, we will want to enable the application to have delegated right to “Read and write directory data”:

<a href="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphP7.png"><img width="1024" height="717" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphP7-1024x717.png" /></a>

&nbsp;

Once the delegated permissions are selected, you’ll need to select “Grant Permissions” for them to be assigned to the App:

<a href="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphP8.png"><img width="1024" height="849" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphP8-1024x849.png" /></a>
<h2></h2>
<h2>Creating the AccessToken Function</h2>
This function is fed parameters from the body of the script, so nothing needs to be modified within it. The function first loads all of the approperiate .DLLs for ADAL/ModernAuth in support of features like MFA/2FA (Multi-factor Authentication aka Two-factor Authentication).  Added to this function is a feature that allows you to control the authentication mechanism to Microsoft Graph, so that if a valid token already exists, it will use it - unless you tell it otherwise (auto v. always).
<pre class="brush: java">Function Get-AccessToken ($TenantName, $ClientID, $redirectUri, $resourceAppIdURI, $CredPrompt){
    Write-Host "Checking for AzureAD module..."
    if (!$CredPrompt){$CredPrompt = 'Auto'}
    $AadModule = Get-Module -Name "AzureAD" -ListAvailable
    if ($AadModule -eq $null) {$AadModule = Get-Module -Name "AzureADPreview" -ListAvailable}
    if ($AadModule -eq $null) {write-host "AzureAD Powershell module is not installed. The module can be installed by running 'Install-Module AzureAD' or 'Install-Module AzureADPreview' from an elevated PowerShell prompt. Stopping." -f Yellow;exit}
    if ($AadModule.count -gt 1) {
        $Latest_Version = ($AadModule | select version | Sort-Object)[-1]
        $aadModule      = $AadModule | ? { $_.version -eq $Latest_Version.version }
        $adal           = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
        $adalforms      = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
        }
    else {
        $adal           = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
        $adalforms      = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
        }
    [System.Reflection.Assembly]::LoadFrom($adal) | Out-Null
    [System.Reflection.Assembly]::LoadFrom($adalforms) | Out-Null
    $authority          = "https://login.microsoftonline.com/$TenantName"
    $authContext        = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
    $platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters"    -ArgumentList $CredPrompt
    $authResult         = $authContext.AcquireTokenAsync($resourceAppIdURI, $clientId, $redirectUri, $platformParameters).Result
    return $authResult
    }
</pre>
<h2></h2>
<h2>Creating the Invoke-MSGraphQuery Function</h2>
The second function is what performs the REST query itself.  This handles both GET and PATCH requests. If it is a PATCH request, JSON must be passed in order to take approperiate PATCH activities.
<pre class="brush: java">Function Invoke-MSGraphQuery($AccessToken, $Uri, $Method, $Body){
    Write-Progress -Id 1 -Activity "Executing query: $Uri" -CurrentOperation "Invoking MS Graph API"
    $Header = @{
        'Content-Type'  = 'application\json'
        'Authorization' = $AccessToken.CreateAuthorizationHeader()
        }
    $QueryResults = @()
    if($Method -eq "Get"){
        do{
            $Results =  Invoke-RestMethod -Headers $Header -Uri $Uri -UseBasicParsing -Method $Method -ContentType "application/json"
            if ($Results.value -ne $null){$QueryResults += $Results.value}
            else{$QueryResults += $Results}
            write-host "Method: $Method | URI $Uri | Found:" ($QueryResults).Count
            $uri = $Results.'@odata.nextlink'
            }until ($uri -eq $null)
        }
    if($Method -eq "Patch"){
        $Results =  Invoke-RestMethod -Headers $Header -Uri $Uri -Method $Method -ContentType "application/json" -Body $Body
        write-host "Method: $Method | URI $Uri | Executing"
        }
    Write-Progress -Id 1 -Activity "Executing query: $Uri" -Completed
    Return $QueryResults
    }
</pre>
<h2></h2>
<h2>Configuring the Script Parameters</h2>
The script requires a number of parameters. The values below are provided for reference however, they will need to be updated to reflect the attributes of your AppID/ClientID.

The ClientID (39b7009d-46c2-4807-9a45-0b34dee40c9c) is the Application ID from the App that we created at the beginning of this article. This value is unique to your application and cannot be reused from one tenant to another.

The Tenant Name (Cloudlojik.onmicrosoft.com) is the name of the tenant that the ClientID belongs to and is ultimately the tenant the you will be querying.

CredPrompt determines how frequently you are prompted for your credentials. If it is set to Always, each time you run the script, you will be required to reenter your credentials. if it is set to Auto, only once the current sessions token expires, you'll be prompted for credentials once more.
<pre class="brush: java">$resourceAppIdURI = "https://graph.microsoft.com"
$ClientID         = "39b7009d-46c2-4807-9a45-0b34dee40c9c"   #AKA Application ID
$TenantName       = "cloudlojik.onmicrosoft.com"             #Your Tenant Name
$CredPrompt       = "Auto"                                   #Auto, Always, Never, RefreshSession
$redirectUri      = "https://RedirectURI.com"                #Your Application's Redirect URI
$Uri              = "https://graph.microsoft.com/beta/users" #The query you want to issue to Invoke a REST command with
$Method           = "Get"                                    #GET or PATCH
$AccessToken      = Get-AccessToken -TenantName $TenantName -ClientID $ClientID -redirectUri $redirectUri -resourceAppIdURI $resourceAppIdURI -CredPrompt $CredPrompt
$JSON = @" 
    {
    "userPrincipalName": "MCC-MigAdmin01@cloudlojik.onmicrosoft.com"
    }
"@ #JSON Syntax if you are performing a PATCH
</pre>
<h1></h1>
<h1>Execution</h1>
Finally, Invoke-MSGraphQuery will execute the REST requests you are trying to perform and in my case, provided these (abbreviated) results:
<pre class="brush: java">Invoke-MSGraphQuery -AccessToken $AccessToken -Uri $Uri -Method $Method -Body $JSON

PS C:\Users\paulkot&gt; C:\PowerShellCommandCenter\Testing\CloudLojikGraphQuery.ps1
Checking for AzureAD module...
Method: Get | URI https://graph.microsoft.com/beta/users | Found: 100
Method: Get | URI https://graph.microsoft.com/beta/users?$skiptoken=X%.........%27 | Found: 200
Method: Get | URI https://graph.microsoft.com/beta/users?$skiptoken=X%.........%27 | Found: 300
Method: Get | URI https://graph.microsoft.com/beta/users?$skiptoken=X%.........%27 | Found: 313

id                             : bf14124a-35ac-4079-9a5b-07637e337665
deletedDateTime                : 
accountEnabled                 : True
ageGroup                       : 
businessPhones                 : {}
city                           : 
createdDateTime                : 2017-09-06T16:57:02Z
companyName                    : 
consentProvidedForMinor        : 
country                        : 
department                     : 
displayName                    : Admin
employeeId                     : 
givenName                      : 
jobTitle                       : 
legalAgeGroupClassification    : 
mail                           : admin@cloudlojik.com
mailNickname                   : admin
mobilePhone                    : 
onPremisesDomainName           : cloudlojik.com
onPremisesImmutableId          : GJAMfUzDmkWWTKVSxcZr3A==
onPremisesLastSyncDateTime     : 2017-09-06T17:57:07Z
onPremisesSecurityIdentifier   : S-1-5-21-3133886935-1569346377-3125956357-5104
onPremisesSamAccountName       : admin
onPremisesSyncEnabled          : True
onPremisesUserPrincipalName    : admin@cloudlojik.com
passwordPolicies               : DisablePasswordExpiration
passwordProfile                : 
officeLocation                 : 
postalCode                     : 
preferredDataLocation          : 
preferredLanguage              : 
proxyAddresses                 : {x500:/o=ExchangeLabs/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=07c0a25fdaa846eab6f23051fa695d67-Admin, X500:/o=CloudlojikExchange/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=Admin688, smtp:admin@cloudlojik.onmicrosoft.com, smtp:admin@cloudlojik.mail.onmicrosoft.com...}
refreshTokensValidFromDateTime : 2017-09-06T16:33:40Z
showInAddressList              : 
imAddresses                    : {}
state                          : 
streetAddress                  : 
surname                        : 
usageLocation                  : 
userPrincipalName              : admin@cloudlojik.com
userType                       : Member
assignedLicenses               : {}
assignedPlans                  : {}
deviceKeys                     : {}
onPremisesExtensionAttributes  : @{extensionAttribute1=; extensionAttribute2=; extensionAttribute3=; extensionAttribute4=; extensionAttribute5=; extensionAttribute6=; extensionAttribute7=; extensionAttribute8=; extensionAttribute9=; extensionAttribute10=; extensionAttribute11=; extensionAttribute12=; extensionAttribute13=; extensionAttribute14=; 
                                 extensionAttribute15=}
onPremisesProvisioningErrors   : {}
provisionedPlans               : {}
</pre>
Screenshot for reference:

<a href="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphScriptScreenshot.png"><img width="300" height="224" class="alignnone wp-image-375 size-medium" alt="" src="https://msdnshared.blob.core.windows.net/media/2018/06/MSGraphScriptScreenshot-300x224.png" /></a>

You can download the sample script in its entirety here:
<a href="https://msdnshared.blob.core.windows.net/media/2018/06/QueryGraphWithMFA.ps1_.txt">QueryGraphWithMFA.ps1.txt</a>

&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>Using Export-CSV in Azure Automation</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudlojik/using-export-csv-in-azure-automation</link>
      <pubDate>Wed, 13 Sep 2017 12:21:47 GMT</pubDate>
      <dc:creator><![CDATA[PaulKotylo]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudlojik/?p=216</guid>
      <description><![CDATA[Introduction

Whether you are just getting started with Azure Automation or you are pretty well in...]]></description>
      <content:encoded><![CDATA[<h1>Introduction<span style="font-size: 24pt">
</span></h1>
Whether you are just getting started with Azure Automation or you are pretty well in tune with it, there will likely come a point where you will want to capture the output of your scripts to a CSV. With Azure Automation, your scripts are run in a virtual environment and when you output your data to a file/csv it will only be saved in that temporary instance from where that script was executed. After the script is complete, that data that you 'thought' was going to persist is deleted. In order to capture that information and persist it you have to save it to an external environment. You do have a few options, but the most cost effective and intuitive approach is to save it to a blob storage account.
<h1>Prerequisites</h1>
<ol>
 	<li>Azure RM Module must be installed in Azure Automation. You can accomplish this by going to the <a href="https://www.powershellgallery.com/packages/AzureRM/4.3.1">PowerShell Gallery</a> and having it "Deploy[ed] to Azure Automation"</li>
 	<li>Azure RM Module installed on your local workstation. If your running PowerShell 3.0 or later, you can run Install-Package AzureRM as an administrator.</li>
 	<li>Azure Subscription</li>
</ol>
<h1>How To</h1>
<h2>Creating a Storage Account</h2>
<ol>
 	<li>
<div>First create a Storage Account. If you don't already have one, you'll to connect to Azure Resource Manager through your local PowerShell client:</div>
<pre class="brush: java">Login-AzureRmAccount
</pre>
</li>
 	<li>
<div>Once you have authenticated, ensure that you are connected to the correct subscription. You can view your subscriptions but using Get-AzureRmSubscription.</div>
<pre class="brush: java">Get-AzureRmSubscription -SubscriptionName "Office 365 Test and Validations" | Select-AzureRmSubscription
    Environment           		: AzureCloud
    Account               		: paul@domain.com
    TenantId             		: 72f988bf-86f1-41af-91ab-212cd011db47
    SubscriptionId        		: 1edb6f86-8931-40e4-a70e-d2128ce0ee32
    SubscriptionName      		: Microsoft Azure Internal Consumption
    CurrentStorageAccount 		:
</pre>
</li>
 	<li>
<div>Next you'll want to create a Storage Account:</div>
<pre class="brush: java">New-AzureRmStorageAccount -SkuName “&lt;"Standard_LRS,Standard_ZRS,Standard_GRS,Standard_RAGRS,Premium_LRS"&gt; -ResourceGroupName  -Name  -Location 
Sample: New-AzureRmStorageAccount -SkuName "Standard_LRS” -ResourceGroupName CloudLogicRG -Name clstorageacct -Location “Central US”
</pre>
</li>
 	<li>And finally, create a Storage Account Container:
<pre class="brush: java">New-AzureStorageContainer -Name "savedfiles"
</pre>
</li>
</ol>
<h2>Setting up Automation to Export to CSV</h2>
<ol>
 	<li>
<div>Now that the foundation is established, you'll want to create a new Runbook of the type "PowerShell".</div>
<img alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/091317_1954_UsingExport1.png" /></li>
 	<li>
<div>Connect to AzureRM with a Service Principal Account</div>
<pre class="brush: java">$connectionName = "AzureRunAsConnection"
try
{
    # Get the connection "AzureRunAsConnection "
    $servicePrincipalConnection=Get-AutomationConnection -Name $connectionName         

    "Logging in to Azure..."
    Add-AzureRmAccount `
        -ServicePrincipal `
        -TenantId $servicePrincipalConnection.TenantId `
        -ApplicationId $servicePrincipalConnection.ApplicationId `
        -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint 
}
catch {
    if (!$servicePrincipalConnection)
    {
        $ErrorMessage = "Connection $connectionName not found."
        throw $ErrorMessage
    } else{
        Write-Error -Message $_.Exception
        throw $_.Exception
    }
}
</pre>
</li>
 	<li>
<div>Select the subscription you are going to work with</div>
<pre class="brush: java">Select-AzureRmSubscription -SubscriptionId '&lt;SubscriptionID&gt;'
</pre>
</li>
 	<li>
<div>Set the Current Storage Account to the approperiate location</div>
<pre class="brush: java">Set-AzureRmCurrentStorageAccount -StorageAccountName  -ResourceGroupName 
</pre>
</li>
 	<li>
<div>Store O365 Credentials – For sake of clarity, we are storing the credentials in a variable. For security reasons, it is best to securely store the credentials and call them when required.</div>
<pre class="brush: java">$MSOUser = "@.onmicrosoft.com"
$MSOPwd = ConvertTo-SecureString -String "" -AsPlainText -Force
$MSOCred = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $MSOUser, $MSOPwd
</pre>
</li>
 	<li>
<div>Connect to Office 365</div>
<pre class="brush: java">Connect-MsolService –Credential $MSOCred
</pre>
</li>
 	<li>
<div>Capture All MSOLUsers in a variable</div>
<pre class="brush: java">$users=get-msoluser -All
</pre>
</li>
 	<li>
<div>Export CSV to Local Automation Storage</div>
<pre class="brush: java">foreach ($user in $users){
    write $user
    $user | export.csv $FileName -NoTypeInformation -Append
}
</pre>
</li>
 	<li>
<div>Capture the file that is local to automation and save to Storage Blob</div>
<pre class="brush: java">Set-AzureStorageBlobContent -Container savedfiles -File AutomationFile.csv -Blob SavedFile.csv
</pre>
</li>
</ol>
<h2>Notes</h2>
<ul>
 	<li>The real magic is done with the very last cmdlet "Set-AzureStorageBlobContent -Container savedfiles -File AutomationFile.csv -Blob SavedFile.csv". The container should be the name of the container that you are saving the file to; in association to the Storage Account your connected to. -File is the name of the local (to the automation) file you wish to make a copy of and the -Blob will be the (new) name of the file that is created in the container.</li>
 	<li>You can use <a href="https://azure.microsoft.com/en-us/features/storage-explorer/">Microsoft Storage Explorer </a>to view the content of the storage account and download the blobs</li>
 	<li>To download the full Automation Script please see: <a href="https://msdnshared.blob.core.windows.net/media/2017/09/AzureAutomationExportCSV.txt">AzureAutomationExportCSV</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Licensing Office 365 Users with PowerShell – Licensing Helper</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudlojik/licensing-office-365-users-with-powershell-licensing-helper</link>
      <pubDate>Fri, 08 Sep 2017 13:04:03 GMT</pubDate>
      <dc:creator><![CDATA[PaulKotylo]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudlojik/?p=115</guid>
      <description><![CDATA[Introduction
Time and time again I've worked with customers that have challenges with figuring out...]]></description>
      <content:encoded><![CDATA[<h1>Introduction</h1>
Time and time again I've worked with customers that have challenges with figuring out how to correctly license users in Office 365; more so, how to construct the disabled plans licensing string. Given the challenges of general know-how required to figure out how to make these strings, I've taken the liberty of creating a friendly UI to help you on your journey.
<h1>Prerequisites</h1>
<ol>
 	<li>I've only tested this with PowerShell version 3.0 and later, the script may require additional modification of you are using an older version</li>
 	<li>MSOnline PowerShell module installed.</li>
 	<li>Office 365 Admin account that has the RBAC rights run access: Get-MSOLAccountSku</li>
</ol>
<h1>How To</h1>
Download the Office 365 User Licensing Helper PowerShell script and run it in PowerShell. When you execute the script, it will first check the PowerShell version and to if the correctly PowerShell modules are installed.

<img alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/090817_1801_LicensingOf1.png" />

If everything is validated successfully, a windows form will appear that will look like this:

<img alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/090817_1801_LicensingOf2.png" />

In this case, I only want to the users to be licensed for Exchange Online, Skype for Business Online and SharePoint Online:

<img alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/090817_1801_LicensingOf3.png" />

Once you have selected the licenses to enable, select "okay" and PowerShell output your selections, the disabled plans string and a sample script:<img alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/090817_1801_LicensingOf4.png" />
<h2>Notes</h2>
<ul>
 	<li>"Services available for this selection" indicate what plans are available for the selected SKU.</li>
 	<li>"Services that will be disabled" list only the plans will not be available for the users. Under "initializing" you can find the plans that you selected that will be available</li>
 	<li>If you select plans from more than a single SKU, the script will output separate sections per SKU.</li>
 	<li>Be sure to review the number of SKUs (subscriptions) available before you attempt to license users. Its important to always plan ahead and procure enough licenses to cover to current users as well as your plans mid-term organizational growth – the last think you want to is scramble to get additional licenses at the last minute.</li>
 	<li>If you receive an error when you execute your licensing script, be sure to review the disabled plans string (-disabledplans). In some circumstances if a plan that you are trying to keep enabled has a dependency that is being disabled, it will fail.</li>
</ul>
You can download the full script here: <a href="https://msdnshared.blob.core.windows.net/media/2017/09/Licensing_Helper-v1.0.txt">Licensing_Helper-v1.0</a>]]></content:encoded>
    </item>
    <item>
      <title>Using PowerShell to Connect to Microsoft Graph API</title>
      <link>https://docs.microsoft.com/archive/blogs/cloudlojik/using-powershell-to-connect-to-microsoft-graph-api</link>
      <pubDate>Tue, 05 Sep 2017 15:00:33 GMT</pubDate>
      <dc:creator><![CDATA[PaulKotylo]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/cloudlojik/?p=46</guid>
      <description><![CDATA[Update 6.29.2018: Changes have been make to the functionality of the well-known ClientIDs that are...]]></description>
      <content:encoded><![CDATA[<span style="font-family: Times New Roman;font-size: 18pt"><strong>Update 6.29.2018:</strong> Changes have been make to the functionality of the well-known ClientIDs that are referred to in this article. Further information <a href="https://blogs.technet.microsoft.com/cloudlojik/2018/06/29/connecting-to-microsoft-graph-with-a-native-app-using-powershell/">can be found here</a>, along with guidance on how to create your own Native application which could be configured to have similar functionality to the well-known ClientIDs.</span>
<h1>Introduction</h1>
<span style="font-family: Times New Roman;font-size: 12pt">In this article I will show you how to connect to Microsoft Graph and query for <em>all</em> users in Azure AD. With Microsoft Graph, you can only return between 1 and 999 objects, per query. If your Azure AD object count is greater than 999, you will need to construct a loop that will capture the next set(s) of users using the .nextlink approach.</span>
<h1>Pre-requisites</h1>
<span style="font-family: Times New Roman;font-size: 12pt">The easy way is to use the PowerShell Gallery to install the Azure module.</span>
<pre class="brush: java">Install-Package Azure</pre>
<span style="font-family: Times New Roman;font-size: 12pt">
</span>
<h1>Setup</h1>
<h2>Creating the AuthToken a Function</h2>
<span style="font-family: Times New Roman;font-size: 12pt">While creating a function is by no means required, it will make your life easier.
</span>

<span style="font-family: Times New Roman;font-size: 12pt">Its important to note that the </span><span style="color: orangered;font-family: Lucida Console;font-size: 9pt">$resourceAppIdURI </span><span style="font-family: Times New Roman;font-size: 12pt">is for graph.microsoft.com instead of graph.windows.net. using Graph.microsoft.com will direct you to Microsoft Graph where as Graph.windows.net will direct you to Azure AD Graph API. As outlined by the <a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-graph-api">Microsoft Azure team</a>, their efforts are concentrated on Microsoft Graph. While there are scenarios that Azure AD Graph may be approperiate, my efforts (at least in this article) will be focused on Microsoft Graph.
</span>
<pre class="brush: java">Function GetAuthToken
    {
    param
        (
        [Parameter(Mandatory=$true)]
        $TenantName
        )
    Import-Module Azure
    $clientId = "1950a258-227b-4e31-a9cf-717495945fc2" 
    $redirectUri = "urn:ietf:wg:oauth:2.0:oob"
    $resourceAppIdURI = "https://graph.microsoft.com"
    $authority = "https://login.microsoftonline.com/$TenantName"
    $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
    $Credential = Get-Credential
    $AADCredential = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential" -ArgumentList $credential.UserName,$credential.Password
    $authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId,$AADCredential)
    return $authResult
    }
</pre>
<span style="font-family: Times New Roman;font-size: 12pt">
</span>
<h2>Creating the GetAllObjectOfType Function</h2>
<span style="font-family: Times New Roman;font-size: 12pt">One of the challenges with Microsoft Graph is that it doesn't inherently have a process to capture every object in Azure AD like Get-MSOLuser does. Because of this, we have to construct a batch process that will create the initial URI. Once that is constructed and executed, we have to capture the "nextlink" to create a call that will allow us to query the next batch of the data set until there is nothing left to query. If you were to run this function without the Do-Until, you would return the initial batch set (default 100 objects) and halt processing.
</span>
<pre class="brush: java">Function GetAllObjectOfType
    {
    param
        (
        [Parameter(Mandatory=$true)]
        $Tenant,
        [Parameter(Mandatory=$true)]
        $Type,
        [Parameter(Mandatory=$false)]
        $BatchSize,
        [Parameter(Mandatory=$false)]
        $Version
        )
  
    if($BatchSize -eq $null) {$BatchSize=100}
    if($Version -eq $null) {$Version='Beta'}
    #------Get the authorization token------#
    $token = GetAuthToken -TenantName $tenant 
  
    #------Building Rest Api header with authorization token------#
    $authHeader = @{
        'Content-Type'='application\json'
        'Authorization'=$token.CreateAuthorizationHeader()
        }

    #------Initial URI Construction------#
    $uri = "https://graph.microsoft.com/$Version/$type`?top=$BatchSize"
    $ObjCapture= @()
    do{
        $users = Invoke-RestMethod -Uri $uri –Headers $authHeader –Method Get
        $FoundUsers = ($Users.value).count
        write-host "URI" $uri " | Found:" $FoundUsers
        #------Batched URI Construction------#
        $uri = $users.'@odata.nextlink'
        $ObjCapture = $ObjCapture + $users.value
       
    }until ($uri -eq $null)
    $ObjCapture
}</pre>
<span style="font-family: Times New Roman;font-size: 12pt">
</span>
<h1>Execution</h1>
<span style="font-family: Times New Roman;font-size: 12pt">To output all 'user' types run the following cmdlet. -Tenant should be the tenant name, -type should be the type of object you are trying to return. -Version will default to "beta" based off the script that was laid out above. I've been playing around with beta lately because there is a more flexible data set. Version could also be v1.0, however the URI constructor </span>cannot have "`?top=$BatchSize" in it in order for it to run successfully. <span style="font-family: Times New Roman;font-size: 12pt">
</span>
<pre class="brush: java">GetAllObjectOfType -Tenant "cloudlojik.onmicrosoft.com" -Type "Users" -BatchSize 80 | fl
</pre>
<span style="font-family: Times New Roman;font-size: 12pt">
</span>
<span style="font-family: Times New Roman;font-size: 12pt">In this case, when I execute the script, it outputs all of the users in my tenant</span>
<pre class="brush: java">PS C:\&gt; C:\Graph.ps1
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
URI https://graph.microsoft.com/Beta/Users?top=80  | Found: 80

id                             : 41cb16c4-fea6-4b78-ac78-aa67b33da8a5
deletedDateTime                : 
accountEnabled                 : True
assignedLicenses               : {}
assignedPlans                  : {}
businessPhones                 : {}
city                           : 
companyName                    : 
country                        : 
department                     : 
deviceKeys                     : {}
displayName                    : AADConnect SyncAcct
employeeId                     : 
givenName                      : AADConnect
jobTitle                       : 
mail                           : 
mailNickname                   : aadconnectsync
mobilePhone                    : 
onPremisesDomainName           : 
onPremisesImmutableId          : 
onPremisesLastSyncDateTime     : 
onPremisesProvisioningErrors   : {}
onPremisesSecurityIdentifier   : 
onPremisesSamAccountName       : 
onPremisesSyncEnabled          : 
onPremisesUserPrincipalName    : 
passwordPolicies               : None
passwordProfile                : 
officeLocation                 : 
postalCode                     : 
preferredDataLocation          : 
preferredLanguage              : 
provisionedPlans               : {}
proxyAddresses                 : {}
refreshTokensValidFromDateTime : 2017-09-05T22:43:36Z
showInAddressList              : 
imAddresses                    : {}
state                          : 
streetAddress                  : 
surname                        : SyncAcct
usageLocation                  : US
userPrincipalName              : aadconnectsync@cloudlojik.onmicrosoft.com
userType                       : Member
</pre>
<span style="font-family: Times New Roman;font-size: 12pt">Connect to Microsoft Graph and Query All (users) - Sample Script: <a href="https://msdnshared.blob.core.windows.net/media/2017/10/ConnectToMicrosoftGraph.txt">ConnectToMicrosoftGraph</a></span>]]></content:encoded>
    </item>
  </channel>
</rss>