Category Archives: PowerShell

Some misc powershell commands for working with azure PS modules

This is one of those posts I’m doing mostly for myself to keep things in one place.

Remove an old version of a module:

$Latest = Get-InstalledModule (modulename); Get-InstalledModule (modulename) -AllVersions | ? {$_.Version -ne $Latest.Version} | Uninstall-Module -WhatIf

another way to do the same:

get-installedmodule modname -requiredversion  x.x.x | uninstall-module

(taken from https://windowsserver.uservoice.com/forums/301869-powershell/suggestions/14934876-update-module-needs-flag-to-remove-previous-versio)

Show what modules are installed:

get-installedmodule

Show what versions of a specific module are installed

get-installedmodule -name modname -allversions

 

Update the azureRM module:

update-module azurerm -force

Install over a stubborn module:

install-module azurerm.cognitiveservices -force

 

 

 

Timewatch, a PowerShell Function for reporting how much time is left in a loop

I had to loop through a bunch of things the other day and wanted to have a nice way to report how far I was through the loop.

This way if I had 1000 things to loop through, and each one took 10 seconds, I knew I had 10,000 seconds to wait, or roughly 2.7 hours.

Armed with this information, I could be comfortable stepping away for a bit with a good guess as to when my script would finish.

To use the function above, you need to paste it into your script, somewhere above where you intend to call it.

Then in your script you likely have a loop like this:

To make use of the timewatch function, we’ll modify our loop as follows:

That’s it, now the timewatch function will track the average time per iteration, and based on how many remaining interations are left, will report both the amount of time left, and an ETA time that the looping would complete.

Having PowerShell talk to you is actually useful!

PowerShell can talk to you.

My favorite use for it, is when I have a script that’s going to run a long time, say 10-20 minutes.
We all KNOW that we’re not going to sit there and watch the output!

Having PowerShell talk when some condition comes up can be really useful if you’ve relegated the window to the background and are doing something else like reading email.

Doing it was super easy.

Shoutout to Michael Blumenthal for suggesting this!

Modify-Sublicense PowerShell function for modifying Office 365 Sublicenses

Modify-Sublicense

An example call would be:

Modify-Sublicense -upn "joe@yourcompany.com" -PrimaryLicense "TENANT:ENTERPRISEPACK -SublicensesToRemove @("SWAY","YAMMER_ENTERPRISE") -SublicensesToAdd @("SHAREPOINTENTERPRISE", "SHAREPOINTWAC")

If you’re new to powershell, scroll down past the code below for some additional tips.

Naturally, sublicenses you had before will REMAIN unless you’ve removed them.
AND
Sublicenses you DID NOT HAVE before will NOT BE ADDED unless you specifically add them.

This is important because of how the licensing works, which has been covered in other blog posts my myself and others.

I’ve used the function below as part of a larger script with good results.

As always, TEST BEFORE YOU USE IT!

New to powershell?

Here are a few tips:

  • Since the code is a function, you’ll need to copy-paste it to a script of your own before you can use it
  • In powershell, functions need to appear in your script above/before you use them.
  • There are ways to load the function in memory, so you can call it as if it was a native command. See How to add functions to your powershell session
  • An array in powershell can have zero or 1 or many items, if you need to pass a single value, just pass it as an array with one value. That would look like this: @("Value1", "Value2")

– Jack

Replace an expiring Client Secret in an app for SPO

What are we even calling these things these days? Apps for SharePoint Online? Apps for Office 365?

This article is about the apps we build using the new app model that was introduced along with SharePoint 2013. It’s the main way of developing functionality for SharePoint Online.

The apps are hosted in Azure (or on the hosting provider of your choosing)

When these Apps are created/installed a Client secret is used to ensure that communication between your externally hosted app and SharePoint Online is secure and not coming from an attacker.

Unfortunately these certificates expire.

Ours have.

The article below talks about replacing them.

https://msdn.microsoft.com/en-us/library/office/dn726681(v=office.15).aspx

We also opened a ticket with Microsoft Premier Support which revealed a few more tidbits.

  • It takes like 24 hours for the new certificate to propogate through your system, leaving your app out of commission for at least that long if you don’t renew before it expires.
  • The article above mentions, but does not give an example of, extending the date from the default 1 year to 3 years. I’ve copied some of the correspondence with Mustaq Patel from Microsoft, who helped us through the process (Thanks Mustaq!)

Note for the scripts below, you’ll need your clientID this is in the web.config of your website that’s hosted in Azure.  As luck would have it, the person at our company who would have had this info was on vacation. Since it’s in the web.config of the running app, it made sense to just pull the actual web.config in use. I did this via FTP, using the steps in this article to configure an FTP account to gain access to the server:

https://azure.microsoft.com/en-us/documentation/articles/web-sites-configure/

Update: You can also find the clientID by going to any sharepoint site that uses the app, Site Settings->Site App Permissions.

It’ll be the guid between the last pipe symbol and the @ symbol

Example i:oi.t|blahblahblah|abcdef-1234-this-is-aguid-and-is-what-you-want@7a534-no-the-guid-you-want-123

(thanks to Mustaq for pointing this out!)

  1. Connect to MSOnline using tenant admin user with below powershell in SharePoint 2013 powershell
  2. Get ServicePrincipals and keys. Printing $keys will give 3 records, replace each KeyId in key1, key2 and key3. You can also see EndDate of each key. Confirm if your expired key shows there. Also note that clientId needs to match as per your clientId.

  3. Generate new ClientSecret for this clientID. Please note it uses clientId set in #2. Also ClientSecret is valid for 3 years.

  4. Copy the output of $newClientSecret.

  5. Replace the Web.config with this ClientId and ClientSecret. Please note we don’t need SecondaryClientSecret appsettings.

  6. Wait for 24 hours to propagate ClientSecret to SPO

Come see me at the Microsoft Ignite Conference!

I’ll be at Microsoft Ignite the week of May 4th-May 8th. Mainly as an attendee, but I do have a few “public appearances” scheduled:

Scripting Guys Booth

This year at Ignite the Scripting Guys will have a booth, and have a schedule up on their blog showing when various PowerShell people will be there.

I’m honored to be invited to spend some time in the booth and will be there Monday Night from 7-7:30 if you’d like to say hello.

There are lots of other big names stopping by the booth throughout the conference including Todd Klindt, Mark Minasi, Jeff Hicks, Jeffrey Snover and others!

The full Schedule of guest appearances is being maintained at the Scripting guys blog:

http://blogs.technet.com/b/heyscriptingguy/archive/2015/04/25/weekend-scripter-scripting-guys-ignite-booth-schedule.aspx

Community Theater

On Wednesday from 11:35-11:55 I’m part of CSPUG’s PowerShell Q&A Live in the Community Theater, which I believe is in the expo hall.

I’ll be Joining PowerShell MVP’s Michael Blumenthal and Jeff Hicks to help answer any questions you  have.

These are all really great people in the community, and it’s a huge honor to be sharing the stage with Michael and Jeff in the Q&A panel, and sharing the booth with Ed and Teresa Wilson, along with their rock star cast of PowerShell Super Heroes who will be stopping by the booth throughout the event.

– Jack

 

Script for Auto-Adjusting Site quotas in SharePoint Online / O365 based on current useage

** IMPORTANT UPDATE #2 -this is no longer needed.

As of September 2015, Site Quotas are no longer needed!

The screenshot below came from our tenant settings screen – Set it to Automatic and forget about site quotas!

AutoStorageSPOnline

** IMPORTANT UPDATE RELATED TO SHAREPOINT / OFFICE 365 VIDEO SITES ** (Updated April 29th 2015)

If you use the script below, you may want to put in a filter to prevent the script from working on any site with the managed path of /portals/

Explanation:

Microsoft recently added Video portals to office 365.

Ours was added this morning.

I looked at it in the admin screen because I was curious what site collections had been created.

I noticed something peculiar: The Storage Quota was 0.

2015-04-29_17-34-23

You can’t set a quota to zero. Not in the UI, not in PowerShell.

Well tonight my script ran and guess what, it reset my quote on the Video portal.

Originally, Video portal storage was supposed to come out of the overall SPOnline allotment, so this may not be a big deal, maybe we needed to set it anyways?

But, since it’s not possible to set zero manually, I wonder if this was one site you didn’t have to manage/pre-allocate storage too? Or maybe MS decided to make storage unlimited?

I’m not really sure, but in the short term, I thought I’d best warn people that there are some unknowns here as it relates to using the below script with Office Video.

 

AND NOW BACK TO OUR ORIGINAL ARTICLE, as it was published on April 15th:

The year is 2015, You’ve just been given “TONS” of storage on SharePoint online, and someone says “Lets give everyone a 200GB site quota”.

Seems like a great idea, you’ll never run out of space, so why not set the limit high?

Well, it turns out, the word “Quota” has a different meaning in SharePoint Online / Office 365 than it did in SP on Premise.

In the On Premise version of SharePoint, the quota was a limit.
In SharePoint Online, it’s an Allocation.

What’s the difference you ask?

Say you have a 1000GB of storage on SharePoint on premise.

With On premise SharePoint, you can allocate a 200gb quota to 10 sites, “over committing” what you actually have. It works because space isn’t ‘reserved’ for that site, it’s just a limit. You’re telling on premise sharepoint “Don’t let any site get bigger than 200gb”.

Take a similar situation on SharePoint Online:

Say you have 1000GB of storage on SPO

You can only allocate 200GB quotas 5 times – each time you do, your total available drops by 200GB so by the 5th one, you have nothing left to give. This is true, even if the sites are empty!

So SharePoint online works a little differently, at least in 2015 it does – maybe one day this article won’t be relevant, but it is today.

What are we to do if we want to give users basically unlimited sized site collections

Now the question: What are we to do if we want to give users basically unlimited sized site collections, but we can’t allocate large numbers to EACH site collection?

Well, here’s what I did – I wrote a script that looks at how much storage each site collection is using, then adjusts it so there is a certain amount of ‘headroom’.

I run the script daily via a scheduled task.

I also have another script that sets up the connection to SharePoint Online which runs first, if you need that part, it’s elsewhere on this site.

The logic is fairly straightforward, but lets do an example:

All sites should be 4GB or more over the size used:

  • An empty site would have 4gb allocated
  • A site using 3gb would have 7gb allocated
  • A site using 10gb would have 14gb allocated.

Make sense?

That logic is pretty simple, take the size of the site, add 4gb to it, that’s it’s allocation.

For performance reasons, it would be great if we weren’t constantly adjusting each and every site, every time we run the script, the $slack setting helps with that.

Here’s the script:

(If you need help scheduling a task, I have a blog post and video here about that. )

– Jack

Script for assigning SharePoint Licenses to Office365

Adding SharePoint licenses to Office 365 can be a bit tricky.

If you add the E3 license, you get EVERYTHING that comes with E3, if that’s what you need, great, but what if you ONLY want SharePoint, and not Lync, email, etc??

I ran into this recently and used a few resources to come up with a script.

This article was really helpful:  http://www.powershellmagazine.com/2012/04/23/provisioning-and-licensing-office-365-accounts-with-powershell/

As was some script work by an awesome guy I work with named Chris.

The tricky thing here is you can’t directly grant just a SharePoint license in MSOL E3…

You have to do it subtractively.

Let me explain…..

Say you have 3 letters, A, B & C

You might expect to add a license for b like this:

Add-license -option B

It doesn’t work that way. (At least not in 2015 when I wrote this)

Instead you have to say:

Add-License -disable A C

No problem you say.

“I’ll just add code to disable A C”

That’s great, until….

Microsoft adds Option D

Now, when you try

Add-License -disable A C

You’ve just assigned a B and D license, when you only wanted to assign a B license.

Now you see the issue….

The solution is not too hard – we can pull a list of all options available, remove the one we want, and then build the disable list from that.

This way we won’t get caught when Microsoft springs options EFGHI on us.

The full script is below.

Note: there are some unused functions in the script for setting a password – if you have brand new users to Office 365, they may never have used their identity and will need the password reset and sent to them, if that’s the case, just add the call to Reset-Password -upn $upn at the appropriate place(s)

Here’s the script:

 

Create a ShareGate User mapping file between on Premise AD and o365 / Azure AD

We use ShareGate to migrate content.

We recently started using ShareGate to migrate content from On Premise to SharePoint Online.

When I did this, I found that one of our domain’s users kept showing up as errors in ShareGate – it said it could not find the user in SharePoint Online.

ShareGate has a nice feature for mapping users from one system to users in another – but doing this manually to any scale would be pretty time consuming.

Thankfully, ShareGate lets us save the mappings, which are just XML files with a .sgum file extension.

Wouldn’t it be great if there was a way to automate creating a mapping file like this for everyone in the domain at once?

Have a look at the script below, it pulls all the user accounts from an OU in AD, then looks up each user to find them in MSOL (Office 365 Azure AD) Then grabs the o365 display name and makes the mapping . Any user not found is logged so it can be dealt with separately.

The whole thing is written out as a complete .sgum file, ready to import into ShareGate the next time you migrate!

Note I didn’t figure out the XML stuff in a vacuum – I found an article on powershellmagazine.com to be very helpful and noted it in the script.

– Jack

Add a person as a site collection administrator to every Office 365 Site / SharePoint Online Site Collection

The Problem:

In SharePoint online (at least as of early 2015) site collection administrators have to be granted on a site by site basis.

When you create a new site collection using  https://yoururl-admin.sharepoint.com, you are only allowed to pick ONE administrator for the Site collection (In on premise, you used to pick two)

NewSiteCollectionSPOdialog

Now a little trick you can use is, after the site collection is created, you can check the site collection then click the “owners” tab:

SPOadminBar

and from that screen you can add as many site collection administrators as you’d like:

AddSPOadminDialog

 

But there is a downside, you can’t “select all” on all your site collections and add a user to all site collections at once.

Now, I hear you saying “Jack: What if I have 500 site collections and we add a new member to our team?” There’s got to be a better way, right? And it turns out, there is.

The Solution: PowerShell…

A Quick note before we get to the script: You’ll need the SharePoint Online Management Shell installed on your PC before this will work.
Here’s a quick overview of how to use the script:

Update all the relevant variables:

  1. Admin site URL ($adminurl), and the $username that has permissions to log into the admin site url to make the change.
  2. put in your $tenantURL
  3. Update the list of $SiteCollectionAdmins with the list of users you want to make site collection admins

Run the script.

When you run the script it will try to logon to your SPO account and will prompt you for your SPO password, then you should see some slow and steady progress as it runs through each site collection. Finally, at the end you can review the log file to see if there were any issues.

The Script: