Showing posts with label Prashanth Padebettu. Show all posts
Showing posts with label Prashanth Padebettu. Show all posts

Thursday, December 3, 2015

PowerShell for Office 365

We can use the admin center of Office 365 for managing Office 365 and SharePoint Online. However, if we use the PowerShell for Office 365 to create scripts for regular tasks, it will be much easier and consistent on an ongoing basis. Lets explore how we can leverage PowerShell for Office 365 from a remote machine.

In order to be able to run PowerShell commands for Office 365 you need to have the administrator rights. Also, the remote machine where you plan to run the PowerShell commands should be a 64-bit machine with at least Windows 7 or Windows Server 2008 R2. Go ahead and install the following where you will be running the PowerShell commands:

  • Microsoft Online Services Sign-in Assistant
  • Azure Active Directory Module

Managing Office 365

The first step is to import the MSOnline module into PowerShell session

Import-Module MSOnline

Next, get the admin credential into a variable.

$credential = Get-Credential 

After running this command a login prompt pops up. Give the Office 365 admin credentials. The credentials will not be validated. It will just be stored in the variable.

Get Credential

Now, you can establish the connection using the credential variable.

Connect-MsolService -Credential $credential

If the entered credentials is correct, the connection will be established. After that, you can start issuing the commands for the Office 365 operations.

The PowerShell commands for Office 365 follow a naming convention of

<verb>-Msol<noun> . Here the Msol stands for the Microsoft Online(The module which we have imported).

Suppose I wanted to update my Job Title to “The SharePoint Guide”, I can give a command as follows. It is required to specify the UserPrincipalName as it will indicate which user details we are updating.

Set-MsolUser -UserPrincipalName spdev@archit.onmicrosoft.com -Title "The SharePoint Guide" 

After executing this command, if I check by Office 365 Admin portal -> Users -> Edit User -> Additional Details,
I can see that the Job Title change is reflecting.

User Details

If you want to add a security group (e.g SharePoint Developers) in your Azure AD for your Office 365 tenant, you can run the command

New-MsolGroup –DisplayName “Developers” –Description “SharePoint Developers”

To add a member to this group, first you need to get the user.

$member = Get-MsolUser -UserPrincipalName spdev@archit.onmicrosoft.com 

Then, get the group and add the member.

$group = Get-MsolGroup | Where-Object {$_.DisplayName –eq “Developers”} Add-MsolGroupMember -GroupObjectId $group.ObjectId -GroupMemberType "user" -GroupMemberObjectId $member.ObjectId 

In Office 365 Admin portal -> Azure AD -> Groups, we can see the Group is created and the user is added to the group.

AD Group

When you have a lot of users to be added, or a lot of details that need to be updated, it will be much easier to create a script and execute it. Also, since you will keep all the user details in a file (which we can read from the script), you will have a record of what data has been updated.

Managing SharePoint Online

In order to be able to run some of these commands, you need to be the SharePoint Online Global Admin

Prerequisites

  1. Atleast Windows Powershell 3.0
  2. SharePoint Online Management Shell

Once you have installed the above prerequisites, open up the SharePoint Online Management Shell.

As in Office 365, you need to get the credential

$credential = Get-Credential 

This command will open up the pop up to enter the username and password of the SharePoint Online admin.

The commands for SharePoint Online will be of the format:

<verb>-SPO<noun> where the SPO stands for SharePoint Online.

First, you need to connect to the SharePoint tenant.

Connect-SPOService -Url http://ift.tt/1SzqLF2 -Credential $credential 

Once you are connected successfully, you can issue the commands specific to your SharePoint online tenant

Get-SPOSite will list all the site collections within the tenant

Get-SPOSite | Select URL 

If you want to change some properties of the site for example the Title

First, you need to get the specific site by specifying the url. Then use the Set-SPOSite command

$site = Get-SPOSite http://ift.tt/1QWgVj9 Set-SPOSite $site -Title "The SharePoint Guide"

Once you have got a reference to the site, you can use the built in commands. For example, the following commands gets all the users in the site.

Get-SPOUser -Limit All -Site $site

The -Limit All will ensure all the users are listed

