Generate a random strong password in PowerShell

I’ve created this PowerShell function that allows you generate any random strong password.

With this method, the caller is able to specify:

  1. The desired password length (minimum = 4)
  2. Whether or not to use lowercase characters
  3. Whether or not to use uppercase characters
  4. Whether or not to use numbers
  5. Whether or not to use special characters
  6. Whether or not to avoid using similar characters ( e.g. i, l, o, 1, 0, I)

The function ensures that each type of character (lowercase, uppercase, number and/or special) is included at least once in the password.

Examples of how to use this:

  • GeneratePassword
    Generates a password using the default settings (length of 8, using a combination of lowercase, uppercase and numbers, while avoiding similar characters), e.g. YeM2B98r
  • GeneratePassword 16
    Generates a longer password using the default settings (length of 16, using a combination of lowercase, uppercase and numbers, while avoiding similar characters), e.g. 89p4758unWt2HDnp
  • GeneratePassword 4 $false $false
    Generates a 4 digit numeric PIN code, e.g. 8298
  • GeneratePassword 8 $true $true $true $true
    Generates an extra strong password, (length of 8, using a combination of lowercase, uppercase, numbers and special characters, while avoiding similar characters), e.g. 9c+9P=#z
  • GeneratePassword 20 $true $true $true $true $false
    Generates an extra strong password, (length of 20, using a combination of lowercase, uppercase, numbers and special characters with possible similar characters), e.g. YCi+R8?vVl1H!B+5hZU8

You can grab the script here (double-click it to copy):

function GeneratePassword() {
    Param (
    [int]$length = 8,    
    [bool] $includeLowercaseLetters = $true,
    [bool] $includeUppercaseLetters = $true,
    [bool] $includeNumbers = $true,
    [bool] $includeSpecialChars = $false,
    [bool] $noSimilarCharacters = $true
    )

    <#
    (c) Morgan de Jonge CC BY SA
    Generates a random password. you're able to specify:
    - The desired password length (minimum = 4)
    - Whether or not to use lowercase characters
    - Whether or not to use uppercase characters
    - Whether or not to use numbers
    - Whether or not to use special characters
    - Whether or not to avoid using similar characters ( e.g. i, l, o, 1, 0, I)
    #>

    # Validate params
    if($length -lt 4) {
        $exception = New-Object Exception "The minimum password length is 4"
        Throw $exception
    }
    if ($includeLowercaseLetters -eq $false -and 
            $includeUppercaseLetters -eq $false -and
            $includeNumbers -eq $false -and
            $includeSpecialChars -eq $false) {
        $exception = New-Object Exception "At least one set of included characters must be specified"
        Throw $exception
    }

    #Available characters
    $CharsToSkip = [char]"i", [char]"l", [char]"o", [char]"1", [char]"0", [char]"I" 
    $AvailableCharsForPassword = $null;
    $uppercaseChars = $null 
    for($a = 65; $a -le 90; $a++) { if($noSimilarCharacters -eq $false -or [char][byte]$a -notin $CharsToSkip) {$uppercaseChars += ,[char][byte]$a }}
    $lowercaseChars = $null
    for($a = 97; $a -le 122; $a++) { if($noSimilarCharacters -eq $false -or [char][byte]$a -notin $CharsToSkip) {$lowercaseChars += ,[char][byte]$a }}
    $digitChars = $null
    for($a = 48; $a -le 57; $a++) { if($noSimilarCharacters -eq $false -or [char][byte]$a -notin $CharsToSkip) {$digitChars += ,[char][byte]$a }}
    $specialChars = $null
    $specialChars += [char]"=", [char]"+", [char]"_", [char]"?", [char]"!", [char]"-", [char]"#", [char]"$", [char]"*", [char]"&", [char]"@"

    $TemplateLetters = $null
    if($includeLowercaseLetters) { $TemplateLetters += "L" }
    if($includeUppercaseLetters) { $TemplateLetters += "U" }
    if($includeNumbers) { $TemplateLetters += "N" }
    if($includeSpecialChars) { $TemplateLetters += "S" }
    $PasswordTemplate = @()
    # Set password template, to ensure that required chars are included
    do {   
        $PasswordTemplate.Clear()
        for($loop = 1; $loop -le $length; $loop++) {
            $PasswordTemplate += $TemplateLetters.Substring((Get-Random -Maximum $TemplateLetters.Length),1)
        }
    }
    while ((
        (($includeLowercaseLetters -eq $false) -or ($PasswordTemplate -contains "L")) -and
        (($includeUppercaseLetters -eq $false) -or ($PasswordTemplate -contains "U")) -and
        (($includeNumbers -eq $false) -or ($PasswordTemplate -contains "N")) -and
        (($includeSpecialChars -eq $false) -or ($PasswordTemplate -contains "S"))) -eq $false
    )
    #$PasswordTemplate now contains an array with at least one of each included character type (uppercase, lowercase, number and/or special)

    foreach($char in $PasswordTemplate) {
        switch ($char) {
            L { $Password += $lowercaseChars | Get-Random }
            U { $Password += $uppercaseChars | Get-Random }
            N { $Password += $digitChars | Get-Random }
            S { $Password += $specialChars | Get-Random }
        }
    }

    return $Password
}

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Remove Timeline from a task view using PowerShell

