A question we sometimes need, but can't get from SharePoint is users last logon time. Usually you have an environment where a user signs in to the network and is authorized to access the company intranet without further password requirements in a single sign on environment. But the information isn't stored in SharePoint, so we can't get it from there.
However, the information is stored in Active Directory, and by importing it, you can get the information when all of your users where last active (logon) on your domain.
# Load the SharePoint cmdlets
$snapin = Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'}
if ($snapin -eq $null)
{
Write-Host "Loading SharePoint Powershell Snapin"
Add-PSSnapin "Microsoft.SharePoint.Powershell" -EA SilentlyContinue
}
# Import ActiveDirectory cmdlets
Import-Module ActiveDirectory
# Here's the function that will return the last logon date and time
function Get-ADUserLastLogon([string]$userName)
{
$dcs = Get-ADDomainController -Filter {Name -like "*"}
$time = 0
foreach($dc in $dcs)
{
$hostname = $dc.HostName
$user = Get-ADUser $userName | Get-ADObject -Properties lastLogon
if($user.LastLogon -gt $time)
{
$time = $user.LastLogon
}
}
$dt = [DateTime]::FromFileTime($time)
Write-Host $username "last logged on at:" $dt
}
# Get the user profiles
$site = Get-SPSite "https://intranet.company.com/"
$context = Get-SPServiceContext $site
$profileManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context)
$profiles = $profileManager.GetEnumerator()
# Iterate all profiles and grab the users last logon date time and write to console
foreach($user in $profiles)
{
Get-ADUserLastLogon -UserName $user["UserName"]
}
Reference: Determining a User's Last Logon Time
August 12, 2013
August 7, 2013
Make metadata column containing multiple terms readable with PowerShell
Sometimes
you find yourself in a situation where you need to read the metadata column,
which contains multiple values. These values are sometimes hard to read, and
contain a lot of extra information (that you may or may not need) that needs to
be stripped, to make the report readable. The string may look like this:
10;#Process|c6a2e0b3-0ac7-41d3-a0d4-bfca9d113c2f;#35;#Report|ea772779-c5ca-4992-a338-ff686479032f;#31;#Policy|523d8c9b-23b7-4746-96f2-a497f37012fb
But what
you really want is Process;Report;Policy which is stripped from the column
value. Starting in the beginning lets add the PSSnapin to our PowerShell if it’s
not loaded.
$snapin =
Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'}
if ($snapin
-eq $null)
{
Write-Host "Loading SharePoint
Powershell Snapin"
Add-PSSnapin
"Microsoft.SharePoint.Powershell"
-EA SilentlyContinue
}
Hook up to
your web and iterate yourself down to the metadata column.
$url = "https://intranet.company.com/document-center/"
$web =
Get-SPWeb $url
foreach($list
in $web.Lists)
{
if($list.BaseType -eq
"DocumentLibrary")
{
foreach($item in $list.items)
{
$file = $item.File
Having an
instance of the file, makes us check whether or not the metadata column has any
value. If it has any value, let’s clean it from the ugly output
# Subject
if($file.Properties["Subject"]
-ne "")
{
$Subject = $file.Properties["Subject"]
if($Subject -like '*#*')
{
At first,
we need to find out how many occurrence’s we have of the hash-character through
the following script
$SubjectSplit =
""
$char = "#"
$result =
0..($Subject.length -1) | ? {$Subject[$_] -eq $char}
Calling $result.count
will give us the number of times “#” is used in the string. When we know that,
we can iterate over the string and pull the information we need. We’re
separating terms by semi colon “;” which unfortunately leaves one extra “;” in
the end
for($i=1; $i -le
$result.count;$i=$i+2)
{
$SubjectSplit =
$SubjectSplit + $Subject.split("#")[$i].split("|")[0] +
";"
}
But it’s
quite easy to remove
$Subject =
$SubjectSplit.TrimEnd(";")
And finally
write the output to the host, so you know you got it right before putting the
information in a csv-file.
}
}
Write-Host $Subject
}
}
}
$web.Dispose();
The
complete script:
$snapin = Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'}
if ($snapin -eq $null)
{
Write-Host "Loading SharePoint Powershell Snapin"
Add-PSSnapin "Microsoft.SharePoint.Powershell" -EA SilentlyContinue
}
$url = "https://intranet.company.com/document-center/"
$web = Get-SPWeb $url
foreach($list in $web.Lists)
{
if($list.BaseType -eq "DocumentLibrary")
{
foreach($item in $list.items)
{
$file = $item.File
# Subject
if($file.Properties["Subject"] -ne "")
{
$Subject = $file.Properties["Subject"]
if($Subject -like '*#*')
{
$SubjectSplit = ""
$char = "#"
$result = 0..($Subject.length -1) | ? {$Subject[$_] -eq $char}
for($i=1; $i -le $result.count;$i=$i+2)
{
$SubjectSplit = $SubjectSplit + $Subject.split("#")[$i].split("|")[0] + ";"
}
$Subject = $SubjectSplit.TrimEnd(";")
}
}
Write-Host $Subject
}
}
}
$web.Dispose();
June 25, 2013
Add user permission to a all webs/sites if missing.
Sometimes you find yourself in a situation where you need to give specific permission to users on all sites and webs in your farm. To avoid duplicates, first check if the user has got permission on the site/web before adding another line of user to your permission list.
$contentWebAppServices = (Get-SPFarm).services |
? {$_.typename -eq "Microsoft SharePoint Foundation Web Application"}
foreach($webApp in $contentWebAppServices.WebApplications)
{
Write-Host "Web Application : " $webApp.name
foreach ($site in $webApp.Sites)
{
Write-Host " " $site.url -foregroundcolor "yellow"
foreach ($web in $site.AllWebs)
{
Write-Host " " $web.title -foregroundcolor "magenta"
$permission = Get-SPUser -Web $web.url -Limit All | select UserLogin, @{name="Exlicit given roles";expression={$_.Roles}}, @{name="Roles given via groups";expression={$_.Groups | %{$_.Roles}}},Groups | Where-Object {$_.UserLogin -like "domain\user"}
if ($permission -notlike "Full Control")
{
Write-Host " User hasn't got permission." -foregroundcolor "red"
Set-SPUser -Identity 'domain\user' -Web $web.url -AddPermissionLevel "Full Control"
}
else
{
Write-Host " User has got permission." -foregroundcolor "green"
}
}
$site.dispose()
}
}
$contentWebAppServices = (Get-SPFarm).services |
? {$_.typename -eq "Microsoft SharePoint Foundation Web Application"}
foreach($webApp in $contentWebAppServices.WebApplications)
{
Write-Host "Web Application : " $webApp.name
foreach ($site in $webApp.Sites)
{
Write-Host " " $site.url -foregroundcolor "yellow"
foreach ($web in $site.AllWebs)
{
Write-Host " " $web.title -foregroundcolor "magenta"
$permission = Get-SPUser -Web $web.url -Limit All | select UserLogin, @{name="Exlicit given roles";expression={$_.Roles}}, @{name="Roles given via groups";expression={$_.Groups | %{$_.Roles}}},Groups | Where-Object {$_.UserLogin -like "domain\user"}
if ($permission -notlike "Full Control")
{
Write-Host " User hasn't got permission." -foregroundcolor "red"
Set-SPUser -Identity 'domain\user' -Web $web.url -AddPermissionLevel "Full Control"
}
else
{
Write-Host " User has got permission." -foregroundcolor "green"
}
}
$site.dispose()
}
}
May 24, 2013
UnGhosting Customized Page Layouts with PowerShell
Sometimes
you end up in a solution where someone have been kind enough to use SharePoint
Designer to edit a Page Layout. This means that you are not able to change the
Page Layout through your deployed code, in a package. Changes made in the
development environment doesn’t show up in production. Your Page Layout is in a
Ghosted mode of its origin, and we need to Un-Ghost the Page Layout to be able
to change it from a package created in our development environment.
Thus you
use this script to first find out which Page Layouts have been changed, and
uncomment the Revert Content Stream to actually change the Page Layout back to
an UnGhosted mode.
$s = Get-SPSite https://siteCollectionUrl
$w = $s.RootWeb
$ps = New-Object Microsoft.SharePoint.Publishing.PublishingSite($s)
$pls = $ps.PageLayouts
foreach ($pl in $pls)
{
$f = $w.GetFile($pl.ServerRelativeUrl)
if ($f.CustomizedPageStatus -eq "Customized")
{
Write-Host
Write-Host "Layout page name: " -NoNewline
Write-Host $f.Name
Write-Host "Status before: " -NoNewline
Write-Host $f.CustomizedPageStatus
#$f.RevertContentStream()
Write-Host "Status after: " -NoNewline
Write-Host $f.CustomizedPageStatus
}
}
$w.Dispose()
$s.Dispose()
April 10, 2013
SharePoint 2010 PowerShell: List all Web Applications deployed solutions
When you need to know which wsp solution is deployed to which Web Application the following script can be of use. First, get all your web applications and iterate through them. While in the loop print web application name and application pool name. Last, iterate all solutions and print their names - like this:
# Get all installed solutions per web application
$contentWebAppServices = (Get-SPFarm).services |
? {$_.typename -eq "Microsoft SharePoint Foundation Web Application"}
foreach($webApp in $contentWebAppServices.WebApplications)
{
Write-Host "Web Application : " $webApp.name
Write-Host "Application Pool : " $webApp.ApplicationPool.Name
Get-SPSolution | ForEach-Object {
if ($_.LastOperationDetails.IndexOf($webApp.url) -gt 0)
{
Write-Host " Solutions:"
Write-Host " " $_.DisplayName
}
}
}
The output looks like this:
Web Application : SharePoint - 1337
Application Pool : SharePoint - 1337
Web Application : SharePoint - 80
Application Pool : SharePoint - 80
Solutions:
customer.intranet.wsp
The first web application (SharePoint - 1337) doesn't have deployed solutions, but the second (SharePoint - 80) has one.
if ($_.LastOperationDetails.IndexOf($webApp.url) -gt 0)
{
Write-Host " Solutions:"
Write-Host " " $_.DisplayName
}
}
}
The output looks like this:
Web Application : SharePoint - 1337
Application Pool : SharePoint - 1337
Web Application : SharePoint - 80
Application Pool : SharePoint - 80
Solutions:
customer.intranet.wsp
The first web application (SharePoint - 1337) doesn't have deployed solutions, but the second (SharePoint - 80) has one.
March 8, 2013
SharePoint 2010: Iterate all webs in Web Application
Sometimes you're just there and need to do something with all of your SPWebs, but have the unfortunate structure of having http://Portal/Sites/SiteCollections in your architecture. There is a way out which is quite simple and working very well. All you need to do is to get hold of all the SiteCollections (SPSite) in the WebApplication (http://portal).
$SPWebApp = Get-SPWebApplication "http://portal/" foreach ($SPSite in $SPWebApp.Sites) { if ($SPSite -ne $null) { foreach ($SPWeb in $SPSite.AllWebs) { Write-Host $SPWeb.Title if ($SPWeb -ne $null) { $SPWeb.Dispose() } } } if ($SPSite -ne $null) { $SPSite.Dispose() } }
You also have the benefit of not missing a web inside an entire Web Application.
February 19, 2013
SharePoint 2010: Migrate Users to new Active Directory Environment
When switching from one AD-environment to another, you sometimes end up with users who don't get imported correct. You see them when they don't have first name and last name when they are logged in to SharePoint. They have <domain>\<username> visible instead.
But let's start from the beginning and migrate the users with the following command:
After that you need to run a full user profile synchronization. When this is done, continue and see which users where not imported correct.
Reference: SharePoint 2010–User Information Lists and User Profile Cleanup
But let's start from the beginning and migrate the users with the following command:
STSADM –o migrateuser –oldlogin OLDDOMAIN\user1 –newlogin NEWDOMAIN\user1 –ignoresidhistory
After that you need to run a full user profile synchronization. When this is done, continue and see which users where not imported correct.
# Clean up accounts that is not imported correctly $upsa = Get-SPServiceApplication | Where-Object {$_.TypeName -like "User Profile Service Application"} # List all user accounts that is not imported correctly Set-SPProfileServiceApplication $upsa -GetNonImportedObjects $true # Remove user accounts not imported correctly # Uncomment line below to run Set-SPProfileServiceApplication $upsa -PurgeNonImportedObjects $true # Run a full User Profile Service Syncronisation, and make sure users # end up in Profile database. # If not, users who log in will create new NonImportedObject accounts
This might have to be repeated several times, especially if you're in a live environment where users login during the day. Eventually these orphan user profiles will disappear.
If you have a lot of users, the script will take a lot of time - so please be patient unless you get an error from PowerShell.
Good Luck!
Reference: SharePoint 2010–User Information Lists and User Profile Cleanup
Subscribe to:
Posts (Atom)