Header Ads

Xuất tất cả danh sách người dùng với thời gian login gần nhất trên office 365

 Mẫu Script PowerShell sử dụng Microsoft Graph

# Cài module nếu chưa có

Install-Module Microsoft.Graph -Scope CurrentUser -Force


# Kết nối tới Graph với quyền cần thiết

Connect-MgGraph -Scopes "AuditLog.Read.All","Directory.Read.All","User.Read.All"


# Đặt profile beta nếu cần (SignInActivity có thể trong beta)

Select-MgProfile -Name "beta"


# Lấy tất cả user kèm SignInActivity

$users = Get-MgUser -All -Property "displayName","userPrincipalName","signInActivity"


# Tạo danh sách kết quả

$report = $users | Select-Object @{Name="DisplayName";Expression={$_.DisplayName}},

                                 @{Name="UPN";Expression={$_.UserPrincipalName}},

                                 @{Name="LastSignIn";Expression={

                                     if ($_.SignInActivity.LastSignInDateTime) {

                                         $_.SignInActivity.LastSignInDateTime

                                     } else {

                                         "Never or > retention"

                                     }

                                 }}


# Xuất ra CSV

$report | Export-Csv -Path "Office365_Users_LastSignIn.csv" -NoTypeInformation


# Hiển thị danh sách

$report | Format-Table -AutoSize


I. Cài đặt và kết nối Microsoft Graph

Mở PowerShell (Run as Administrator) và chạy:

Install-Module Microsoft.Graph -Scope AllUsers -Force

Sau đó đăng nhập bằng tài khoản có quyền Global Reader / User Administrator / Global Admin:

Connect-MgGraph -Scopes "User.Read.All","AuditLog.Read.All","Directory.Read.All" Select-MgProfile -Name "beta"

🔸 Dùng beta profile để có thể truy cập trường SignInActivity, vì trường này không có trong bản stable.


Tuyệt! Đây là script hoàn chỉnh đã FIX lỗi license null, giữ đủ các cột như bạn muốn và bổ sung LastLogin (định dạng dd/MM/yyyy HH:mm:ss). Chạy được trên PowerShell 5.1/7.x, không cần Entra P1/P2.


# ============================

# FULL Office 365 User Report + LastLogin (no Entra P1/P2)

# Kết quả: C:\Reports\O365_FullColumns_WithLastLogin.csv

# ============================


# (Khuyến nghị nếu bị chặn script)

# Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force


# 1) Kết nối Microsoft Graph

Connect-MgGraph -Scopes "Reports.Read.All","User.Read.All","Directory.Read.All"


# 2) Tải báo cáo Active User Detail (D180) -> CSV

$dir = "C:\Reports"

New-Item -ItemType Directory -Path $dir -Force | Out-Null

$actCsv = Join-Path $dir "O365_ActiveUserDetail_D180.csv"

Get-MgReportOffice365ActiveUserDetail -Period D180 -OutFile $actCsv

$act = Import-Csv $actCsv


# 3) Lấy Directory users (để có đủ thông tin người dùng)

$uProps = @(

  "id","displayName","userPrincipalName","givenName","surname","createdDateTime",

  "jobTitle","department","companyName",

  "city","country","officeLocation","state","usageLocation",

  "onPremisesSyncEnabled","accountEnabled","preferredLanguage",

  "mobilePhone","businessPhones","postalCode","streetAddress","proxyAddresses",

  "assignedLicenses"

)

$users = Get-MgUser -All -Property ($uProps -join ",")


# Bảng tra UPN -> user object

$uLookup = @{}

foreach ($u in $users) { if ($u.UserPrincipalName) { $uLookup[$u.UserPrincipalName.ToLower()] = $u } }


# 4) Map SkuId -> SkuPartNumber (tên gói license) — an toàn khi null

$skuMap = @{}

try {

  $skus = Get-MgSubscribedSku

  if ($skus) {

    foreach ($s in $skus) {

      if ($s.SkuId -and $s.SkuPartNumber) {

        $skuMap[$s.SkuId.Guid] = $s.SkuPartNumber

      }

    }

  }

} catch { }


# 5) Helper: lấy ngày mới nhất trong các cột hoạt động (xấp xỉ last login)

function Get-LatestDate {

    param([string[]]$values)

    $dates = @()

    foreach ($v in $values) {

        if (-not $v) { continue }

        $v = $v.Trim(); if ($v -eq "") { continue }

        try { $dates += [datetime]::Parse($v) } catch { }

    }

    if ($dates.Count -gt 0) { ($dates | Sort-Object -Descending | Select-Object -First 1) } else { $null }

}


$activityCols = @(

  'Last Activity Date',

  'Exchange Last Activity Date',

  'OneDrive Last Activity Date',

  'SharePoint Last Activity Date',

  'Teams Last Activity Date',

  'Yammer Last Activity Date',

  'Skype For Business Last Activity Date'

)


