0

I have the following Powershell-Script I wrote, which is working fine in Powershell ISE. The problem is, I need it working in VS Code.

What is the script doing? Well, it connects to an Azure Active Directory (User with Admin-Privilegs is needed) Looks for active users, who haven't licensed Teams, Sharepoint, OneDrive AND Exchange (that was the tasks origin, to check if all four applications are NOT licensed, if one is - the user won't be listed!)

Then it looks for the license status, lists affected user in the console and offers the option to export it into an excel file.

# Install AzureAD-Module (if not installed)
if (-not (Get-Module -Name AzureAD -ListAvailable)) {
    Write-Host -ForegroundColor Yellow "The AzureAD-Module isn't installed. Installation will be started..."
    Install-Module -Name AzureAD -Force
}

# Connect with Azure AD
Connect-AzureAD

# Request Tenant-ID
$tenantId = (Get-AzureADTenantDetail).ObjectId

# Request Username
$currentUserName = $env:USERNAME

# Request every user without app-access
$usersWithoutAppAccess = Get-AzureADUser -All $true | Where-Object {
    $userId = $_.ObjectId
    $hasExchangeLicense = (Get-AzureADUserLicenseDetail -ObjectId $userId | Where-Object { $_.ServicePlans -like "*EXCHANGE_S_*" }).Count -eq 0
    $hasOneDriveLicense = (Get-AzureADUserLicenseDetail -ObjectId $userId | Where-Object { $_.ServicePlans -like "*SHAREPOINT_S_*" }).Count -eq 0
    $hasSharePointLicense = (Get-AzureADUserLicenseDetail -ObjectId $userId | Where-Object { $_.ServicePlans -like "*SHAREPOINTENTERPRISE_*" }).Count -eq 0
    $hasTeamsLicense = (Get-AzureADUserLicenseDetail -ObjectId $userId | Where-Object { $_.ServicePlans -like "*TEAMS1_*" }).Count -eq 0
    $hasExchangeLicense -and $hasOneDriveLicense -and $hasSharePointLicense -and $hasTeamsLicense
}

# Print affected user into powershell console
$affectedUserCount = $usersWithoutAppAccess.Count
Write-Host -ForegroundColor Yellow "Anzahl der Benutzer ohne App-Zugriff: $affectedUserCount"
Write-Host -ForegroundColor Yellow "Betroffene Benutzer:"
$usersWithoutAppAccess | ForEach-Object {
    Write-Host $_.UserPrincipalName
    # check status about license history for user
    $userLicenseHistory = Get-AzureADUserLicenseDetail -ObjectId $_.ObjectId
    if ($userLicenseHistory) {
        Write-Host "previously allocated licenses:"
        $userLicenseHistory | ForEach-Object {
            Write-Host "- $_.SkuPartNumber"
        }
    } else {
        Write-Host "There are no previously allocated licenses."
    }
}

# request user with at least one license
$usersWithAppAccess = Get-AzureADUser -All $true | Where-Object {
    $userId = $_.ObjectId
    $hasExchangeLicense = (Get-AzureADUserLicenseDetail -ObjectId $userId | Where-Object { $_.ServicePlans -like "*EXCHANGE_S_*" }).Count -gt 0
    $hasOneDriveLicense = (Get-AzureADUserLicenseDetail -ObjectId $userId | Where-Object { $_.ServicePlans -like "*SHAREPOINT_S_*" }).Count -gt 0
    $hasSharePointLicense = (Get-AzureADUserLicenseDetail -ObjectId $userId | Where-Object { $_.ServicePlans -like "*SHAREPOINTENTERPRISE_*" }).Count -gt 0
    $hasTeamsLicense = (Get-AzureADUserLicenseDetail -ObjectId $userId | Where-Object { $_.ServicePlans -like "*TEAMS1_*" }).Count -gt 0
    $hasExchangeLicense -or $hasOneDriveLicense -or $hasSharePointLicense -or $hasTeamsLicense
}

# export list ofuser without app-access and user with at least on app-license into excel (optional)
Write-Host -ForegroundColor Green "Do you wish to export the list of user without any access to any app and user with at least one app license into an excelfile? (Y/N)"
$exportToExcel = Read-Host

