9/10/17

Powershell Upload Multiple Files to SharePoint

SharePoint document library enables us to manage documents. In some cases, we need to upload multiple files to that library.  A common approach to automate this process is to integrate via the SharePoint Restful APIs. In this article, we take a look at using PowerShell to create a script that can quickly enable this integration without having the need to know all the details of the API.


Solution


For our use case, we have a drop location where our files are located. We need to read all the files and upload them to a SharePoint document library.

Note: We can run this snippet using Visual Studio Code. Just save the file with an extension of ps1, and VS Code will guide you on installing the PowerShell extensions.



# include the web cmdlets
Add-PSSnapin microsoft.sharepoint.powershell

# name:  uploadFiles
# purpose: upload multiple files from a shared location
#
function uploadFiles($path, $siteUrl)
{

try {

  # gets all the files (-File) in the directory
  $files = Get-ChildItem -Path $path –File

  #iterate thru each file
  foreach($file in $files) 
  { 
      $url = $siteUrl + $file
      $filePath = $path + $file

      #upload the file to the server using default credentials from the
      #current session
      $result = Invoke-WebRequest -Uri $url -InFile $filePath -Method PUT
               -UseDefaultCredentials

      #if the request status code is successful, we delete the files
      #else write an error message
      if($result.statuscode -eq 200){       
        Remove-Item $filePath -Force
      }else{
        write-host "Failed to upload" $filePath $result.statuscode
      }
  }
}
catch {
  write-host "Exception was raised: $PSItem" #psitem is the error object
}

}


#usage
#uploadFiles parm0 param1
#param[0] shared-location 
#param[1] sharepoint document library url
#
UploadFiles "\\some-document-path" "https://ozkary.com/shared-docs/"


In this snippet, we first need to include the snap-in for SharePoint. This loads the web cmdlets that provide the implementation abstraction to the SharePoint APIs.

The uploadFiles function enables us to read a folder location and lists only the files. We then iterate thru each file and use the Invoke-WebRequest to load them to a particular SharePoint document library. If the response has Status 200, we know that the upload was a success, and we remove the file. Otherwise, we write to the standard output using write-host.

Security


We should notice that when uploading the files, we use the -DefaultCredentials parameter.  This enables our script to pass the current session credentials to the request.  The credentials are set when the script is executed under the context of a particular service account that has access to the SharePoint document library.

 I hope this provides a quick automated way to upload files to your document libraries.



Originally published by ozkary.com

8/19/17

SharePoint 2013 Service Cannot be Activated on host-named Site Collection

A host-named site collection on SharePoint has a URL format of apps.ozkary.com. In comparison, a path-based site collection has this URL ozkary.com/sites/apps.

When using a host-named site collection for document libraries, we may encounter some behavior that it is not reproducible when using a path-based site.  Let’s take a look at this service activation error.

Unable to activate service Error

Browser Error
This is error shown on the browser console.


https://apps.ozkary.com/_vti_bin/DocControl/DocControlService.svc/MoveFile 500
(System.ServiceModel.ServiceActivationException)


Server Error
This is the error shown on the server logs.


WebHost failed to process a request.
System.ServiceModel.ServiceActivationException: The service '/_vti_bin/DocControl/DocControlService.svc' cannot be activated due to an exception during compilation.  The exception message is: The type 'DocControl.Controls.ISAPI.DocControl.DocControlService, DocControl.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=, provided as the Service attribute value in the ServiceHost directive, or provided in the configuration element system.serviceModel/serviceHostingEnvironment/serviceActivations could not be found


This error indicates that the service cannot be activated because it is not found.  This is a problem on the fact that the relative path the service activation is using is not found because our site is a host-named URL, and there is nothing defined on IIS for this path. A host-named URL is managed internally by SharePoint, so this is the reason why IIS may not have the URL defined on the site bindings.  A solution for this problem is to configure the site on IIS and add this URL to the site bindings.



After adding the binding, the operation that was causing the error should work properly.

I hope this helps.


Originally published by ozkary.com

8/12/17

Move an Azure Subscription to a Different AD Directory

When managing multiple Azure AD and subscriptions, we need to create subscription on a particular Azure AD to grant access to the users in the directory. This allows us to prevent unauthorized access to other subscriptions. In some cases, we may want to transfer a subscription to a different AD directory. 

