Showing posts with label powershell. Show all posts
Showing posts with label powershell. Show all posts

Thursday, August 30, 2018

Issue when executing PowerShell scripts with characters outside of A-Z

I have a PowerShell script in which I pass a parameter to command containing the Norwegian character ø, where the command sets a value on a web page.

When checking the result, it looks like this:

Hvem gjør hva

Clearly an encoding issue. My .ps1 file was saved in UTF-8, and to make it work I changed it to UTF-8 with BOM (byte order mark). This way PowerShell can correctly detect the script as being in UTF-8 and encode the characters correct. To change encoding use for example VSCode or Notepad++.

Summary

If you have characters outside of a-z in your scripts, be sure to save them as UTF-8 with BOM to avoid any encoding issues.

Cover photo by Krisitan Strand at Unsplash

Tuesday, April 24, 2018

How to run AzureAD PowerShell commandlets in Azure

I have a PowerShell script which today uses AzureAD commandlets to perform some write operations in Azure AD. This script is to be run on a schedule, and where better to run this than in Azure. It could be as a web job or as an Azure Function.

When running in an app service we cannot use interactive login, but have to use the connect signature below which takes an ADAL app id and a certificate:

Connect-AzureAD –TenantId <tenantId> –ApplicationId <appid> –CertificateThumbprint <thumbprint>

This means we have to create and ADAL app which accepts a certificate, as well as make sure we can access the certificate from the app service.

For this tutorial I’ll go with an Azure Function, but the steps are pretty much the same.

Pre-requisite

Install the AzureAD or AzureADPreview command lets on your local machine.

Steps covered

  • Create a self-signed certificate
  • Create an ADAL app
  • Grant the ADAL app access to write to AAD
  • Create an Azure Function
  • Load Azure AD PowerShell in an Azure Function
  • Connect to AzureAD using an ADAL app and a certificate

Thursday, February 15, 2018

Programmatic nuance in .Net and PowerShell which can wreck havoc


Photo by David Kovalenko at Unsplash

Took me an hour or so to figure out why something I had ported from C# to PowerShell was not working, and the culprit is how casting of decimals to bytes work.

In .Net: (byte)4.6 = 4, meaning it truncates

In PowerShell [byte]4.6 = 5, meaning it rounds up

The solution is to use [Math]::Floor instead in PowerShell, which of course works fine in .Net as well.

Friday, August 11, 2017

How to list all Communication sites in your tenant

The unique identifier for a Communication site is the web template used, and the name of the template for Communication sites is SITEPAGEPUBLISHING.

With this piece of information there are a couple of options you can use to find all the sites.

The first is to iterate over all site collections, and filter on the web template property, the other is to use search.

