Tuesday, July 29, 2025

๐Ÿ”ง Supercharge Your Sitecore Admin Workflow: PowerShell Scripts for Efficient User Management

Hi All,

Managing users in a large Sitecore environment can quickly become overwhelming — especially when dealing with inactive accounts, security audits, or regular maintenance. Whether you’re a Sitecore administrator or a dev lead, having a clean, secure user base is crucial.

In this blog, I’ll walk you through 4 essential PowerShell scripts that have helped my team streamline Sitecore user management and perform periodic cleanup with ease. ๐Ÿงน⚙️

๐Ÿš€ Why PowerShell for Sitecore?

Sitecore PowerShell Extensions (SPE) provide a powerful scripting environment to interact with Sitecore APIs directly — enabling automation, reporting, and even UI integration.

These scripts are simple, reusable, and can be scheduled or triggered on demand — helping you keep your environment healthy and compliant.

๐Ÿง‘‍๐Ÿ’ผ Use Case #1: List All Disabled Users from Sitecore

Inactive, disabled accounts can pile up over time. Use this script to identify all users who were disabled within the past— handy for audits or cleanup reports.

# Get all users (from all domains)
$allUsers = Get-User -Filter "*"
 
# Filter disabled users (IsEnabled = $false)
$disabledUsers = $allUsers | Where-Object { $_.IsEnabled -eq $false }
 
# Add parsed domain info for each user
$disabledUsersWithDomain = $disabledUsers | ForEach-Object {
    $splitName = $_.Name -split '\\'
    [PSCustomObject]@{
        Name      = $_.Name
        Domain    = if ($splitName.Length -eq 2) { $splitName[0] } else { "unknown" }
        UserName  = if ($splitName.Length -eq 2) { $splitName[1] } else { $_.Name }
        IsEnabled = $_.IsEnabled
    }
}
 
# Show in interactive list view
$disabledUsersWithDomain | Show-ListView -Title "Disabled Users" -Property Name, Domain, UserName, IsEnabled

Benefits:

  • Audit ready
  • Easily exportable

๐Ÿ•ต️ Use Case #2: Find Users Who Haven’t Logged In for 6+ Months

This one’s gold for spring cleaning your user base. It checks the LastLogin date and lists users who haven’t logged in since the specified threshold.

Script 1:

Add-Type -AssemblyName "System.Web"
 
# Set the cutoff date (6 months ago)
$cutoffDate = (Get-Date).AddMonths(-6)
 
# Get all Sitecore users
$allUsers = Get-User -Filter *
 
# Create a list of inactive users
$inactiveUsers = @()
 
foreach ($sitecoreUser in $allUsers) {
    $userName = $sitecoreUser.Name
 
    # Get Membership user for accurate LastLoginDate
    $membershipUser = [System.Web.Security.Membership]::GetUser($userName, $false)
 
    # Skip if membership user doesn't exist
    if ($membershipUser -eq $null) {
        continue
    }
 
    $lastLogin = $membershipUser.LastLoginDate
 
    if ($lastLogin -eq $null -or $lastLogin -lt $cutoffDate) {
        $inactiveUsers += [PSCustomObject]@{
            Username   = $sitecoreUser.Name
            FullName   = $sitecoreUser.Profile.FullName
            Email      = $sitecoreUser.Profile.Email
            LastLogin  = if ($lastLogin) { $lastLogin } else { "Never Logged In" }
        }
    }
}
 
# Show the list
$inactiveUsers | Sort-Object LastLogin | Show-ListView -Title "Users Not Logged In in Last 6 Months (Accurate)" -Property Username, FullName, Email, LastLogin

Script 2:

Add-Type -AssemblyName "System.Web"
 
# Get the membership provider (adjust provider name if custom)
$provider = [System.Web.Security.Membership]::Provider
 
# Set cutoff date to 6 months ago
$cutoffDate = (Get-Date).AddMonths(-6)
 
# Prepare list for inactive users
$inactiveUsers = @()
 
# Paging parameters
$pageSize = 1000
$pageIndex = 0
$totalRecords = 0
 