If you create a new view for a SharePoint 2013 task list, you’ll get a timeline above the task items table.

Should you want to remove this timeline from the view using PowerShell, you should alter the ViewData property for the view.

Initially, this property contains the following data:

<FieldRef Name="PercentComplete" Type="StrikeThroughPercentComplete" /><FieldRef Name="DueDate" Type="TimelineDueDate" />

Simply remove the second FieldRef element from the view’s ViewData to remove the Timeline from the view:

$web = Get-SPWeb <insert web URL>
$view = $web.GetViewFromUrl(<insert view URL>
$view.ViewData = "<FieldRef Name=`"PercentComplete`" Type=`"StrikeThroughPercentComplete`" />"
$view.Update()
$web.Dispose()

Updating the User Information List in SharePoint 2010 from AD

In some cases, there is no need for User Profiles and My Sites. However, when you’re using Active Directory for authentication, you might notice that changes made to the AD Domain users are not effective for SharePoint users, such as a different or new email address. When you click “My Settings” from the user menu, you’ll still see the old values for name, email address, etc.

A simple way of solving this is using the Set-SPUser cmdlet in PowerShell, using the -SyncFromAD parameter. However, when you have multiple site collections with multiple users, you’ll need to do this for each user, in each site collection’s top level site.

The following PowerShell script will save you the trouble of going through this manually, it fetches all site collections with their RootWebs and syncs all available SPUser objects with AD.

Make sure you run it under a user that has access to each site collection, preferably as a site collection administrator.

$sites = Get-SPSite -Limit All
foreach($site in $sites) {
    $web = $site.RootWeb
    if($web -ne $null) {
        Write-Host "Processing: $site"
        Get-SPUser -Limit All -web $web | foreach {
            if ($site.WebApplication.UseClaimsAuthentication) {
                $claim = New-SPClaimsPrincipal $_.LoginName -IdentityType WindowsSamAccountName
                $user  = $web | Get-SPUser -Identity $claim -ErrorAction SilentlyContinue
            }
            else
            {
                $user = $web | Get-SPUser -Identity $_.LoginName -ErrorAction SilentlyContinue
            }
            if ($user -ne $null)
            {
                Set-SPUser -Identity $user -web $web -SyncFromAD -ErrorAction SilentlyContinue
            }
        }
    }
    $web.Dispose()
    $site.Dispose()
}

 

Using Powershell to Add Permission Levels in SharePoint 2010

Besides using PowerShell to modify or adding list permissions, you can also add new Permission Levels. As permission levels don’t persist within site templates, this can be handy when creating deployment scripts for new sites.

Here’s how you do it:

# Add Permission Level to a site
# (c) 2011 Morgan de Jonge

$spSite = Get-SPSite "http://portal.contoso.com"
# We'll assume the list is in the top-level site in the site collection
$spWeb = $spSite | Get-SPWeb

# In this example, we add a new Permission Level labelled "Add Only" to the site, which will allow users to only add new items (no editing or removing)
if($spWeb.RoleDefinitions["Add Only"] -eq $null)
{
    # Role Definition named "Add Only" does not yet exist
    $spRoleDefinition = New-Object Microsoft.SharePoint.SPRoleDefinition
    $spRoleDefinition.Name = "Add Only"
    $spRoleDefinition.Description = "Can only Add items. Use this Permission Level for List or Library Permissions."
    # .Type is a ReadOnly property, hence it'll remain on "None".

    # Use the command [System.Enum]::GetNames("Microsoft.SharePoint.SPBasePermissions") to get a list of possible BasePermission values
    # For this Permission Level, we'll add four base permissions:
    $spRoleDefinition.BasePermissions = "ViewListItems, AddListItems, Open, ViewPages"
    $spWeb.RoleDefinitions.Add($spRoleDefinition)
}

#Display the properties for our new Permission level
$spWeb.RoleDefinitions["Add Only"] | Out-Host

$spWeb.Dispose()
$spSite.Dispose()

Unfortunately, the RoleDefinition.Type property, which contains a RoleType Enum value,  is Read-Only. Hence, it’ll get the default value “None”.

The .BasePermissions Property is a flags attribute which contains the actual permissions granted to users and groups assigned with the permission level. See MSDN for a description of these Permissions, or use the following command to enumerate them in PowerShell:

# Enumerate through SPBasePermissions
PS > [System.Enum]::GetNames("Microsoft.SharePoint.SPBasePermissions")
EmptyMask
ViewListItems
AddListItems
EditListItems
DeleteListItems
ApproveItems
OpenItems
ViewVersions
DeleteVersions
CancelCheckout
ManagePersonalViews
ManageLists
ViewFormPages
Open
ViewPages
AddAndCustomizePages
ApplyThemeAndBorder
ApplyStyleSheets
ViewUsageData
CreateSSCSite
ManageSubwebs
CreateGroups
ManagePermissions
BrowseDirectories
BrowseUserInfo
AddDelPrivateWebParts
UpdatePersonalWebParts
ManageWeb
UseClientIntegration
UseRemoteAPIs
ManageAlerts
CreateAlerts
EditMyUserInfo
EnumeratePermissions
FullMask

See the modify or adding list permissions article for instructions on how to assign this new Permission Level to a user or group.

Modifying list permissions from Powershell

There can be cases where you need to make changes to list permissions or list behaviour regarding security from PowerShell. One case may be where a saved site template does not contain all settings for a list, such as Item-level permission settings (found in List Settings → Advanced Settings). Another case may be a list with unique permissions.

This post contains two examples for making changes to these kind of list settings and permissions from Powershell. These are taken from a deployment script I created for a client.

This script will alter the Item-level Permissions for a list called “Questions” so that users can only access and edit list items they themselves created:

Furthermore, it adds Contribute permissions to the Visitors group for the list, providing unique list permissions (breaking inheritance).

# Alter Item-Level Permission settings and assign "Contribute" role definition to the visitors group
# (c) 2011 Morgan de Jonge

# Specify the name of the visitors SharePoint group
$visitorsSPGroupName = "Example Site Visitors"

$spSite = Get-SPSite "http://portal.contoso.com"
# We'll assume the list is in the top-level site in the site collection
$spWeb = $spSite | Get-SPWeb
# Look up the list named "Questions"
$questionsList = $spWeb.Lists["Questions"]

# Set the Read access Item-level permissions settings to "Read items that were created by the user"
$questionsList.ReadSecurity = 2
# Set the Create and Edit access Item-level permissions to "Create items and edit items that were created by the user
$questionsList.WriteSecurity = 2

# Assign the "Contribute" RoleDefition to the site's visitors group
$visitorsSPGroup = $spWeb.Groups[$visitorsSPGroupName]
$questionsList.BreakRoleInheritance($true)
$assignment = New-Object Microsoft.SharePoint.SPRoleAssignment($visitorsSPGroup)
# Assuming this is a default site, we'll look for a role definition of the type "Contributer".
# This way, the script will also work with SharePoint sites created in languages besides English.
$assignment.RoleDefinitionBindings.Add(($spWeb.RoleDefinitions | Where-Object { $_.Type -eq "Contributor" }))
$questionsList.RoleAssignments.Add($assignment)

$questionsList.Update()

$spWeb.Dispose()
$spSite.Dispose()
(To copy this code, double-click the anywhere in the code and press CTRL/Cmd+C to copy it)

In line 24, you could’ve also looked up the role using $spWeb.RoleDefinitions[“Contribute”], but selecting it based on type will ensure it also works with SharePoint sites in different languages.

See MSDN for the possible values for a list’s ReadSecurity and WriteSecurity.

Count all lists and list items in a site collection

I was recently asked how to inventorize all lists and list items for all sites in a site collection.

Here’s a PowerShell script that does exactly that, displaying the SharePoint site and List name, with the number of items per list:

$ListsInfo = @{}
$TotalItems = 0
$SiteCollection = Get-SPSite "http://<<SiteCollectionURL>>/"
ForEach ($Site in $SiteCollection.AllWebs)
{
    ForEach ($List in $Site.Lists)
    {
        $ListsInfo.Add($Site.Url + " - " + $List.Title, $List.ItemCount)
        $TotalItems += $List.ItemCount
    }
}
$ListsInfo.GetEnumerator() | sort name | Format-Table -Autosize
Write-Host "Total number of Lists: " $ListsInfo.Count
Write-Host "Total number of ListItems: " $TotalItems
(To copy this code, double-click the anywhere in the code and press CTRL/Cmd+C to copy it)

Replace the http://<<SiteCollectionURL>>/ string with the URL for your site collection.

How to find the SharePoint Server 2010 version

In some cases, i.e. installing a language pack, it’s handy to know which version of SharePoint you’re running exactly.

One way is to use Central Administration, go to System SettingsManage servers in this farm.

Or you can use PowerShell:

(Get-SPFarm).buildversion

The most common build numbers are:

  • 14.0.4762.1000 – RTM
  • 14.0.6029.1000 – SP1
  • 14.0.6109.5000 / .5002 – August 2011 CU

For a full list of build numbers, see Todd Klindt’s SharePoint Admin Blog.

List of all databases used by a SharePoint 2010 farm

Someone recently asked me how to get a listing of databases used by a farm, with the server instance name and database names.

There are ways to retrieve this info from Central Administration, but PowerShell makes your life much easier:

Get-SPDatabase | select name, databaseconnectionstring

Where the Data Source element in the Connection String contains the exact DB server instance used by the farm.

Using SharePoint Powershell from PowerShell ISE

Whoever has worked with PowerShell probably came to the same conclusion: this stuff is potent and powerful!

The ‘standard’ SharePoint 2010 Management Shell does have some drawbacks.

Working with a Command-Prompt-like environment does not appeal to everyone, especially those used to visual IDE’s like Visual Studio. Fortunately, PowerShell v2 comes with PowerShell ISE, a more visual experience that makes it much easier to work with scripts. This is available by default on Windows 7 and can be enabled as a feature on Windows Server 2008, using the following PowerShell command:

Add-WindowsFeature PowerShell-ISE

You can now find PowerShell ISE shortcuts in the Start Menu.

However, when you start PowerShell ISE, you’ll find that it only works with Windows cmdlets. For PowerShell ISE to work with SharePoint cmdlets, you’ll only need to add a PowerShell Snapin, using the following command.

Add-PSSnapin Microsoft.SharePoint.PowerShell

After this, you’ll be able to access the SharePoint commandlets, whose noun all start with “sp”.

Now if you’re like me, you’ll always want these SharePoint cmdlets available from PowerShell ISE. Zubair Alexander posted a way of doing this earlier this year on his blog.

  1. You can check if a PowerShell profile is available for your current identity using the Test-Path $profile command. This will return true if a profile is present and false if not.
  2. You can create a new profile for your identity by using the following command:
    Test-Path $profile
    if (!(test-path $profile)) {new-item -type file -path $profile -force}

    This will perform a “Create Directory” operation on the target destination folder C:\Users\<username>\Documents\WindowsPowerShell, and add a file titled “Microsoft.PowerShellISE_profile.ps1” to this folder.

  3. Now, use PowerShell ISE to open the newly created .ps1 file
  4. Add the command
    Add-PSSnapIn Microsoft.SharePoint.PowerShell

    (and any other commands you want to automatically run when you open PowerShell ISE) to the file and press Save.

  5. Restart PowerShell ISE. You’ll now find you’ll be able to access all SharePoint cmdlets directly, each time you run PowerShell ISE on this machine.