{"id":1010,"date":"2021-01-17T21:39:17","date_gmt":"2021-01-17T20:39:17","guid":{"rendered":"http:\/\/www.vatland.no\/?p=1010"},"modified":"2021-01-17T21:48:48","modified_gmt":"2021-01-17T20:48:48","slug":"add-tenant-licenses-from-csp-to-database","status":"publish","type":"post","link":"https:\/\/www.vatland.no\/index.php\/add-tenant-licenses-from-csp-to-database\/","title":{"rendered":"Add tenant licenses from csp to database."},"content":{"rendered":"<p>This is a followup from previus post. In this post I will populate the database with what licenses a tenant has aquired.<br \/>\nThis will add records of what aquired skus and &#8216;usage&#8217;. For me this is how many license are bought versus how many are assigned. This does not account for senarios other than CSP.<br \/>\nIn this function I am only adding the overview of license. How many has been purchased(from us) and versus how many has been assigned. There is no information about what licens a specific user are assigened ( This is for a later article).<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;width:435px;height:300px;\"><div class=\"text codecolorer\">function update-tenantlicsinDB {<br \/>\n&nbsp; &nbsp; &lt;#<br \/>\n&nbsp; .SYNOPSIS<br \/>\n&nbsp; Update tenant subscriptions\/licenses from Cegal CSP<br \/>\n&nbsp; .DESCRIPTION<br \/>\n&nbsp; Update licenses from tenant.<br \/>\n&nbsp; Tenant refer to the display name of the tenant &quot;Super Company 1&quot;<br \/>\n&nbsp; Tenant is a dynamic parameter, autocomplete list.<br \/>\n<br \/>\n&nbsp; DYNAMIC PARAMTERS<br \/>\n&nbsp; <br \/>\n&nbsp; PARAMETER tenant<br \/>\n&nbsp; -tenant &lt;string&gt;<br \/>\n&nbsp; tenant refers to the display name of the tenant &quot;Super Company 1&quot;<br \/>\n&nbsp; If omitted all tenants are returned. Autocomplete list of all tenants in csp<br \/>\n<br \/>\n&nbsp; .PARAMETER force<br \/>\n&nbsp; Will force update of skus in database. Normaly updated once a day.<br \/>\n&nbsp; <br \/>\n&nbsp; .EXAMPLE<br \/>\n&nbsp; update-tenantlicsindb -tenant 'Tenant name' -force<br \/>\n<br \/>\n&nbsp; .EXAMPLE<br \/>\n&nbsp; update-tenantlicsindb<br \/>\n<br \/>\n&nbsp;#&gt;<br \/>\n&nbsp; &nbsp; [CmdletBinding()]<br \/>\n&nbsp; &nbsp; param(<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; [switch]$force,<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; [switch]$updateusers<br \/>\n&nbsp; &nbsp; )<br \/>\n&nbsp; &nbsp; DynamicParam {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $ParameterName = &quot;tenant&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; # Create and set the parameters' attributes<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $ParameterAttribute.Mandatory = $false<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $ParameterAttribute.Position = 1<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; # Add the attributes to the attributes collection<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $AttributeCollection.Add($ParameterAttribute)<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; # Generate and set the ValidateSet<br \/>\n&nbsp;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; # Add the ValidateSet to the attributes collection &nbsp; <br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $SQLInstance = &quot;localhost\\SQLExpress&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $SQLDatabase = &quot;Microsoft365&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $sqlqr = &quot;select * from [Microsoft365].[dbo].[tenants]&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $customers = invoke-sqlcmd -query $sqlqr -ServerInstance $SQLInstance -Database $SQLDatabase<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; #$arrSet = Get-WmiObject Win32_Service -ComputerName $computername | select -ExpandProperty Name<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($Customers | Select-Object -ExpandProperty tenantname)<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $AttributeCollection.Add($ValidateSetAttribute)<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; # Create and return the dynamic parameter<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection)<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter)<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; return $RuntimeParameterDictionary<br \/>\n&nbsp; &nbsp; }<br \/>\n&nbsp; &nbsp; begin {<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; # Bind the parameter to a friendly variable<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $Kunde = $PsBoundParameters[$ParameterName] &nbsp;<br \/>\n&nbsp; &nbsp; }<br \/>\n&nbsp; &nbsp; process {<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; import-module partnercenter<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $tid = &quot;&lt;CSP tenant ID&gt;&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $appid = &quot;&lt;App ID&gt;&quot;<br \/>\n&nbsp; &nbsp; <br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $k = (get-storedcredential -user $appid).password<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $token = (get-storedcredential -user cspuser).getnetworkcredential().password<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $app = New-Object System.Management.Automation.PSCredential -ArgumentList $appid, $k<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; # &nbsp; &nbsp; &nbsp; &nbsp;$partneraccesstoken = New-PartnerAccessToken -RefreshToken $token -Resource &quot;https:\/\/api.partnercenter.microsoft.com&quot; -Credential $app -TenantId $tid<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $partneraccesstoken = New-PartnerAccessToken -RefreshToken $token -Credential $app -Tenant $tid -Scopes 'https:\/\/api.partnercenter.microsoft.com\/user_impersonation' -ServicePrincipal -ApplicationId $appid &nbsp;# &nbsp;-Resource &quot;https:\/\/api.partnercenter.microsoft.com&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $partneraccesstoken<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; #$connected = Connect-PartnerCenter -AccessToken $partneraccesstoken.AccessToken -ApplicationId $app.username -TenantId $tid -Environment AzureCloud -ServicePrincipal<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $connected = Connect-PartnerCenter -ApplicationId $appid -Credential $app -RefreshToken $token<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; if (-not $connected) { throw &quot;Error connecting to partnercenter..&quot; }<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; update-storedcredential -user cspuser -secret ($partneraccesstoken.RefreshToken | ConvertTo-SecureString -AsPlainText -Force)<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $SQLInstance = &quot;localhost\\SQLExpress&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $SQLDatabase = &quot;Microsoft365&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; # &nbsp;$SQLUsername = &quot;&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; # &nbsp;$SQLPassword = &quot;&quot;<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $today = Get-date<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; $dayofyear = &quot;$($today.Year)-$($today.DayOfYear)&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; if (-not $kunde) {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $customers = Get-PartnerCustomer<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; catch { Write-Host &quot;Error getting tenants from partnercenter.&quot; }<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; }<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; else {<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $customers = Get-PartnerCustomer | Where-Object { $_.domain -eq $kunde }<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; }<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; # Add users to DB. (not #ext# or contacts)<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; # $customer=$customers[9]<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; foreach ($customer in $customers ) {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #$customer=$customers[2] <br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Write-Host &quot;Processing tenant: $($customer.Name) ($($customer.domain))&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Add Sku to Skus table<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $customerskus = Get-PartnerCustomerSubscribedSku -CustomerId $customer.CustomerId<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if ($customerskus) {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; foreach ($sku in $customerskus) {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $sqlsku = &quot;insert into skus (SkuID,SkuPartNumber,ProductName) values ('$($sku.SkuID)','$($sku.SkuPartNumber)','$($sku.ProductName)')&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; invoke-sqlcmd -query $sqlsku -ServerInstance $SQLInstance -Database $SQLDatabase -ErrorAction Stop # -Username $SQLUsername -Password $SQLPassword <br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Write-Output &quot;SkuID ($($sku.ProductName)) added to database&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; catch {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $sqlsku = &quot;insert into skus (SkuID,SkuPartNumber,ProductName) values ()&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # &nbsp;Write-Output &quot;SkuID ($($sku.ProductName)) already exists in database&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Add licensed2licensedskus table<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $sqlls = &quot;select * from licensedskus where DayOfYear='$($dayofyear)' and tenantid='$($customer.CustomerId)' and skuid='$($sku.SkuID)'&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $ls = invoke-sqlcmd -query $sqlls -ServerInstance $SQLInstance -Database $SQLDatabase -ErrorAction Stop # -Username $SQLUsername -Password $SQLPassword <br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (-not $ls ) {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # Not registered for today -&gt; insert<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $sqlls = &quot;insert into licensedskus (DayOfYear,Date,TenantID,SkuID,AvailableUnits,ActiveUnits,CapabilityStatus,ConsumedUnits,LicenseGroupId,SuspendedUnits,TargetType,TotalUnits,WarningUnits) values ('$($dayofyear)','$($today)','$($customer.CustomerId)','$($sku.SkuID)','$($sku.AvailableUnits)','$($sku.ActiveUnits)','$($sku.CapabilityStatus)','$($sku.ConsumedUnits)','$($sku.LicenseGroupId)','$($sku.SuspendedUnits)','$($sku.TargetType)','$($sku.TotalUnits)','$($sku.WarningUnits)')&quot; &nbsp;#.ToUniversalTime()<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $ls = invoke-sqlcmd -query $sqlls -ServerInstance $SQLInstance -Database $SQLDatabase -ErrorAction Stop # -Username $SQLUsername -Password $SQLPassword <br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if ($force) {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $sqlls = &quot;update licensedskus set DayOfYear='$($dayofyear)',Date='$($today)',TenantID='$($customer.CustomerId)',SkuID='$($sku.SkuID)',AvailableUnits='$($sku.AvailableUnits)',ActiveUnits='$($sku.ActiveUnits)',CapabilityStatus='$($sku.CapabilityStatus)',ConsumedUnits='$($sku.ConsumedUnits)',LicenseGroupId='$($sku.LicenseGroupId)',SuspendedUnits='$($sku.SuspendedUnits)',TargetType='$($sku.TargetType)',TotalUnits='$($sku.TotalUnits)',WarningUnits='$($sku.WarningUnits)' where DayOfYear='$($dayofyear)' and tenantid='$($customer.CustomerId)' and skuid='$($sku.SkuID)'&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $ls = invoke-sqlcmd -query $sqlls -ServerInstance $SQLInstance -Database $SQLDatabase -ErrorAction Stop # -Username $SQLUsername -Password $SQLPassword &nbsp; &nbsp; <br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Write-output &quot; Updating sku ($($sku.Productname))&quot;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br \/>\n<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <br \/>\n&nbsp; &nbsp; }<br \/>\n}<\/div><\/div>\n<p>This PS script inserts data into &#8220;skus&#8221; table and &#8220;licensedskus&#8221; table. Here are the sql management studio scripts to create those.<br \/>\n&#8220;SKSU&#8221; tabler<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;width:435px;height:300px;\"><div class=\"text codecolorer\">USE [Microsoft365]<br \/>\nGO<br \/>\n<br \/>\n\/****** Object: &nbsp;Table [dbo].[Skus] &nbsp; &nbsp;Script Date: 17.01.2021 21:34:11 ******\/<br \/>\nSET ANSI_NULLS ON<br \/>\nGO<br \/>\n<br \/>\nSET QUOTED_IDENTIFIER ON<br \/>\nGO<br \/>\n<br \/>\nCREATE TABLE [dbo].[Skus](<br \/>\n&nbsp; &nbsp; [SkuID] [varchar](255) NOT NULL,<br \/>\n&nbsp; &nbsp; [SkuPartNumber] [varchar](255) NULL,<br \/>\n&nbsp; &nbsp; [ProductName] [varchar](255) NULL,<br \/>\n&nbsp; &nbsp; [FriendlyName] [varchar](255) NULL,<br \/>\n&nbsp;CONSTRAINT [PK_Skus] PRIMARY KEY CLUSTERED <br \/>\n(<br \/>\n&nbsp; &nbsp; [SkuID] ASC<br \/>\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]<br \/>\n) ON [PRIMARY]<br \/>\nGO<\/div><\/div>\n<p>And lucky you here are the sql MS to create the othe table:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;width:435px;height:300px;\"><div class=\"text codecolorer\">USE [Microsoft365]<br \/>\nGO<br \/>\n<br \/>\n\/****** Object: &nbsp;Table [dbo].[LicensedSkus] &nbsp; &nbsp;Script Date: 17.01.2021 21:38:41 ******\/<br \/>\nSET ANSI_NULLS ON<br \/>\nGO<br \/>\n<br \/>\nSET QUOTED_IDENTIFIER ON<br \/>\nGO<br \/>\n<br \/>\nCREATE TABLE [dbo].[LicensedSkus](<br \/>\n&nbsp; &nbsp; [ID] [int] IDENTITY(1,1) NOT NULL,<br \/>\n&nbsp; &nbsp; [DayOfYear] [varchar](10) NULL,<br \/>\n&nbsp; &nbsp; [Date] [datetime] NULL,<br \/>\n&nbsp; &nbsp; [TenantID] [varchar](50) NULL,<br \/>\n&nbsp; &nbsp; [SkuID] [varchar](50) NULL,<br \/>\n&nbsp; &nbsp; [AvailableUnits] [int] NULL,<br \/>\n&nbsp; &nbsp; [ActiveUnits] [int] NULL,<br \/>\n&nbsp; &nbsp; [CapabilityStatus] [varchar](50) NULL,<br \/>\n&nbsp; &nbsp; [ConsumedUnits] [int] NULL,<br \/>\n&nbsp; &nbsp; [LicenseGroupId] [varchar](50) NULL,<br \/>\n&nbsp; &nbsp; [SuspendedUnits] [int] NULL,<br \/>\n&nbsp; &nbsp; [TargetType] [varchar](50) NULL,<br \/>\n&nbsp; &nbsp; [TotalUnits] [int] NULL,<br \/>\n&nbsp; &nbsp; [WarningUnits] [int] NULL,<br \/>\n&nbsp;CONSTRAINT [PK_LicensedSkus] PRIMARY KEY CLUSTERED <br \/>\n(<br \/>\n&nbsp; &nbsp; [ID] ASC<br \/>\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]<br \/>\n) ON [PRIMARY]<br \/>\nGO<\/div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>This is a followup from previus post. In this post I will populate the database with what licenses a tenant has aquired. This will add records of what aquired skus and &#8216;usage&#8217;. For me this is how many license are bought versus how many are assigned. This does not account for senarios other than CSP. &hellip; <a href=\"https:\/\/www.vatland.no\/index.php\/add-tenant-licenses-from-csp-to-database\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Add tenant licenses from csp to database.<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"Add tenant licenses from csp to database.","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[73,72,74,2,48,10],"tags":[],"class_list":["post-1010","post","type-post","status-publish","format-standard","hentry","category-azure-uncategorized","category-azure","category-csp","category-development","category-powershell","category-windows"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":false,"jetpack-related-posts":[{"id":975,"url":"https:\/\/www.vatland.no\/index.php\/log-tenants-from-office-365-to-local-db\/","url_meta":{"origin":1010,"position":0},"title":"Log tenants from office 365 to local Db","author":"Atle","date":"January 3, 2021","format":false,"excerpt":"Hi, I like to keep control of how many licenses our cutomers use versus how many\u00a0 have been purchased. Here is 1st part\u00a0 my PS script to copy the info from csp to the DB. I will start creating a database and table to keep a list of all the\u2026","rel":"","context":"In &quot;Azure&quot;","block_context":{"text":"Azure","link":"https:\/\/www.vatland.no\/index.php\/category\/azure\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":902,"url":"https:\/\/www.vatland.no\/index.php\/csp-access-to-tenants-using-powershell-part-3\/","url_meta":{"origin":1010,"position":1},"title":"CSP access to tenants using powershell. Part 3","author":"Atle","date":"September 23, 2019","format":false,"excerpt":"In this part 3 of CSP and powershell I will show how you can connect to azureAD of a customer tenant using your CSP app credentials and refreshtoken. This is almost the same procedure as we use to connect to az. We will start with the same variables as in\u2026","rel":"","context":"In &quot;Azure&quot;","block_context":{"text":"Azure","link":"https:\/\/www.vatland.no\/index.php\/category\/azure\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":875,"url":"https:\/\/www.vatland.no\/index.php\/csp-access-to-tenants-using-powershell-part-1\/","url_meta":{"origin":1010,"position":2},"title":"CSP access to tenants using powershell. Part 1","author":"Atle","date":"September 18, 2019","format":false,"excerpt":"A short explanation of how to access customer tenant using a CSP tenant SPN credential connectiong to AzureAD and AZ. Have been struggling for a while to manage all our customers tenants using powershell scripts. It can be complicated to organize all the credentials, tenant domain, tenant id's password expiry.\u2026","rel":"","context":"In &quot;Azure&quot;","block_context":{"text":"Azure","link":"https:\/\/www.vatland.no\/index.php\/category\/azure\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1043,"url":"https:\/\/www.vatland.no\/index.php\/list-user-and-license-in-database\/","url_meta":{"origin":1010,"position":3},"title":"List users and licenses in Database","author":"Atle","date":"March 26, 2021","format":false,"excerpt":"Now that we have a database containing user, tenant and license it would be nice to have a function\/command to list this. Took me a while to figure it out but thanks to Bing, I prefer Bing before google. I sync my database on a schedule once a day. This\u2026","rel":"","context":"In &quot;CSP&quot;","block_context":{"text":"CSP","link":"https:\/\/www.vatland.no\/index.php\/category\/csp\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":914,"url":"https:\/\/www.vatland.no\/index.php\/csp-access-to-tenants-using-powershell-part-4\/","url_meta":{"origin":1010,"position":4},"title":"CSP access to tenants using powershell. Part 4","author":"Atle","date":"September 24, 2019","format":false,"excerpt":"This is a small script that connects to partnercenter list all customers tenants and let you select one. When one is selected it connects to azuread and az for that customer. All my credentials are stored in SecretServer . I use a web service request to get those credentials. I\u2026","rel":"","context":"In &quot;Azure&quot;","block_context":{"text":"Azure","link":"https:\/\/www.vatland.no\/index.php\/category\/azure\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":957,"url":"https:\/\/www.vatland.no\/index.php\/hash-tables-in-powershell\/","url_meta":{"origin":1010,"position":5},"title":"Hash tables in powershell","author":"Atle","date":"March 23, 2020","format":false,"excerpt":"We all have the need to store data in some kind of arrays. I use hashtables a lot. Preferred use is as a lookup table, I can use 'contains' instead of looping through each item or reference an object by name instead of index number. Lookup table for licenses is\u2026","rel":"","context":"In &quot;CSP&quot;","block_context":{"text":"CSP","link":"https:\/\/www.vatland.no\/index.php\/category\/csp\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/posts\/1010","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/comments?post=1010"}],"version-history":[{"count":6,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/posts\/1010\/revisions"}],"predecessor-version":[{"id":1015,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/posts\/1010\/revisions\/1015"}],"wp:attachment":[{"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/media?parent=1010"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/categories?post=1010"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/tags?post=1010"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}