By default, when you access SharePoint online with the built in commands you can only do some limited things such as updating the site collection, site and user details.

However, when you use the SharePoint Client side object model with PowerShell, you will have much more functionality available such as updating Lists, List items etc. Basically, everything that you could do with SharePoint Client side object model.

I will do another post on using the Client Side Object Model with PowerShell.

Check out this article and other articles on my blog at PowerShell for Office 365


by Prashanth Padebettu via Everyone's Blog Posts - SharePoint Community

Saturday, September 5, 2015

SharePoint Search - how to return all results

SharePoint Search - how to return all results

By default, when we use the Search API, SharePoint limits the number of items retrieved. If your query returns a number of items within this limit, then it is not a problem. However, if your query results in a larger set, then by default those items will not be present in the result set.

I noticed that when using KQL, by default SharePoint limits the results to 50 rows. We can explicitly set the RowLimit up to 500. When using the REST API using JavaScript, I noticed that the results were limited to 500. If our result set contains more items, then we need a mechanism to retrieve the other results. 

We might want to include all the results in one single unit such as in a report. Or, we might want to show a initial set of results and then page through the remaining results. In either case, we need to be able to retrieve sections of the results at a time. In case we want to create a single report, we can merge them together. 

This can be done by keeping the current row index value(which is the last row of the current result set), looping through the pages and updating the current row index after fetching the current page. 

For this, lets set the RowLimit to 50. Then, if the TotalRows is greater than the row count of the returned results, get the additional rows.

KeywordQuery keywordQuery = new KeywordQuery(siteCollection);

SearchExecutor searchExecutor = new SearchExecutor();
keywordQuery.QueryText = "KQL Query String";
keywordQuery.StartRow = 0;
keywordQuery.RowLimit = 50;

//retrieve the first page of results
ResultTableCollection resultTableCollection = searchExecutor.ExecuteQuery(keywordQuery);
var resultTables = resultTableCollection.Filter("TableType", KnownTableTypes.RelevantResults);
var resultTable = resultTables.FirstOrDefault();
DataTable resultDataTable = resultTable.Table;

int currentRowIndex = 0;
//Iterate through the rest of the pages
while (resultTable.TotalRowsIncludingDuplicates > resultDataTable.Rows.Count)
{
//Update the current row index
currentRowIndex += resultDataTable.Rows.Count;
resultTableCollection = GetSearchResults(keywordQuery, currentRowIndex, searchExecutor);
var searchResults = resultTableCollection.FirstOrDefault();
if (searchResults.RowCount <= 0)
break;
else
resultDataTable.Merge(searchResults.Table);
}

private ResultTableCollection GetSearchResults(KeywordQuery keywordQuery, int startIndex, SearchExecutor searchExecutor)
{
ResultTableCollection resultTableCollection = null;
try
{
//keyword search using "Default Provider" .
keywordQuery.ResultsProvider = SearchProvider.Default;
keywordQuery.StartRow = startIndex;//gets or sets the first row of information from the search results

// execute the query and load the results into a collection
resultTableCollection = searchExecutor.ExecuteQuery(keywordQuery);
}
catch (Exception ex)
{
}
return resultTableCollection;
}

After executing the above code the resultDataTable will have the complete results even if it is a large result set.

Doing this using JavaScript and REST API, is a bit more tricky. The key thing here is to make the recursive call from the success handler. This is because we want to merge the results of all the individual pages of information.

var allResults;
function yourFunction() {
var searchUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/search/postquery";
postData = {
'request': {
'__metadata': { 'type': 'Microsoft.Office.Server.Search.REST.SearchRequest' },
'Querytext': "sharepoint",
'RowLimit': '50',
'SortList':
{
'results': [
{
'Property': 'Created',
'Direction': '1'
}
]
}
}
};
allResults = [];
searchSharePoint(searchUrl, 0);
}