imageTo list all sites you can use the SPO Management Shell, CSOM tenant API, or hope my PR at PnP PowerShell get’s accepted (https://github.com/SharePoint/PnP-PowerShell/pull/998)

Basically the CSOM code looks something like this:

SPOSitePropertiesEnumerableFilter filter = new SPOSitePropertiesEnumerableFilter()
{
    IncludePersonalSite = PersonalSiteFilter.UseServerDefault,
    StartIndex = null,
    IncludeDetail = true,
    Template = "SITEPAGEPUBLISHING#0",
    Filter = null
};

var list = Tenant.GetSitePropertiesFromSharePointByFilters(filter);

Using the SharePoint Online Management Shell do this:

Connect-SPOService https://contoso-admin.sharepoint.com
Get-SPOSite -Template SITEPAGEPUBLISHING#0 -Limit ALL

With the PR accepted you would be able to use PnP Posh with the following command to list all Communication sites much like the management shell:

Connect-PnPOnline https://contoso-admin.sharepoint.com
Get-PnPTenantSite -WebTemplate SITEPAGEPUBLISHING#0

If you want to use search, you can use the Submit-PnPSearchQuery commandlet.

Submit-PnPSearchQuery -Query "webtemplate=SITEPAGEPUBLISHING" -All -RelevantResults
This approach is of course available for other templates as well. Happy iteration!

Friday, April 21, 2017

Creating a .pnp provisioning template file

SharePoint Patterns and Practices

After my demo on the PnP screen cast where I showed a provisioning solution based on PowerShell and Azure web jobs, I’ve had some questions about how you go about creating the .pnp files we use for provisioning templates.

There are basically two options, and it’s quite easy. For full samples run Get-Help <command> –Examples on the command lets. If you want to use code instead of PowerShell, look at the PowerShell code in github and see how it’s all implemented.

Generate .pnp file from a site

Connect to the site, and then run:

PS:> Get-PnPProvisioningTemplate -Out template.pnp

By naming the output .pnp, you get a .pnp file instead of and .xml file.

Generate .pnp file from a template xml file

This works for both a single .xml file, or one referencing artifacts.

Make sure the .xml file and all artifacts are stored in a folder. Then run:

PS:> Convert-PnPFolderToProvisioningTemplate -Out template.pnp -Folder c:\temp

It’s important that the .pnp file has the same name as the .xml file inside the folder, due to convention when applying the template, as you can have multiple .xml files in a complete template referenced with <xi:include> statements.

Monday, March 6, 2017

Enable usage policy for Office 365 Groups using the AAD V2 PowerShell module

A quick note, at the time of this writing you have to use the preview commandlets as the released one is missing the settings commands needed.

First off you have to install the AAD Preview V2 PowerShell module.

Find-Module AzureADPreview #to ensure it's in the list when doing install
Install-Module AzureADPreview

Next up load the module into your PowerShell session and connect to Azure AD

Import-Module AzureADPreview
$credentials = Get-Credential
Connect-AzureAD -Credential $credentials

Once connected we get a copy of the template for Unified Groups, and use this to create and set new settings. If you already have settings in place for Group.Unified to for example disable group creation, you need to load and modify this setting object instead.

$policyTemplate = Get-AzureADDirectorySettingTemplate |? Id -eq 62375ab9-6b52-47ed-826b-58e47e0e304b
$setting = $policyTemplate.CreateDirectorySetting()
$setting["UsageGuidelinesUrl"] = "https://www.contoso.com/guidelines"
$setting["ClassificationList"] = "Low,Medium,High"
$setting["DefaultClassification] = "Low"
$policySetting = New-AzureADDirectorySetting -DirectorySetting $setting

You might have to wait a little bit before it’s all working, but once all set, if you edit a groups’ settings, you will see a dropdown for classification, and a hyperlink to usage guidelines.

image

The setting is also visible on the group site.

image


Tuesday, September 20, 2016

PowerShell script to upload user profile images to Office 365

There are numerous posts out there about how to do this, but thought I’d share my small script which includes the option to have images > 10kb. The script assumes you have a folder with with images on the notation <username>.jpg. It will loop over all images and use the Set-UserPhoto commandlet to upload the image.

The first time you run the script it prompts you for the password for the account you are using and stores it as a secure string in a file to be used on sub-sequent runs or on a schedule. The script will also move images one folder up after processing.

$adminUser = "foo@contoso.onmicrosoft.com"
$localFolderPath = "d:\images\upload" 
$passwordFile = "$PSScriptRoot\userphoto-password.txt"

if(![System.IO.File]::Exists($passwordFile)){
    read-host -prompt "Type the password for $adminUser to be used (will be saved encrypted)" -assecurestring | convertfrom-securestring | out-file $passwordFile
}

$password = cat $passwordFile | convertto-securestring
$MSOLCred = new-object -typename System.Management.Automation.PSCredential `
         -argumentlist $adminUser, $password

$ExOLSession = New-PSSession -Credential $MSOLCred -authentication Basic -Configurationname Microsoft.Exchange -ConnectionURI https://outlook.office365.com/powershell-liveid/?proxyMethod=RPS -allowredirection

#load Exchange Online Management cmdlets
Import-PSSession $ExOLSession -AllowClobber

$files = ([System.IO.DirectoryInfo] (Get-Item $localFolderPath)).GetFiles() |  ForEach-Object {
    if(([IO.Path]::GetExtension($_.FullName)) -eq ".jpg") {    
        $username = [IO.Path]::GetFileNameWithoutExtension($_.FullName);    
        $userPhoto = ([Byte[]] $(Get-Content -Path $_.FullName -Encoding Byte -ReadCount 0))
        Set-UserPhoto -Identity $username -PictureData $userPhoto -Confirm:$False
        
        #move files one folder up after processing
        $destinationFolder = Split-Path -Parent $_.Directory.FullName
        move-item $_.FullName $destinationFolder
    }
}
#unload session
Remove-PSSession $ExOLSession

Wednesday, September 16, 2015

Export and import property bag values from SharePoint using PowerShell

This one is for us oldies still doing on-premises work with SharePoint.

image

I’m currently working on a 2010 to 2013 migration and we need to move some values from the farm and web application property bags as we’re not doing a 1:1 migration, but merging multiple 2010 farms solutions into one new 2013 farm.

So I googelized a bit and came up with this script which can export and import property bag values from SPFarm, SPWebApplication, SPSite and SPWeb. Should be pretty self explanatory to use but it could look like this:

./Export-Import-Props.ps1 –Url http://myserver -CsvFile ./test.csv -Level SPWebApplication -Mode Export

Monday, March 24, 2014

Caveats when using Summary Link Web Part in a Web Template

My scenario was that the Summary Link Web Part had been used on a site which was to be saved as a site template using the UI (Save site as template). Saving the template worked fine, but once you created a new site based on the template you got the infamous “List does not exist” error.

The reason for the error is that the SummaryLinkWebPart class inherits the DataFormWebPart class, which has a property called ListId. If the page which hosts the Summary Links Web Part is located in for example SitePages, then the id will point to that list. Once you save the template, this id will come along, and will of course not exist in the new site.

When it comes to the Summary Link Web Part it really don’t need a reference to a list, as it’s storing all the data inside the web part itself. To fix up the template site before saving it I wrote the following PowerShell script.

function FixWebpart($wpm) {
$count = $wpm.WebParts.Count-1
ForEach ($number in 1..$count )
{
$webpart = $wpm.WebParts[$number]
# Check if it's a summary link web part
if( $webpart.PsObject.TypeNames[0] -eq 'Microsoft.SharePoint.Publishing.WebControls.SummaryLinkWebPart' ) {
write-host "Fixing listid - " + $webpart.Title + " : " + $webpart.ID
# Set the id to a blank GUID
$webpart.ListId = [guid]::Parse("00000000-0000-0000-0000-000000000000")
$wpm.SaveChanges($webpart)
}
}
}

#Get a reference to the template site
$web = get-spweb https://intranet.contoso.com/sites/template
$list = $web.Lists.TryGetList("Site Pages")

foreach($item in $list.Items) {
$wpm = $web.GetLimitedWebPartManager($item.Url, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared)
FixWebpart($wpm)
}

Monday, November 11, 2013

Install Display Templates using PowerShell (or copy files using WebDAV in SharePoint)

I’m in the process of writing a Search Center configuration script for SharePoint in PowerShell, and in the process I wanted to copy my display templates as well.

I could have used the SharePoint API to upload the files into the _catalogs/masterpage/Display Templates folder, but this felt like too much work.

My next thought was to copy the files using WebDAV. I started my search on the interwebs and found some posts around PowerShell and WebDAV, but nothing really clear and simple. Then I had an epiphany, maybe I can just copy the files? And you can!!

$dest = '\\intranet.contoso.com@80\_catalogs\masterpage\Display Templates\'
Copy-Item LocalPath -Destination $dest -Recursive

It’s a matter of formatting the URL in a server UNC notation and it just works.

What this doesn’t do is making sure the item copied is approved and published as a major version in SharePoint. To do this you either have to use the SharePoint API from PowerShell, or for example navigate to https://intranet.contoso.com/search/_layouts/DesignDisplayTemplates.aspx and filter on Approval Status = Draft, and publish each one.

Personally I change the settings on the _catalogs/masterpage library to not require approval or check-in/check-out, and only have major versions. If doing this you have to make sure you have control over the library as any saved change will go live right away – this means using a test environment or test site collection for the search page first is highly recommended.

Saturday, June 9, 2012

Using PowerShell in a .NET installer for a SharePoint App

powershell_2This is not a post about how to invoke PowerShell from within .NET or why you should do it. It is a post about second guessing why you write code the way you do.

At Puzzlepart we have created a time tracking application and we have an .exe installer to provision a site, and create all lists and content types needed. Some weeks ago we decided to have the installer deploy the WSP as well, and not only to post-deploy work.