As of the time of this article, the new Azure portal does not enable this operation. In order to do that, we have to use the Azure AD portal and then load the Classic portal for the final transfers. Let’s see how that is done:

Transfer subscription to different directory

  • Login with the account that has the subscription to aad.portal.azure.com
  • Click on Azure Active Directory menu option
  • Click on Classic Portal (top menu bar)
  • On the Top-Right, select Subscriptions (ref image 1)
  • Filter by the directory where the subscription is located
  • Click on Manage subscription directory
  • Select the subscription that we want to transfer
  • Select on edit directory (bottom button - ref image 2)
  • Select the target directory
  • Click continue (right arrow) and make sure that there are no problems with users that do not exist on the target directory.  This means that the owner must exist on both directories.
  • Click OK (Check mark)

image 1

image 2



The subscription should be moved to the new directory in a few minutes. After this is successful, we can log back in to Azure portal. We need to make sure that we select the correct directory from the top-right user profile component. There we can find a list of all the directories the user is associated with.

We can now load this URL. There is no menu option to load this view, so we can create a shortcut on the dashboard with this link.


https://portal.azure.com/#blade/Microsoft_Azure_Billing/SubscriptionsBlade

If we only click on the subscription menu option that it is available from the billing blade area, we see only the subscriptions with associated billing, and that filters our newly transferred subscription.


This should help us move our subscriptions to another AD directory without too much pain.

Originally published by ozkary.com

7/15/17

Microsoft MVP Award - 2017

On July 2017, I was proud to receive my second Microsoft Most Valuable Professional (MVP) award. This year the award came in earlier than expected, as the Microsoft MVP program decided to grant these awards once a year moving forward.  



This is rewarding recognition that makes all the on-going work that I do for the different software communities around the world worth it


I enjoy knowing that what I learn and share with others has some meaningful value.


What to Expect Next


 My plans for the next year is to continue to learn and share with others by writing blogs  entries, deliver more presentations and help on different technical forums like Stackoverflow, ASP.NET, GitHub, Twitter and CodeProject.

On the technology side,  I plan to continue the  grow on areas like Angular 2, Node.js, Azure Technologies, SQL Server, NoSQL,  ASP.Net , Visual Studio, and Microsoft Core technologies to expand my areas into the Linux world. 

Thanks again to Microsoft and those working the MVP program as well as the community that enjoy and support my contributions.

Oscar Garcia
@ozkary

2016-2017

Originally published by ozkary.com

7/8/17

SQL Server - Pivot Rows to Columns

On systems that are meta-data driven, there may not be a concrete table schema declaration, and the meta-data values can be stored as rows. To provide an example, let’s build a custom_field table that can hold multiple custom values for a particular entity:

Pivoting rows to columns



Setup the table and sample data



create table dbo.custom_fields
(
   ref_id int, 
   field_id int,
   field_name varchar(55),
   field_value int
)
go

INSERT INTO [dbo].[custom_fields]
           ([ref_id]
           ,[field_id]
           ,[field_name]
           ,[field_value])          
    VALUES
 (1020, 1000,'width',10)
,(1020, 1001,'height',20)
,(1020, 1003,'thick',5)
,(2010, 1000,'width',15)
,(2010, 1001,'height',5)
,(2010, 1003,'thick',5)
,(2010, 1003,'units',5)
,(3000, 1000,'width',35)
,(3000, 1001,'height',55)
,(3000, 1003,'thick',20)

--returns all the records
select *
from custom_fields

After we create the table and insert the test data, we can run a query to select all the records. The results should as follows:




The problem with the way the data is stored is that those values are properties values for an entity associated by the ref_id, and we would want to read those values as columns instead of rows as shown below:


Pivot Query


To convert those rows to columns, we need to use the PIVOT relational operator which enables us to convert the table results into a different shape. Let’s write a SQL query that can do that for us.


SELECT ref_id,width,height,thick,units
FROM
(
  SELECT [ref_id], [field_name], [field_value]
  FROM custom_fields   
) fields
pivot
(
  MAX(field_value)
  FOR [field_name] in (width,height,thick,units)
) piv;