function searchSharePoint(searchUrl, startRow, allResults) {
//initialize to empty array if it does not exist
allResults = allResults || [];
postData.request.StartRow = startRow;

$.ajax(
{
type: "POST",
headers: {
"accept": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
data: JSON.stringify(postData),
url: searchUrl,
success: onQuerySuccess,
error: onQueryFail
});
}

function onQuerySuccess(data) {
var searchUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/search/postquery";
var results = data.d.postquery.PrimaryQueryResult.RelevantResults;
allResults = allResults.concat(results.Table.Rows.results);
if (results.TotalRows > postData.request.StartRow + results.RowCount) {
reportSearch(searchUrl, postData.request.StartRow + results.RowCount, allResults);
}
else if (allResults != null && allResults.length > 0) {
//process allResults
}
else {
if (reportDataTable != null) {
reportDataTable = [];
}
// Show Message No results found
}
}

function onQueryFail(data, errorCode, errorMessage) {
//log error message
}

Hope this helps.

Check out the original article at my blog -  SharePoint Search – how to return all results


by Prashanth Padebettu via Everyone's Blog Posts - SharePoint Community

Tuesday, August 25, 2015

Office 365 Authentication using MVC application and retrieving contacts using Office 365 api

Office 365 Authentication

Office 365 Authentication using Visual Studio MVC application

Lets create an MVC application which has it's back end as office 365. In order to try this out, you just need to have Visual Studio installed on your machine and Office 365 account.

Lets start by creating a new project.

  1. Select Web -> ASP.Net Web Application and click OK Office365Authentication-NewProject
  2. Click on Change Authentication                                 ChangeAuthentication
  3. Select No Authentication. Click OK.                            NoAuth

Setting up the tools to connect to Office 365

Lets first install the Office 365 API Tools which is required for connecting to the Office 365 API.

  1. In Visual Studio, go to Tools/Extensions
  2. Search for Office 365
  3. Install the Office 365 API Tools

Next, lets add a connected service

  1. Right click on the project -> Add -> Connected Service AddConnectedService
  2. Click on Register your app                                         RegisterApp
  3. When prompted, sign into your Office 365 account
  4. We need to set permissions here. Since we need to read from Contacts, click on Contacts -> permissions , check 'Read your contacts', click Apply Permissions
  5. Click on Users and Groups and check 'Sign you in and read your profile UserProfilePermission
  6. Click on app properties and remove the http address, click Apply and OK AppProperties

This will install the required components including the Outlook services and Discovery services which we will be using to retrieve information from Office 365.

Configuring the authentication

Setting the https endpoint

  1. In the project properties, set SSL Enabled to True
  2. Copy the SSL URL property
  3. Right-click the project, and select Properties -> Web tab -> in Servers section -> set Project URL to the SSL URL created above

We need to install some NuGet packages to the project. Right click on the project and click on Manage NuGet packages.                                                                               Manage-NuGet

Ensure you have selected online on the left, search and install the following NuGet packages:

  1. Active Directory Authentication Library
  2. EntityFramework
  3. Microsoft.Owin.Host.SystemWeb
  4. Microsoft.Owin.Security.Cookies
  5. Microsoft.Owin.Security.OpenIdConnect

Configure the Token Cache database

  1. Right click on App_Data and select Add -> New Item.
  2. Name the db ADALTokenCacheDb

Update the web.config to reflect the db name

<connectionStrings>
<add name="DefaultConnection"
connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\ADALTokenCacheDb.mdf;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>

  1. Right click on the project and select Add New-> OWIN startup class. Enter name of the file as Startup.cs (This is found under Web -> General)
  2. Add the following namespace references (Update your namespace for Models and Utils):                         

    using Microsoft.IdentityModel.Clients.ActiveDirectory;
    using Microsoft.Owin.Security;
    using Microsoft.Owin.Security.Cookies;
    using Microsoft.Owin.Security.OpenIdConnect;
    using Office365Authentication.Models;
    using Office365Authentication.Utils;
    using Owin;
    using System;
    using System.IdentityModel.Claims;
    using System.Threading.Tasks;
    using System.Web;
    using Microsoft.Owin;

  3. Add the following method                                                                                                                             

    public void ConfigureAuth(IAppBuilder app)
    {
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

    app.UseCookieAuthentication(new CookieAuthenticationOptions());

    app.UseOpenIdConnectAuthentication(
    new OpenIdConnectAuthenticationOptions
    {
    ClientId = SettingsHelper.ClientId,
    Authority = SettingsHelper.Authority,

    Notifications = new OpenIdConnectAuthenticationNotifications()
    {
    // If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away.
    AuthorizationCodeReceived = (context) =>
    {
    var code = context.Code;
    ClientCredential credential = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.AppKey);
    String signInUserId = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;

    AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.Authority, new ADALTokenCache(signInUserId));
    AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, SettingsHelper.AADGraphResourceId);

    return Task.FromResult(0);
    },
    RedirectToIdentityProvider = (context) =>
    {
    // This ensures that the address used for sign in and sign out is picked up dynamically from the request
    // this allows you to deploy your app (to Azure Web Sites, for example)without having to change settings
    // Remember that the base URL of the address used here must be provisioned in Azure AD beforehand.
    string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
    context.ProtocolMessage.RedirectUri = appBaseUrl + "/";
    context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;

    return Task.FromResult(0);
    },
    AuthenticationFailed = (context) =>
    {
    // Suppress the exception if you don't want to see the error
    context.HandleResponse();
    return Task.FromResult(0);
    }
    }

    });
    }

  4. Call this method from Startup.Configuration as follows:                                                                               

    public void Configuration(IAppBuilder app)
    {
    ConfigureAuth(app);
    }