do {
    # Retrieve a page of users
    $usersPage = $provider.GetAllUsers($pageIndex, $pageSize, [ref]$totalRecords)
 
    foreach ($user in $usersPage) {
        # Get LastLoginDate from membership user
        $lastLoginDate = $user.LastLoginDate
 
        if ($lastLoginDate -eq $null -or $lastLoginDate -lt $cutoffDate) {
            # Try to get Sitecore user for profile info
            $sitecoreUser = Get-User -Identity $user.UserName -ErrorAction SilentlyContinue
 
            $inactiveUsers += [PSCustomObject]@{
                "Username"  = if ($sitecoreUser) { $sitecoreUser.Name } else { $user.UserName }
                "FullName"  = if ($sitecoreUser) { $sitecoreUser.Profile.FullName } else { "" }
                "Email"     = if ($sitecoreUser) { $sitecoreUser.Profile.Email } else { "" }
                "LastLogin" = if ($lastLoginDate) { $lastLoginDate } else { "Never Logged In" }
            }
        }
    }
 
    $pageIndex++
} while ($pageIndex * $pageSize -lt $totalRecords)
 
# Output the inactive users sorted by last login date
$inactiveUsers | Sort-Object LastLogin | Show-ListView -Title "Users Not Logged In Last 6 Months" -Property Username, FullName, Email, LastLogin
๐Ÿ’ก Pro Tip: You can combine this with your organizational offboarding process to auto-disable accounts.

❌ Use Case #3: Disable List of Users in Bulk

Need to quickly disable multiple users? Paste a list of usernames and run this batch disable script.

# Prompt for comma-separated list (e.g., amgen\pia,sitecore\admin)
$userList = Read-Host "Enter comma-separated list of usernames or fully qualified usernames to disable"
 
# Split and clean the input
$userNames = $userList -split ',' | ForEach-Object { $_.Trim() }
 
foreach ($userName in $userNames) {
    if ([string]::IsNullOrWhiteSpace($userName)) {
        Write-Host "⚠️ Skipped empty username entry." -ForegroundColor DarkYellow
        continue
    }
 
    # Check if user exists
    $user = Get-User -Identity $userName -ErrorAction SilentlyContinue
 
    if ($user -ne $null) {
        if ($user.IsEnabled) {
            try {
                Disable-User -Identity $userName
                Write-Host "✅ Disabled: $userName" -ForegroundColor Green
            } catch {
                Write-Host "❌ Failed to disable $userName — $($_.Exception.Message)" -ForegroundColor Red
            }
        } else {
            Write-Host "โ„น️ Already disabled: $userName" -ForegroundColor Yellow
        }
    } else {
        Write-Host "❌ User not found: $userName" -ForegroundColor Red
    }
}

๐Ÿง  Use Cases:

  • Security lockdowns
  • Role changes
  • Temporary suspension

✅ Use Case #4: Enable List of Users in Bulk

Just like disabling, enabling a list of users is just as straightforward.

# Prompt for comma-separated list (e.g., amgen\pia,sitecore\admin)
$userList = Read-Host "Enter comma-separated list of usernames or fully qualified usernames to enable"
 
# Split and clean the input
$userNames = $userList -split ',' | ForEach-Object { $_.Trim() }
 
foreach ($userName in $userNames) {
    if ([string]::IsNullOrWhiteSpace($userName)) {
        Write-Host "⚠️ Skipped empty username entry." -ForegroundColor DarkYellow
        continue
    }
 
    # Check if user exists
    $user = Get-User -Identity $userName -ErrorAction SilentlyContinue
 
    if ($user -ne $null) {
        if (-not $user.IsEnabled) {
            try {
                Enable-User -Identity $userName
                Write-Host "✅ Enabled: $userName" -ForegroundColor Green
            } catch {
                Write-Host "❌ Failed to enable $userName — $($_.Exception.Message)" -ForegroundColor Red
            }
        } else {
            Write-Host "โ„น️ Already enabled: $userName" -ForegroundColor Yellow
        }
    } else {
        Write-Host "❌ User not found: $userName" -ForegroundColor Red
    }
}

๐Ÿš€ Ideal for:

  • Reinstating users post-project
  • Bulk onboarding
  • Re-enabling after audits

๐Ÿ—‚️ Optional: Exporting to CSV

You can export results of any of the above scripts for record-keeping:

$inactiveUsers | Export-Csv -Path "C:\SitecoreReports\InactiveUsers.csv" -NoTypeInformation

๐Ÿ”„ Bonus Tip: Automate It!

You can schedule these scripts via Task Scheduler or integrate into a custom Sitecore SPE Job for automation. This ensures your environment stays tidy without manual intervention.

๐Ÿงญ Wrapping Up

Sitecore user management doesn’t have to be tedious. With these PowerShell scripts:

✅ You save time
 ✅ Reduce risk
 ✅ Improve governance
 ✅ Keep your environment secure

๐Ÿ” Whether you’re prepping for an audit, onboarding a team, or cleaning up dormant accounts — PowerShell is your best friend.

๐Ÿ“Œ Have your own PowerShell tips or scripts for Sitecore? Drop them in the comments or connect with me on LinkedIn. Let’s make Sitecore management smarter — together!

References:

https://github.com/gaurarun777/SitecorePowerShell/blob/main/SitecoreEnableListOfUsers.ps1

https://github.com/gaurarun777/SitecorePowerShell/blob/main/SitecoreDisableListOfUsers.ps1

https://github.com/gaurarun777/SitecorePowerShell/blob/main/SitecoreInactiveUsersfrom6months.ps1

https://github.com/gaurarun777/SitecorePowerShell/blob/main/SitecoreInactiveUsersfrom6months_1.ps1

https://github.com/gaurarun777/SitecorePowerShell/blob/main/SitecoreListAlldisabledusers.ps1

I hope you enjoy this Sitecore blog. Stay tuned for more Sitecore related articles.

Till that happy Sitecoring :)

Please leave your comments or share this article if it’s useful for you.

Monday, July 7, 2025

๐Ÿš€ Sitecore 10.4 SXA Upgrade: Language Embedding Issue & Temporary Workaround

Hi everyone! ๐Ÿ‘‹

We recently upgraded our Sitecore platform from version 10.1 to 10.4, along with the SXA module. While the overall upgrade process was largely seamless — thanks to Sitecore’s detailed documentation — we did run into a few unexpected challenges that I believe are worth highlighting. This post is especially for those planning a similar upgrade journey.

If you’re just starting out, I recommend reviewing my earlier blogs where I outline key upgrade steps and best practices. For now, let’s focus on one specific post-upgrade issue we encountered: language embedding in URLs not functioning as expected.

๐Ÿงฉ The Issue: Language Embedding Not Working Properly

Our SXA-based websites rely on language embedding to ensure that URLs include the language code, such as:

https://hostname/en-CA/medical

However, post-upgrade we observed two key problems:

  • The language prefix was not applied at the hostname root.
  • While language switching on the website technically worked, the URL did not reflect the language change, leading to user confusion.

Initially, we suspected a bug in our custom implementation. But after deep investigation and coordination with Sitecore Support, it was confirmed to be a product-level issue. (Reference: Case #CS0585903, awaiting official confirmation.)

The root cause was traced to the SwitchableLinkProvider, which wasn’t honoring the Language Embedding checkbox in the SXA settings. Sitecore acknowledged the issue and has scheduled a fix under reference SXA-8360.

๐Ÿ›  Temporary Fix: Custom Link Provider Implementation

While waiting for the official hotfix, we needed an immediate workaround due to our reliance on this feature across multiple sites.

Here’s the temporary solution we implemented:

  • We configured a custom link provider to replace the default SwitchableLinkProvider.
  • A simple patch config was added.
  • In the SXA Site Grouping settings, we explicitly set the Link Provider name to use our custom provider.

This resolved the language embedding issue across all URLs.

Patch Example:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
   <sitecore>
      <linkManager defaultProvider="switchableLinkProvider" >
         <providers>
            <add name="CustomLinkProvider" type="Sitecore.XA.Foundation.Multisite.LinkManagers.LocalizableLinkProvider, Sitecore.XA.Foundation.Multisite" lowercaseUrls="true" languageEmbedding="always" addAspxExtension="false" />
         </providers>
      </linkManager>
   </sitecore>
</configuration>

⚠️ Note: This is a temporary workaround. We’re still awaiting the official Sitecore patch and will share updates once it’s available.

๐Ÿ’ฌ Final Thoughts

Upgrading to newer Sitecore versions — especially when SXA is involved — can surface subtle yet impactful issues. The important takeaway:

  • Stay proactive,
  • Don’t hesitate to involve Sitecore Support, and
  • Be open to temporary creative workarounds when business continuity is on the line.

๐Ÿ’ก “There are many solutions to a problem. The challenge is identifying the right one at the right time.”

Happy coding! ๐Ÿ”ง
 Have you encountered similar issues during your upgrade? I’d love to hear your experiences and solutions in the comments.

I hope you enjoy this Sitecore blog. Stay tuned for more Sitecore related articles.

Till that happy Sitecoring :)

Please leave your comments or share this article if it’s useful for you.