# 6) Hợp nhất dữ liệu, xuất đúng các cột mong muốn + LastLogin

$result = foreach ($row in $act) {


    # Lấy UPN từ report

    $upn = $row.'User Principal Name'; if (-not $upn) { $upn = $row.UserPrincipalName }

    if (-not $upn) { continue }


    $u = $uLookup[$upn.ToLower()]


    # License readable (lọc null, fallback SkuId)

    $licNames = ""; $licIds = ""

    if ($u -and $u.AssignedLicenses -and $u.AssignedLicenses.Count -gt 0) {

        $ids = @($u.AssignedLicenses | ForEach-Object { $_.SkuId.Guid } | Where-Object { $_ -and $_ -ne [guid]::Empty })

        if ($ids.Count -gt 0) {

            $licIds = [string]::Join(';', $ids)

            $names = @()

            foreach ($id in $ids) {

                if ($skuMap.Count -gt 0 -and $skuMap.ContainsKey($id)) { $names += $skuMap[$id] } else { $names += $id }

            }

            if ($names.Count -gt 0) { $licNames = [string]::Join(';', $names) }

        }

    }


    # LastLogin = max ngày hoạt động trong report

    $vals   = foreach ($c in $activityCols) { if ($row.PSObject.Properties.Name -contains $c) { $row.$c } }

    $last   = Get-LatestDate $vals

    $lastFmt= if ($last) { ([datetime]$last).ToString("dd/MM/yyyy HH:mm:ss") } else { "" }


    # Tạo record theo đúng các cột bạn cần + LastLogin

    [pscustomobject]@{

        'Display name'                       = $(if ($u) { $u.DisplayName } else { $row.'Display Name' })

        'DirSyncEnabled'                     = $(if ($u) { $u.OnPremisesSyncEnabled } else { "" })

        'User principal name'                = $upn

        'Object Id'                          = $(if ($u) { $u.Id } else { "" })

        'First name'                         = $(if ($u) { $u.GivenName } else { "" })

        'Last name'                          = $(if ($u) { $u.Surname } else { "" })

        'When created'                       = $(if ($u) { $u.CreatedDateTime } else { "" })

        'Soft deletion time stamp'           = ""    # chỉ có ở Recycle bin report

        'Title'                              = $(if ($u) { $u.JobTitle } else { "" })

        'Department'                         = $(if ($u) { $u.Department } else { "" })

        'Preferred data location'            = ""    # không có trực tiếp trong user object

        'City'                               = $(if ($u) { $u.City } else { "" })

        'CountryOrRegion'                    = $(if ($u) { $u.Country } else { "" })

        'Office'                             = $(if ($u) { $u.OfficeLocation } else { "" })

        'StateOrProvince'                    = $(if ($u) { $u.State } else { "" })

        'Usage location'                     = $(if ($u) { $u.UsageLocation } else { "" })

        'Last dirsync time'                  = ""    # có trong AAD Connect report riêng

        'Block credential'                   = $(if ($u -and $u.AccountEnabled -eq $false) {'TRUE'} else {'FALSE'})

        'Licenses'                           = $licNames

        'Password never expires'             = ""    # cần policy riêng nếu muốn lấy

        'Last password change time stamp'    = ""    # yêu cầu P1/P2 nếu lấy từ SignInActivity

        'Mobile Phone'                       = $(if ($u) { $u.MobilePhone } else { "" })

        'Phone number'                       = $(if ($u -and $u.BusinessPhones) { $u.BusinessPhones -join ';' } else { "" })

        'Postal code'                        = $(if ($u) { $u.PostalCode } else { "" })

        'Preferred language'                 = $(if ($u) { $u.PreferredLanguage } else { "" })

        'Street address'                     = $(if ($u) { $u.StreetAddress } else { "" })

        'Fax'                                = ""    # không có trường fax

        'Proxy addresses'                    = $(if ($u -and $u.ProxyAddresses) { $u.ProxyAddresses -join ';' } else { "" })

        'LastLogin'                          = $lastFmt

    }

}


# 7) Xuất CSV

$out = Join-Path $dir "O365_FullColumns_WithLastLogin.csv"

$result | Export-Csv -Path $out -NoTypeInformation -Encoding UTF8

Write-Host "`n✅ Đã xuất báo cáo đầy đủ: $out"



  • LastLogin = ngày mới nhất phát hiện hoạt động của user trong 180 ngày (Exchange/OneDrive/SharePoint/Teams/Yammer/Skype…).

  • Các cột như Soft deletion time stamp, Last dirsync time, Password never expires, Last password change time stamp… không có nguồn trực tiếp khi không dùng P1/P2 hoặc AAD Connect report → mình để trống để giữ đúng layout. Nếu bạn có nguồn các báo cáo đó, mình sẽ merge thêm thành một file duy nhất.

  • Không có nhận xét nào

    Được tạo bởi Blogger.