Let's use part of the code in the github project Office 365 single-tenant MVC project.

  1. Copy the SettingsHelper.cs into the Utils folder
  2. Copy the ApplicationDbContext.cs and the ADALTokenCache.cs to the Models folder
  3. Copy the _LoginPartial.cshtml file into the Views > Shared folder
  4. Ensure that you update the namespace in the copied files

Now lets add the sign in and sign out functionality

  1. Right click on Controllers folder and add a blank controller called AccountController. Replace the existing AccountController
  2. Replace the namespace with                                                                                                                          

    using Microsoft.Owin.Security;
    using Microsoft.Owin.Security.Cookies;
    using Microsoft.Owin.Security.OpenIdConnect;
    using System.Web;
    using System.Web.Mvc;

  3. Delete the index method and add the following:                                                                                          

    public void SignIn()
    {
    if (!Request.IsAuthenticated)
    {
    HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" }, OpenIdConnectAuthenticationDefaults.AuthenticationType);
    }
    }
    public void SignOut()
    {
    string callbackUrl = Url.Action("SignOutCallback", "Account", routeValues: null, protocol: Request.Url.Scheme);

    HttpContext.GetOwinContext().Authentication.SignOut(
    new AuthenticationProperties { RedirectUri = callbackUrl },
    OpenIdConnectAuthenticationDefaults.AuthenticationType, CookieAuthenticationDefaults.AuthenticationType);
    }

    public ActionResult SignOutCallback()
    {
    if (Request.IsAuthenticated)
    {
    // Redirect to home page if the user is authenticated.
    return RedirectToAction("Index", "Home");
    }

    return View();
    }

Update the MVC application to retrieve and show the contact information from Office 365

Now, lets update the MVC application to retrive the contact information.

  1. Add a class to the Models folder called MyContact

    Update the code as

    public class MyContact
    {
    public string Name { get; set; }
    }

  2. Add an empty controller MVC 5 Controller - Empty to the Controllers folder called ContactsController
  3. Add the usings (Update your project namespace for Models and Utils)                                                       

    using Microsoft.IdentityModel.Clients.ActiveDirectory;
    using Microsoft.Office365.Discovery;
    using Microsoft.Office365.OutlookServices;
    using Office365Authentication.Models;
    using Office365Authentication.Utils;
    using System.Collections.Generic;
    using System.Security.Claims;
    using System.Threading.Tasks;
    using System.Web.Mvc;

  4. Add an authorize attribute                                                                                                                             

    [Authorize]
    public class ContactsController : Controller

  5. Change the index method to aysnchronous                                                                                                  public async Task<ActionResult> Index()
  6. Add the following code to index method                                                                                                      

    List<MyContact> myContacts = new List<MyContact>();

    var signInUserId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
    var userObjectId = ClaimsPrincipal.Current.FindFirst("http://ift.tt/1xhjXp4").Value;

    AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.Authority, new ADALTokenCache(signInUserId));
    try
    {
    DiscoveryClient discClient = new DiscoveryClient(SettingsHelper.DiscoveryServiceEndpointUri,
    async () =>
    {
    var authResult = await authContext.AcquireTokenSilentAsync(SettingsHelper.DiscoveryServiceResourceId, new ClientCredential(SettingsHelper.ClientId, SettingsHelper.AppKey), new UserIdentifier(userObjectId, UserIdentifierType.UniqueId));

    return authResult.AccessToken;
    });

    var dcr = await discClient.DiscoverCapabilityAsync("Contacts");

    OutlookServicesClient exClient = new OutlookServicesClient(dcr.ServiceEndpointUri,
    async () =>
    {
    var authResult = await authContext.AcquireTokenSilentAsync(dcr.ServiceResourceId, new ClientCredential(SettingsHelper.ClientId, SettingsHelper.AppKey), new UserIdentifier(userObjectId, UserIdentifierType.UniqueId));

    return authResult.AccessToken;
    });

    var contactsResult = await exClient.Me.Contacts.ExecuteAsync();

    do
    {
    var contacts = contactsResult.CurrentPage;
    foreach (var contact in contacts)
    {
    myContacts.Add(new MyContact { Name = contact.DisplayName });
    }

    contactsResult = await contactsResult.GetNextPageAsync();

    } while (contactsResult != null);
    }
    catch (AdalException exception)
    {
    //handle token acquisition failure
    if (exception.ErrorCode == AdalError.FailedToAcquireTokenSilently)
    {
    authContext.TokenCache.Clear();
    //handle token acquisition failure
    }
    }

    return View(myContacts);

Now, lets add the view to the Contacts controller:

  1. In the Views folder, right click on Contacts folder -> Add View
  2. Enter view name as Index
  3. Select List as the template
  4. Select MyContact as model
  5. Click on Add

In the Shared folder, open the _Layout.cshtml file

  1. Add an actionlink to the MyContacts page to get a navigation link to the MyContacts view so that it is updated as:                                                                                                                                                     

    <div class="navbar-collapse collapse">
    <ul class="nav navbar-nav">
    <li>@Html.ActionLink("Home", "Index", "Home")</li>
    <li>@Html.ActionLink("About", "About", "Home")</li>
    <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
    <li>@Html.ActionLink("My Contacts", "Index", "Contacts")</li>
    </ul>
    @Html.Partial("_LoginPartial")
    </div>

Now if you run the application, and click on the MyContacts link, it should show the contacts in your Office 365 site!

When prompted, login to your Office 365 account and accept the permission requirements. Output

Check out the original article at my blog -  Office 365 Authentication using Visual Studio MVC application


by Prashanth Padebettu via Everyone's Blog Posts - SharePoint Community

Wednesday, August 19, 2015

Deploy Solution wsp to SharePoint

The Microsoft technet article Automated Farm level Solution Deployment and Retraction, gives a very good example of deploying SharePoint wsp solutions using PowerShell. However, I felt that it would be better to wait for the timer job to complete instead of using sleep command as mentioned in SharePoint 2010: PowerShell to Wait for WSP Solution Deployment Timer Job to Complete

Also, I thought it would be better if we added a configuration xml instead of providing input parameters.

Please feel free to let me know if this script can be enhanced by leaving a comment, preferably on my site page here

We can have a configuration file which contains information such as web application url, site collection and web specific information such as features to be activated. It can have any number of Site and Web sections to handle multiple site collections and webs.

Configuration Config.xml:

<WebApp>
<WebAppUrl>http://server/webapp</WebAppUrl>
<Site>
<SiteUrl>http://server/sites/site1</SiteUrl>
<Features>
<Feature>PublishingSite</Feature>
</Features>
</Site>
<Web>
<WebUrl>http://server/sites/site1</WebUrl>
<Features>
<Feature>PublishingWeb</Feature>
</Features>
</Web>
</WebApp>

Ensure that the wsps are kept in a sub folder called WSP inside the folder where the script is saved.

So, here is the enhanced script

