{"id":610,"date":"2025-02-28T17:39:38","date_gmt":"2025-02-28T16:39:38","guid":{"rendered":"https:\/\/digitalmaterial.ch\/blog\/?p=610"},"modified":"2025-02-28T17:49:54","modified_gmt":"2025-02-28T16:49:54","slug":"cisco-meraki-gather-license-information-through-the-api","status":"publish","type":"post","link":"https:\/\/digitalmaterial.ch\/blog\/cisco-meraki-gather-license-information-through-the-api\/","title":{"rendered":"Cisco Meraki &#8211; Gather license information through the API"},"content":{"rendered":"\n<p>When managing multiple organizations and networks, it can be difficult to get an overview of all licenses. Instead of manually reviewing each organization, you can leverage the API to gather the necessary information. For example, this can be used to store and track license expirations as assets in a CRM.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">API User<\/h2>\n\n\n\n<p>Create an administrator account with read privileges for the organization and add it to the networks you want to gather information from. In the profile settings, generate a new API key and securely store it for later use.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"151\" src=\"https:\/\/digitalmaterial.ch\/blog\/wp-content\/uploads\/2025\/02\/image-17-1024x151.png\" alt=\"\" class=\"wp-image-612\" srcset=\"https:\/\/digitalmaterial.ch\/blog\/wp-content\/uploads\/2025\/02\/image-17-1024x151.png 1024w, https:\/\/digitalmaterial.ch\/blog\/wp-content\/uploads\/2025\/02\/image-17-300x44.png 300w, https:\/\/digitalmaterial.ch\/blog\/wp-content\/uploads\/2025\/02\/image-17-768x114.png 768w, https:\/\/digitalmaterial.ch\/blog\/wp-content\/uploads\/2025\/02\/image-17-1536x227.png 1536w, https:\/\/digitalmaterial.ch\/blog\/wp-content\/uploads\/2025\/02\/image-17-2048x303.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">License overview<\/h2>\n\n\n\n<p>Using PowerShell, we can easily export all license-related information to a CSV. Save this script as a <code>.ps1<\/code> file in a directory.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(3 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">ShellScript<\/span><span role=\"button\" tabindex=\"0\" data-code=\"Param(\n    [Parameter(Mandatory = $true)]\n    [string]$BearerToken\n)\n\n# Define API headers\n$headers = New-Object &quot;System.Collections.Generic.Dictionary[[String],[String]]&quot;\n$headers.Add(&quot;datatype&quot;, &quot;json&quot;)\n$headers.Add(&quot;Authorization&quot;, &quot;Bearer $BearerToken&quot;)  \n\n# Get all organizations\n$orgs = Invoke-WebRequest `\n    -UseBasicParsing `\n    -Uri &quot;https:\/\/api.meraki.com\/api\/v1\/organizations&quot; `\n    -Method GET `\n    -Headers $headers | ConvertFrom-Json\n\n# Initialize list to store results\n$licenseList = @()\n\n# Loop through each organization to get license info\nforeach ($org in $orgs) {\n    $orgId = $org.id\n    Write-Host &quot;Fetching license info for Organization ID: $orgId&quot;\n\n    # Fetch licenses overview\n    try {\n        $licensesOverview = Invoke-WebRequest `\n            -UseBasicParsing `\n            -Uri &quot;https:\/\/api.meraki.com\/api\/v1\/organizations\/$orgId\/licenses\/overview&quot; `\n            -Method GET `\n            -Headers $headers | ConvertFrom-Json\n    }\n    catch {\n        Write-Host &quot;Failed to fetch licenses overview for Org ID $orgId. Skipping...&quot;\n        continue\n    }\n\n    # Parse Date\n    $expirationDateRaw = $licensesOverview.expirationDate\n    # fallback if parsing fails\n    $expirationDateFormatted = $expirationDateRaw\n\n    if ($expirationDateRaw) {\n        # Remove trailing ' UTC' if present\n        $expirationDateTrimmed = $expirationDateRaw -replace ' UTC$', ''\n        try {\n            # Let PowerShell parse the date automatically (handles single\/double digit days)\n            $parsedDate = [DateTime]::Parse($expirationDateTrimmed)\n            $expirationDateFormatted = $parsedDate.ToString(&quot;yyyy-MM-dd HH:mm:ss&quot;)\n        }\n        catch {\n            # If parsing fails, just keep $expirationDateFormatted as the raw string\n        }\n    }\n\n    # Fetch coterm licenses\n    try {\n        $cotermLicenses = Invoke-WebRequest `\n            -UseBasicParsing `\n            -Uri &quot;https:\/\/api.meraki.com\/api\/v1\/organizations\/$orgId\/licensing\/coterm\/licenses&quot; `\n            -Method GET `\n            -Headers $headers | ConvertFrom-Json\n    }\n    catch {\n        Write-Host &quot;Failed to fetch coterm licenses for Org ID $orgId. Skipping...&quot;\n        continue\n    }\n\n    # Filter valid license keys: where expired is false and invalidated is false\n    $validLicenseKeys = $cotermLicenses |\n    Where-Object { $_.expired -eq $false -and $_.invalidated -eq $false } |\n    Select-Object -ExpandProperty key -ErrorAction SilentlyContinue\n    # Convert $null to empty array to avoid errors\n    $validLicenseKeys = @($validLicenseKeys)\n    $validLicenseKeysString = [string]::Join(&quot;, &quot;, $validLicenseKeys)\n\n    # Filter expired\/invalid license keys: where expired is true or invalidated is true\n    $invalidLicenseKeys = $cotermLicenses |\n    Where-Object { $_.expired -eq $true -or $_.invalidated -eq $true } |\n    Select-Object -ExpandProperty key -ErrorAction SilentlyContinue\n    # Convert $null to empty array to avoid errors\n    $invalidLicenseKeys = @($invalidLicenseKeys)\n    $invalidLicenseKeysString = [string]::Join(&quot;, &quot;, $invalidLicenseKeys)\n\n    # Create a custom object to store the desired details\n    $licenseData = [PSCustomObject]@{\n        OrgId                = $orgId\n        OrgName              = $org.name\n        OverviewStatus       = $licensesOverview.status\n        ExpirationDate       = $expirationDateFormatted\n        LicensedDeviceCounts = ($licensesOverview.licensedDeviceCounts | ConvertTo-Json -Compress)\n        ValidLicenseKeys     = $validLicenseKeysString\n        InvalidLicenseKeys   = $invalidLicenseKeysString\n    }\n\n    $licenseList += $licenseData\n}\n\n# Export to CSV\n$csvPath = &quot;$PSScriptRoot\\meraki_license.csv&quot;\n$licenseList | Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8\n\nWrite-Host &quot;Export complete! CSV saved to $csvPath&quot;\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #DCDCAA\">Param(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    [Parameter(Mandatory = <\/span><span style=\"color: #9CDCFE\">$true<\/span><span style=\"color: #D4D4D4\">)]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    [string]<\/span><span style=\"color: #9CDCFE\">$BearerToken<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\"># Define API headers<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">$headers<\/span><span style=\"color: #D4D4D4\"> = New-Object <\/span><span style=\"color: #CE9178\">&quot;System.Collections.Generic.Dictionary[[String],[String]]&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">$headers<\/span><span style=\"color: #D4D4D4\">.Add(<\/span><span style=\"color: #DCDCAA\">&quot;datatype&quot;<\/span><span style=\"color: #DCDCAA\">,<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;json&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">$headers<\/span><span style=\"color: #D4D4D4\">.Add(<\/span><span style=\"color: #DCDCAA\">&quot;Authorization&quot;<\/span><span style=\"color: #DCDCAA\">,<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;Bearer <\/span><span style=\"color: #9CDCFE\">$BearerToken<\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #D4D4D4\">)  <\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\"># Get all organizations<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">$orgs<\/span><span style=\"color: #D4D4D4\"> = Invoke-WebRequest <\/span><span style=\"color: #CE9178\">`<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">    <\/span><span style=\"color: #DCDCAA\">-UseBasicParsing<\/span><span style=\"color: #CE9178\"> `<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">-Uri<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;https:\/\/api.meraki.com\/api\/v1\/organizations&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">`<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">    <\/span><span style=\"color: #DCDCAA\">-Method<\/span><span style=\"color: #CE9178\"> GET `<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">-Headers<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$headers<\/span><span style=\"color: #D4D4D4\"> | <\/span><span style=\"color: #DCDCAA\">ConvertFrom-Json<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\"># Initialize list to store results<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">$licenseList<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #DCDCAA\">@<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># Loop through each organization to get license info<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">foreach (<\/span><span style=\"color: #9CDCFE\">$org<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$orgs<\/span><span style=\"color: #D4D4D4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">$orgId<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$org<\/span><span style=\"color: #CE9178\">.id<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">Write-Host<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;Fetching license info for Organization ID: <\/span><span style=\"color: #9CDCFE\">$orgId<\/span><span style=\"color: #CE9178\">&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\"># Fetch licenses overview<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">try<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">$licensesOverview<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">Invoke-WebRequest<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">`<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">            <\/span><span style=\"color: #DCDCAA\">-UseBasicParsing<\/span><span style=\"color: #CE9178\"> `<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #DCDCAA\">-Uri<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;https:\/\/api.meraki.com\/api\/v1\/organizations\/<\/span><span style=\"color: #9CDCFE\">$orgId<\/span><span style=\"color: #CE9178\">\/licenses\/overview&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">`<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">            <\/span><span style=\"color: #DCDCAA\">-Method<\/span><span style=\"color: #CE9178\"> GET `<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #DCDCAA\">-Headers<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$headers<\/span><span style=\"color: #D4D4D4\"> | <\/span><span style=\"color: #DCDCAA\">ConvertFrom-Json<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">catch<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">Write-Host<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;Failed to fetch licenses overview for Org ID <\/span><span style=\"color: #9CDCFE\">$orgId<\/span><span style=\"color: #CE9178\">. Skipping...&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">continue<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\"># Parse Date<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">$expirationDateRaw<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$licensesOverview<\/span><span style=\"color: #CE9178\">.expirationDate<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\"># fallback if parsing fails<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">$expirationDateFormatted<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$expirationDateRaw<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">$expirationDateRaw<\/span><span style=\"color: #D4D4D4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\"># Remove trailing &#39; UTC&#39; if present<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">$expirationDateTrimmed<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$expirationDateRaw<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-replace<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&#39; UTC$&#39;,<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&#39;&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">try<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #6A9955\"># Let PowerShell parse the date automatically (handles single\/double digit days)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">$parsedDate<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> [DateTime]::Parse(<\/span><span style=\"color: #9CDCFE\">$expirationDateTrimmed<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">$expirationDateFormatted<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$parsedDate<\/span><span style=\"color: #CE9178\">.ToString<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #DCDCAA\">&quot;yyyy-MM-dd HH:mm:ss&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">catch<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #6A9955\"># If parsing fails, just keep $expirationDateFormatted as the raw string<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\"># Fetch coterm licenses<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">try<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">$cotermLicenses<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">Invoke-WebRequest<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">`<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">            <\/span><span style=\"color: #DCDCAA\">-UseBasicParsing<\/span><span style=\"color: #CE9178\"> `<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #DCDCAA\">-Uri<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;https:\/\/api.meraki.com\/api\/v1\/organizations\/<\/span><span style=\"color: #9CDCFE\">$orgId<\/span><span style=\"color: #CE9178\">\/licensing\/coterm\/licenses&quot;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">`<\/span><\/span>\n<span class=\"line\"><span style=\"color: #CE9178\">            <\/span><span style=\"color: #DCDCAA\">-Method<\/span><span style=\"color: #CE9178\"> GET `<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #DCDCAA\">-Headers<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$headers<\/span><span style=\"color: #D4D4D4\"> | <\/span><span style=\"color: #DCDCAA\">ConvertFrom-Json<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">catch<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">Write-Host<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;Failed to fetch coterm licenses for Org ID <\/span><span style=\"color: #9CDCFE\">$orgId<\/span><span style=\"color: #CE9178\">. Skipping...&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">continue<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\"># Filter valid license keys: where expired is false and invalidated is false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">$validLicenseKeys<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$cotermLicenses<\/span><span style=\"color: #D4D4D4\"> |<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">Where-Object<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">{<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">$_<\/span><span style=\"color: #CE9178\">.expired<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-eq<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$false<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-and<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">$_<\/span><span style=\"color: #CE9178\">.invalidated<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-eq<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$false<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">}<\/span><span style=\"color: #D4D4D4\"> |<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">Select-Object<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-ExpandProperty<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">key<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-ErrorAction<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">SilentlyContinue<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\"># Convert $null to empty array to avoid errors<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">$validLicenseKeys<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">@<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">$validLicenseKeys<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">$validLicenseKeysString<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> [string]::Join(<\/span><span style=\"color: #DCDCAA\">&quot;, &quot;<\/span><span style=\"color: #DCDCAA\">,<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$validLicenseKeys<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\"># Filter expired\/invalid license keys: where expired is true or invalidated is true<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">$invalidLicenseKeys<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$cotermLicenses<\/span><span style=\"color: #D4D4D4\"> |<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">Where-Object<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">{<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">$_<\/span><span style=\"color: #CE9178\">.expired<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-eq<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$true<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-or<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">$_<\/span><span style=\"color: #CE9178\">.invalidated<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-eq<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$true<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">}<\/span><span style=\"color: #D4D4D4\"> |<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">Select-Object<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-ExpandProperty<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">key<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-ErrorAction<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">SilentlyContinue<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\"># Convert $null to empty array to avoid errors<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">$invalidLicenseKeys<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">@<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">$invalidLicenseKeys<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">$invalidLicenseKeysString<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> [string]::Join(<\/span><span style=\"color: #DCDCAA\">&quot;, &quot;<\/span><span style=\"color: #DCDCAA\">,<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$invalidLicenseKeys<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\"># Create a custom object to store the desired details<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">$licenseData<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> [PSCustomObject]@{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">OrgId<\/span><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$orgId<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">OrgName<\/span><span style=\"color: #D4D4D4\">              <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$org<\/span><span style=\"color: #CE9178\">.name<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">OverviewStatus<\/span><span style=\"color: #D4D4D4\">       <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$licensesOverview<\/span><span style=\"color: #CE9178\">.status<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">ExpirationDate<\/span><span style=\"color: #D4D4D4\">       <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$expirationDateFormatted<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">LicensedDeviceCounts<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> ($licensesOverview.licensedDeviceCounts | <\/span><span style=\"color: #DCDCAA\">ConvertTo-Json<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-Compress<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">ValidLicenseKeys<\/span><span style=\"color: #D4D4D4\">     <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$validLicenseKeysString<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">InvalidLicenseKeys<\/span><span style=\"color: #D4D4D4\">   <\/span><span style=\"color: #CE9178\">=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$invalidLicenseKeysString<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">$licenseList<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">+=<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$licenseData<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #6A9955\"># Export to CSV<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">$csvPath<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;<\/span><span style=\"color: #9CDCFE\">$PSScriptRoot<\/span><span style=\"color: #CE9178\">\\meraki_license.csv&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">$licenseList<\/span><span style=\"color: #D4D4D4\"> | <\/span><span style=\"color: #DCDCAA\">Export-Csv<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-Path<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">$csvPath<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-NoTypeInformation<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">-Encoding<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">UTF8<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #DCDCAA\">Write-Host<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;Export complete! CSV saved to <\/span><span style=\"color: #9CDCFE\">$csvPath<\/span><span style=\"color: #CE9178\">&quot;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>To run the script, open PowerShell and navigate to the directory where the script is located. Use the <code>-BearerToken<\/code> parameter to pass the API token.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#2b2b2b;color:#c7c7c7\">ShellScript<\/span><span role=\"button\" tabindex=\"0\" data-code=\".\\get_all_devices_claimed_at.ps1 -BearerToken YOURTOKENHERE\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #DCDCAA\">.<\/span><span style=\"color: #D4D4D4\">\\get_all_devices_claimed_at.ps1 <\/span><span style=\"color: #569CD6\">-BearerToken<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">YOURTOKENHERE<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>The script will generate a <code>.csv<\/code> file in the same directory where the script is stored. The CSV will include the OrgID, Name, Status, Expiration Date, Device Count, Valid Licenses, and Invalid Licenses.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"95\" src=\"https:\/\/digitalmaterial.ch\/blog\/wp-content\/uploads\/2025\/02\/image-19-1024x95.png\" alt=\"\" class=\"wp-image-615\" srcset=\"https:\/\/digitalmaterial.ch\/blog\/wp-content\/uploads\/2025\/02\/image-19-1024x95.png 1024w, https:\/\/digitalmaterial.ch\/blog\/wp-content\/uploads\/2025\/02\/image-19-300x28.png 300w, https:\/\/digitalmaterial.ch\/blog\/wp-content\/uploads\/2025\/02\/image-19-768x72.png 768w, https:\/\/digitalmaterial.ch\/blog\/wp-content\/uploads\/2025\/02\/image-19-1536x143.png 1536w, https:\/\/digitalmaterial.ch\/blog\/wp-content\/uploads\/2025\/02\/image-19.png 1825w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>When managing multiple organizations and networks, it can be difficult to get an overview of all licenses. Instead of manually reviewing each organization, you can leverage the API to gather the necessary information. For example, this can be used to store and track license expirations as assets in a CRM. API User Create an administrator [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":640,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-610","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-allgemein"],"_links":{"self":[{"href":"https:\/\/digitalmaterial.ch\/blog\/wp-json\/wp\/v2\/posts\/610","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/digitalmaterial.ch\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/digitalmaterial.ch\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/digitalmaterial.ch\/blog\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/digitalmaterial.ch\/blog\/wp-json\/wp\/v2\/comments?post=610"}],"version-history":[{"count":4,"href":"https:\/\/digitalmaterial.ch\/blog\/wp-json\/wp\/v2\/posts\/610\/revisions"}],"predecessor-version":[{"id":639,"href":"https:\/\/digitalmaterial.ch\/blog\/wp-json\/wp\/v2\/posts\/610\/revisions\/639"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/digitalmaterial.ch\/blog\/wp-json\/wp\/v2\/media\/640"}],"wp:attachment":[{"href":"https:\/\/digitalmaterial.ch\/blog\/wp-json\/wp\/v2\/media?parent=610"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/digitalmaterial.ch\/blog\/wp-json\/wp\/v2\/categories?post=610"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/digitalmaterial.ch\/blog\/wp-json\/wp\/v2\/tags?post=610"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}