The syntax may not be clear at first, but the query pivots the data on the field_name (FOR Expression) values, so that they become the column heading. This matches the meta-data in the field_name column, so we can read the field value using the MAX function. 

When a field_name does not exist for a particular row, the return value is null.  For example, both ref_ids (1020, 3000) do not have a units custom field.

This should enable us to make more complex pivot queries using SQL Server.

Thanks for reading.

Originally published by ozkary.com

6/24/17

Building Angular2 CLI Bootstrap3 Menu Component

With Angular2 CLI, the approach to include Bootstrap components is somewhat different that the traditional way of installing our packages and including our framework references manually.  In this article, we take a look at build an Angular2 app using the Angular CLI. We also show how to include the Bootstrap framework in our application.

Build the app

We start by building the application using the CLI command. For this, we assume you have already installed all the Angular2 dependencies.

Open a command line and type the following commands:

ng new ang2-bootstrap
This creates the basic application. The source code for our app is created on the src\app folder


cd ang2-bootstrap 
In order to use additional cli commands, we need to change to the directory where the app was created.

ng generate component menu

This commands scaffold a component named menu using the basic template. The component is created in a folder under the app directory (src\app\menu) with a component, test, html and css files.

ng serve

At this point, we have a simple application that can be built and loaded by running the ng serve command. Open the browser and load the application using the address that is shown on the console. 

Customization

There is nothing special about the app. We should now add some customization to our application by removing some of the default stuff that was created by the CLI. Do not stop the tasks, so we can see how our page changes as we add our customization. Let’s start by editing the src\app\app.component.html file. Let's replace the current mark-up with this:

<!--The whole content below can be removed with the new code.-->
<div id="wrapper">
<div id="page-content-wrapper">
<nav class="navbar navbar-default navbar-fixed-top bg-primary">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#"> Welcome to {{title}}!!</a>
        </div>       
      </div>
</nav>
<div id="page-content">
  <div id="page-sidebar">
    <app-menu></app-menu>
  </div>
  <div class="container-fluid" id="page-content-main">
    <div class="page-header">
      <h1>Content </h1>
      </div>
    <section class="row text-center placeholders">           
    </section>
  </div>
</div>
</div>
 </div>



We are adding some headers and content layout to make the application better looking. Notice how we are also adding the app-menu mark-up. This is the directive to load our menu component that was created with the CLI command. We can now add this mark-up to the src\app\menu\menu.component.html file.


<nav class="navbar navbar-default sidebar" role="navigation">
<div class="container-fluid">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#sidemenu">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>          
    </div>
    <div class="collapse navbar-collapse" id="sidemenu">
       <ul class="nav navbar">
    <li *ngFor="let menu of menus">
        <a href="{{menu.url}}" class="primary" target="_new"  title="{{menu.title}}" (click)="menu.selected = !menu.selected">
        <i class="fa fa-fw fa-2x {{menu.class}}"></i> <span class="nav-header-primary">{{menu.title}}</span> &nbsp;                       
      </a>             
    </li>
  </ul>
    </div>
  </div>
</nav>

We just added the Bootstrap navbar menu that we can dock on the left side of our application. The menu component view needs a menus property from the components class. This is how it gets the data that it needs for the menus entries. Replace all the code from the src\app\menu\menu.component.ts file with the following code:


import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-menu',
  templateUrl: './menu.component.html',
  styleUrls: ['./menu.component.css']
})
export class MenuComponent implements OnInit {

  constructor() { }

  public menus: Array<IMenu>;

  ngOnInit() {
    this.menus = [{
        "id": 1,"title": "Azure","class": "fa-cloud",
        "url": "http://azure.com"},{ "id": 2,
        "title": "AWS","class": "fa-cloud",
        "url": "http://aws.amazon.com"},{ "id": 3,
        "title": "Google Cloud",
        "class": "fa-cloud",
        "url": "http://cloud.google.com"}];
  }

}

export interface IMenu {
    id : number;
    title : string;  
    class : string;
    url : string;   
}


Our JSON model is loaded on the menus property which implements an array of the IMenu interface. This allows us to strongly type our JSON data. Ideally this data should come from a common service.

If we take a look at the page, we should now see our menu options, but there is still no style there. We have added some of the Bootstrap styles to the mark-up, but we are not loading the Bootstrap dependencies yet. Let’s take care of that by adding Bootstrap and font-awesome to our app. This is good time to stop the ng serve command and enter the following commands:


npm install bootstrap@latest –save

npm install font-awesome –save

npm install jquery –save


On the first command, we are installing the latest 3.n version of Bootstrap. This is done by using the scope (@) and label latest.   For Bootstrap 4, the label is next, but we are not using that version on this example. We are also using font-awesome for those fa fa-name icon that we want on our menus. Lastly, we need to install Jquery which is a dependency of the Bootstrap JavaScript file.

Configure the References

We now have all our dependencies installed (check for errors on the console). Now, we need to configure the references in our app. This is no longer done using the HTML tags on the page. We now need to add them to the collection of styles and script files on the .angular-cli.json file which should be at the root of our project folder.  Find the following tags and replace with these snippets:


"styles": [
        "../node_modules/bootstrap/dist/css/bootstrap.min.css",
        "../node_modules/font-awesome/css/font-awesome.min.css",
        "styles.css"
      ],
      "scripts": [
        "../node_modules/jquery/dist/jquery.min.js",
        "../node_modules/bootstrap/dist/js/bootstrap.min.js"
      ],

Update style.css

We should add the following to our src\style.css files. This is where we can add global app style classes.

/* You can add global styles to this file, and also import other style files */
body{
    margin: 0;
    overflow: hidden;
}
#wrapper {
    padding-left: 0;
    -webkit-transition: all 0.5s ease;
    -moz-transition: all 0.5s ease;
    -o-transition: all 0.5s ease;
    transition: all 0.5s ease;
}
#page-content-wrapper {
    width: 100%;
    position: absolute;
    margin-top:-20px;
    padding: 0x;
}
#page-content{
margin-top:70px;
}
@media (min-width: 765px) {
  #page-sidebar {
    z-index: 1000;
    position: fixed;         
    height: 100%;
    overflow-y: auto;  
}
#page-content-main{
   margin-left: 220px;
   padding:0;
}
}
 @media (max-width: 765px) {
 #page-sidebar {
    z-index: 1000;         
    height: 100%;
    overflow-y: auto;  
    background: #e7e7e7;
}
#page-content-main{
   margin-left: 0;
   padding:0;
}
 }

Update our component styles

We also have styles that are specific to our component. Since these styles are only required by our menu component, we can use the src\app\menu\menu.component.css file for this purpose. Add the following to that file:


nav.sidebar{
    -webkit-transition: margin 200ms ease-out;
      -moz-transition: margin 200ms ease-out;
      -o-transition: margin 200ms ease-out;
      transition: margin 200ms ease-out;
    
  }
 @media (min-width: 765px) {   
    nav.sidebar.navbar.sidebar>.container .navbar-brand, .navbar>.container-fluid .navbar-brand {
      margin-left: 0px;
    }
    nav.sidebar .navbar-brand, nav.sidebar .navbar-header{
      text-align: center;
      width: 100%;
      margin-left: 0px;
    }      
    nav.sidebar .navbar-collapse, nav.sidebar .container-fluid{
      padding: 0 0px 0 0px;
    }
    nav.sidebar{
      width: 200px;
      height: 100%;
      margin-left: -160px;
      float: left;
      margin-bottom: 0px;
    }
    nav.sidebar li {
      width: 100%;
    }
    nav.sidebar:hover{
      margin-left: 0px;
    }
    .forAnimate{
      opacity: 0;
    }
  }
  @media (min-width: 1330px) {
    nav.sidebar{
      margin-left: 0px;
      float: left;
    }
    nav.sidebar .forAnimate{
      opacity: 1;
    }
  }

  nav.sidebar .navbar-nav .open .dropdown-menu>li>a:hover, nav.sidebar .navbar-nav .open .dropdown-menu>li>a:focus {
    color: #CCC;
    background-color: transparent;
  }
  nav:hover .forAnimate{
    opacity: 1;
  }
  section{
    padding-left: 15px;
  }


We can now load the app again by running ng serve, and we should see that we have a decently looking Angular2 with Bootstrap 3 app which has header, navigation menu and main content area.

App Preview




We will continue to work on this application to make it look great and add many features. Come back for more articles.

Thanks for reading.

Originally published by ozkary.com