PowerShell 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"
}
#get the configuration info
$config = [xml](Get-Content "Config.xml");

$wspFolderPath = "WSP";
[int]$sleepTime = 4;
$AdminServiceName = "SPAdminV4";
$TimerServiceName = "SPTimerV4";
$url = $config.WebApp.WebAppUrl;

#Start the Admin service if it is not started
if ($(Get-Service $AdminServiceName).Status -eq "Stopped")
{
Start-Service $AdminServiceName
Write-Host "Started the SharePoint 2013 Admin Service"
}

#Start the Timer service if it is not started
if ($(Get-Service $TimerServiceName).Status -eq "Stopped")
{
Start-Service $TimerServiceName
Write-Host "Started the SharePoint Timer Job"
}

function DeactivateSiteFeatures($siteCol)
{
$siteUrl = $siteCol.SiteUrl
$Site = Get-SPSite -Identity $siteUrl
foreach ($featureName in $siteCol.Features.Feature)
{
$EnabledSiteFeatures = Get-SPFeature -site $siteUrl
foreach($enabledFeature in $EnabledSiteFeatures)
{
#Check if feature is already activated. Deactivate if already activated.
if($featureName -eq $enabledFeature.DisplayName)
{
Write-Host "Feature $featureName Activated" -foregroundcolor Green
Write-Host "- Deactivating Feature" -foregroundcolor Yellow
Start-Sleep 3
Disable-SPFeature -Identity $featureName -url $SiteUrl -confirm:$false
Write-Host " -- Feature deactivated successfully" -foregroundcolor Green
}
}
}
$Site.Dispose()
}

function ActivateSiteFeatures($siteCol)
{
$siteUrl = $siteCol.SiteUrl
$Site = Get-SPSite -Identity $siteUrl
foreach ($featureName in $siteCol.Features.Feature)
{
Write-Host "Activating $featureName feature" -foregroundcolor Yellow
Enable-SPFeature -identity $featureName -Url $SiteUrl -Confirm:$false
Start-Sleep 3
Write-Host " -- Feature activated successfully" -foregroundcolor Green
}
$Site.Dispose()
}

function DeactivateWebFeatures($PubWeb)
{
Write-Host "Deactivating Web features"
#Web
$WebUrl = $PubWeb.WebUrl

foreach ($featureName in $PubWeb.Features.Feature)
{
Write-Host " "

$EnabledWebFeatures = Get-SPFeature -Web $WebUrl

foreach($enabledFeature in $EnabledWebFeatures)
{
#Check if feature is activated. Deactivate if activated.
if($featureName -eq $enabledFeature.DisplayName)
{
Write-Host "Feature $featureName already Activated" -foregroundcolor Green
Write-Host "- Deactivating Feature" -foregroundcolor Yellow
Start-Sleep 3
Disable-SPFeature -Identity $featureName -url $WebUrl -confirm:$false
Write-Host " -- Feature deactivated successfully" -foregroundcolor Green
}
}
}
}

function ActivateWebFeatures($PubWeb)
{
Write-Host "Activating Web features"
#Web
$WebUrl = $PubWeb.WebUrl

foreach ($featureName in $PubWeb.Features.Feature)
{
Write-Host "Activating $featureName feature" -foregroundcolor Yellow
Enable-SPFeature -identity $featureName -Url $WebUrl -Confirm:$false
Start-Sleep 3
Write-Host " -- Feature activated successfully" -foregroundcolor Green
}

}
function WaitForSPSolutionJobToComplete($solution)
{
if ($solution)
{
$solutionName = $solution.Name;
if ($solution.JobExists)
{
Write-Host -NoNewLine "Waiting for timer job to complete for solution '$solutionName'."
}

# Check if there is a timer job still associated with this solution and wait until it has finished
while ($solution.JobExists)
{
$jobStatus = $solution.JobStatus

# If the timer job succeeded then proceed
if ($jobStatus -eq [Microsoft.SharePoint.Administration.SPRunningJobStatus]::Succeeded)
{
Write-Host "Solution '$solutionName' timer job suceeded"
return $true
}

# If the timer job failed or was aborted then fail
if ($jobStatus -eq [Microsoft.SharePoint.Administration.SPRunningJobStatus]::Aborted -or
$jobStatus -eq [Microsoft.SharePoint.Administration.SPRunningJobStatus]::Failed)
{
Write-Host "Solution '$solutionName' has timer job status '$jobStatus'."
return $false
}

# Otherwise wait for the timer job to finish
Write-Host -NoNewLine "."
Sleep 1
}

# Write a new line to the end of the '.....'
Write-Host
}

return $true
}