if ($exportToExcel -eq "Y") {
    # path for excelfile
    $documentsPath = [Environment]::GetFolderPath('MyDocuments')
    $excelFileName = "$(Get-Date -Format 'yyyyMMdd')_UsersAccess.xlsx"
    $excelFilePath = Join-Path -Path $documentsPath -ChildPath $excelFileName

    # check, if file already exists
    $counter = 1
    while (Test-Path $excelFilePath) {
        $counter++
        $excelFileName = "$(Get-Date -Format 'yyyyMMdd')_UsersAccess_$counter.xlsx"
        $excelFilePath = Join-Path -Path $documentsPath -ChildPath $excelFileName
    }

    # create object for excel table
    $excel = New-Object -ComObject Excel.Application
    $workbook = $excel.Workbooks.Add()
    
    # Sheet "User without app-access"
    $worksheetWithoutAppAccess = $workbook.Worksheets.Item(1)
    $worksheetWithoutAppAccess.Name = "user without app-access"

    # title for "user without app-access"
    $worksheetWithoutAppAccess.Cells.Item(1, 1).Value2 = "Tenant-ID"
    $worksheetWithoutAppAccess.Cells.Item(1, 2).Value2 = $tenantId
    $worksheetWithoutAppAccess.Cells.Item(3, 1).Value2 = "UserPrincipalName"
    $worksheetWithoutAppAccess.Cells.Item(3, 2).Value2 = "DisplayName"
    $worksheetWithoutAppAccess.Cells.Item(3, 3).Value2 = "LicensedUser"

    # format title for "User without app-access"
    $headerRangeWithoutAppAccess = $worksheetWithoutAppAccess.Range("A1:C3")
    $headerRangeWithoutAppAccess.Font.Bold = $true

    # write data into the sheet for "User without app-access" into the file
    $rowIndexWithoutAppAccess = 4
    foreach ($userWithoutAppAccess in $usersWithoutAppAccess) {
        $worksheetWithoutAppAccess.Cells.Item($rowIndexWithoutAppAccess, 1).Value2 = $userWithoutAppAccess.UserPrincipalName
        $worksheetWithoutAppAccess.Cells.Item($rowIndexWithoutAppAccess, 2).Value2 = $userWithoutAppAccess.DisplayName
        $worksheetWithoutAppAccess.Cells.Item($rowIndexWithoutAppAccess, 3).Value2 = "No"

        $rowIndexWithoutAppAccess++
    }

    # automatically align column-width for "User without app-access"
    $usedRangeWithoutAppAccess = $worksheetWithoutAppAccess.UsedRange
    $usedRangeWithoutAppAccess.EntireColumn.AutoFit() | Out-Null

    # sheet for "User with at least one license"
    $worksheetWithAppAccess = $workbook.Worksheets.Add()
    $worksheetWithAppAccess.Name = "User with app-license"

    # write title for "User with app-license"
    $worksheetWithAppAccess.Cells.Item(1, 1).Value2 = "Tenant-ID"
    $worksheetWithAppAccess.Cells.Item(1, 2).Value2 = $tenantId
    $worksheetWithAppAccess.Cells.Item(3, 1).Value2 = "UserPrincipalName"
    $worksheetWithAppAccess.Cells.Item(3, 2).Value2 = "DisplayName"
    $worksheetWithAppAccess.Cells.Item(3, 3).Value2 = "LicensedUser"
    $worksheetWithAppAccess.Cells.Item(3, 4).Value2 = "LicensedAppCount"
    $worksheetWithAppAccess.Cells.Item(3, 5).Value2 = "LicensedApps"

    # format titles for "User with app-license"
    $headerRangeWithAppAccess = $worksheetWithAppAccess.Range("A1:E3")
    $headerRangeWithAppAccess.Font.Bold = $true

    # write data for "User with app-license" into the file
    $rowIndexWithAppAccess = 4
    foreach ($userWithAppAccess in $usersWithAppAccess) {
        $worksheetWithAppAccess.Cells.Item($rowIndexWithAppAccess, 1).Value2 = $userWithAppAccess.UserPrincipalName
        $worksheetWithAppAccess.Cells.Item($rowIndexWithAppAccess, 2).Value2 = $userWithAppAccess.DisplayName
        $worksheetWithAppAccess.Cells.Item($rowIndexWithAppAccess, 3).Value2 = "Yes"
        $userLicenseStatus = Get-AzureADUserLicenseDetail -ObjectId $userWithAppAccess.ObjectId
        if ($userLicenseStatus) {
            $licensedApps = $userLicenseStatus.ServicePlans | ForEach-Object {
                $_.ServicePlanName
            }
            $licensedAppCount = $licensedApps.Count
            $worksheetWithAppAccess.Cells.Item($rowIndexWithAppAccess, 4).Value2 = [int]$licensedAppCount
            $worksheetWithAppAccess.Cells.Item($rowIndexWithAppAccess, 5).Value2 = $licensedApps -join ","
        }

        $rowIndexWithAppAccess++
    }

    # automatically align column-width for "User with app-license"
    $usedRangeWithAppAccess = $worksheetWithAppAccess.UsedRange
    $usedRangeWithAppAccess.EntireColumn.AutoFit() | Out-Null

    # save and close excel-table
    $workbook.SaveAs($excelFilePath)
    $workbook.Close()

    # clean up excel-objects
    $excel.Quit()
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($worksheetWithoutAppAccess) | Out-Null
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($worksheetWithAppAccess) | Out-Null
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook) | Out-Null
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null
    Remove-Variable excel, workbook, worksheetWithoutAppAccess, worksheetWithAppAccess

    Write-Host -ForegroundColor Green "The list was exported successfully:"
    Write-Host -ForegroundColor Green $excelFilePath
} else {
    Write-Host -ForegroundColor Green "The export was skipped."
}

The problem is, the Module MSOnline in VS Code isn't working as also the AzureAD Module. I found out it's possible to use the Az-Module, but I don't find any useful hints how to get any information about licensedetails, everything I tried ends in issues/errors in the console (which is btw. really annoying due to version features which were cut or changed) or I am referred to "use MSOnline etc." which isn't working.

Can someone help me please, how to change that code, so it would be working in VS Code?

Best Regards,

3
  • VSCode can run the exact same script as ISE. My guess is that you're having problems using different PS versions (ISE uses PS5.1, VSCode usually defaults to PS7). You should check this for clarification and update your question if this is the case. Commented Jun 15, 2023 at 12:30
  • You may not be running As Admin in VSCode. Try right click VSCode shortcut and select Run As Admin. Commented Jun 15, 2023 at 12:36
  • No I am running as admin. Oh man I am going crazy. - I chose the version 5.1 - but didn't switch the session, so I made a check which version it is using (was 7); I changed the session to 5.1 now and it's working. Thank you so much, sometimes we need to get out of the forest ;-) How ever, does it mean, there's currently no elegant way, to get this done with version 7? Commented Jun 15, 2023 at 12:38

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.