#deactivate site collection features
foreach ($siteCollection in $config.WebApp.Site)
{
DeactivateSiteFeatures($siteCollection)
}

#deactivate web features
foreach ($web in $config.WebApp.Web)
{
DeactivateWebFeatures($web)
}

#WSP Solution
foreach($filename in Get-ChildItem $wspFolderPath)
{
Write-Host " "
$SolutionPackageName = $filename.name
$Solution = Get-SPSolution | ? {($_.Name -eq $SolutionPackageName) -and ($_.Deployed -eq $true)}
if ($Solution -ne $null)
{
Write-Host "Solution already Deployed. Rectracting solution: $SolutionPackageName" -foregroundcolor Red
if($Solution.ContainsWebApplicationResource)
{
Uninstall-SPSolution $SolutionPackageName -WebApplication $url -Confirm:$false
}
else
{
Uninstall-SPSolution $SolutionPackageName -Confirm:$false
}

# Calling Function to wait for timer job to compelete
WaitForSPSolutionJobToComplete($Solution)

Write-Host "-Rectracting $SolutionPackageName solution Done." -foregroundcolor Green

if ($(Get-SPSolution | ? {$_.Name -eq $SolutionPackageName}).Deployed -eq $false)
{
Write-Host "Removing solution: $SolutionPackageName" -foregroundcolor Red
Remove-SPSolution $SolutionPackageName -Confirm:$false
Start-Sleep -Seconds $sleepTime
Write-Host " - Removing $SolutionPackageName solution Done." -foregroundcolor Green
}
}

Write-Host "-Adding solution: $SolutionPackageName" -foregroundcolor Green
$SolutionPath = $PSScriptRoot + "\" +$wspFolderPath +"\"+ $SolutionPackageName
Add-SPSolution $SolutionPath | Out-Null
Start-Sleep -Seconds $sleepTime
Write-Host " - Adding $SolutionPackageName Solution Done." -foregroundcolor Green


Write-Host "-Deploying solution: $SolutionPackageName" -foregroundcolor Green
$Solution = Get-SPSolution | ? {($_.Name -eq $SolutionPackageName) -and ($_.Deployed -eq $false)}
if(($Solution -ne $null) -and ($Solution.ContainsWebApplicationResource))
{
Install-SPSolution $SolutionPackageName -WebApplication $url -GACDeployment -Confirm:$false
}
else
{
Install-SPSolution $SolutionPackageName -GACDeployment -Confirm:$false
}

# Calling Function to wait for timer job to compelete
WaitForSPSolutionJobToComplete($Solution)

Write-Host
Write-Host " - Deploying $SolutionPackageName solution Done." -foregroundcolor Green
}

#loop all the site collections
foreach ($siteCollection in $config.WebApp.Site)
{
ActivateSiteFeatures($siteCollection)
}

#loop all the webs
foreach ($web in $config.WebApp.Web)
{
ActivateWebFeatures($web)
}

Please let me know your thoughts.


** See the original post at http://ift.tt/1LD33pT - The SharePoint Guide


by Prashanth Padebettu via Everyone's Blog Posts - SharePoint Community

Thursday, August 6, 2015

WEBMETHODS IN SHAREPOINT USING JQUERY

WebMethods in SharePoint using JQuery

Lets say we have a SharePoint Site Page or Application Page which has a server side method and we would like to call this method from JavaScript code. Wouldn't it be great if we can do the server side processing and return the result such as a string or a json object back to the client side? Well, this is precisely what we can do using WebMethod framework.

Lets start off by adding a simple WebMethod to a SharePoint page. Lets say we have added the below code to a page in "http://servername/site/WebMethod.aspx". We decorate the method with [WebMethod] attribute. [ScriptMethod] is the attribute which allows us the client side access. Also note that we make the WebMethod static.


[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static string GetServerDetails(string name)
{
return "Hi " + name + ":from WebMethod";
}

Then from the JavaScript, we can call the WebMethod by appending the page url and the WebMethod name. We use this string to make an ajax post request. If we need to pass a parameter to the method we have to stringify the object. Below is the client side code:


var methodUrl = "http://servername/site/WebMethod.aspx/GetServerDetails";
var param = {};
param.name = "Prashanth";

$.ajax({
type: "POST",
url: methodUrl,
data: JSON.stringify(param),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (result) {
var output = result.d;
}
error: function (jqXHR, textStatus, errorThrown) {
alert('Error occured');
if (jqXHR.status == 500) {
console.log('Internal error: ' + jqXHR.responseText);
} else {
console.log('Unexpected error.');
}
}


Instead of returning a simple string from the WebMethod, if we wanted to return a json object, we need to create a class and return an object of that class. For example, if we wanted to return address details, we can have an Address class which has the properties which encapsulates all the related data.


public class Address
{
public string HouseNumber {get; set;};
public string Street {get; set;};
public string City {get; set;};
public string Pin {get; set;};
public string Country {get; set;};
}

Then in the WebMethod, we create object of this class and return the same. We will then receive the json object containing the Address data on the client side. We can even return arrays of strings and objects. We would then receive the collection inside the json object.


** original post at http://ift.tt/1LD33pT - The SharePoint Guide
by Prashanth Padebettu via Everyone's Blog Posts - SharePoint Community

Wednesday, July 22, 2015

Download file from SharePoint document library C#

Download File from SharePoint Document Library C#

Lets see how to download a file from SharePoint document library using C#. Sometimes, we would want to download multiple files based on a pre-defined query such as a monthly report or a bulk download. We can use the explorer view, if it is a few files or if it is a complete folder or all the files in the document library. However, if we want to customize the query or automate the process, then we can use the below C# code to download the files programmatically.

  1. Use the standard object model to access the SharePoint site and web.
string siteUrl = "site url";
using(SPSite site = new SPSite(siteUrl) {
using(SPWeb web = site.OpenWeb()) {
       // code to download documents
}
}
  1. Access the document library using the web object from the above step.
// get the required document library SPList
docLib = web.Lists["Shared Documents"];
  1. Access the items to be downloaded and download the files.
// loop through each item or document in the document library
foreach(SPListItem item in docLib.Items) {
  // Access the file
  SPFile file = item.File; if(file != null) {
  // retrieve the file as a byte array byte[] bArray = file.OpenBinary();
  string filePath = Path.Combine("c:\\temp", file.Name);
  //open the file stream and write the file
  using(FileStream fs = new FileStream(filePath, FileMode.Create,     FileAccess.ReadWrite)) {
    fs.Write(bArray, 0, bArray.Length);
} } }

The above server side code can be used if you are using page code behind, event handler, timer job etc.

In case you do not want to download all the files, you can use CAML query to filter the items in a document library or even a site collection and loop through those items. If it is spanning multiple site collections, you can use search query to retrieve the items.

Instead of using the file object from the SharePoint item, we can also use the file url to download the file from the document library. Following code will download the file located at url fileUrl to C:\Docs folder locally on the server:

FileStream fstream = null;
string fileName = Path.GetFileName(fileUrl);
if (!string.IsNullOrEmpty(fileName)) { byte[] data; byte[] buffer = new byte[2048];
WebRequest request = WebRequest.Create(url);
using (WebResponse response = request.GetResponse()) {
using (Stream responseStream = response.GetResponseStream()) {
using (MemoryStream ms = new MemoryStream()) {
int count = 0;
do {
count = responseStream.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, count);
} while (count != 0);
data = ms.ToArray();
} } }
string filePath = "C:\Docs";
using (fstream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite)) {
fstream.Write(data, 0, data.Length);
fstream.Close();
} }

** original post at http://ift.tt/1LD33pT - The SharePoint Guide


by Prashanth Padebettu via Everyone's Blog Posts - SharePoint Community