Category: SharePoint

SharePoint posts

  • PowerShell Script to Download all Documents from all Doclibs, Versions Included

    I recently saw a post (maybe on Reddit) where someone was asking for a script that would download all the files in a SharePoint site. I found myself with a few spare minutes and an open ChatGPT window, so I took a swing at it. I think the results turned out pretty well. I do want to give a shout out to the Salaudeen Rajack at SharePoint Diary. We did get some help from this script of his.

    To give the script a wider audience, I submitted it to the PnP Script Samples GalleryYou can download it here.

    I tried to write it as well as I could, so I wrote it as a function inside of a module file. Because of that you have to save the script as a PSM1 file (as opposed to a regular old PS1 file). Then use Import-Module to import that PSM1 file, which adds my function, Download-SharePointFiles to your PowerShell host. Then run Download-SharePointFiles with the correct parameters. It looks like this:

    That gives you output that looks like this:

    I hope you find it helpful. Let me know in the comments if there’s any functionality you’d like me to add.

    tk

    ShortURL: https://www.toddklindt.com/POSHDownloadAllFiles

  • PnP Script Sample: Force a User Profile Property Index

    Have you ever updated some properties for a user in SharePoint Online, waited what seemed like a reasonable length of time, then did a search for that user? Have you ever done that and found your old values still there? Gah! Me too! Did you then use Mikael Svenson’s brilliant script to fix that? Yeah, me too. A few times.

    I’m also a tinkerer, and I love me some PowerShell. So I cracked open VS Code, put on some aggressive music, loaded up Mikael’s code, and looked around a bit. I found a couple of things that I’d do differently. Not that there’s anything wrong with his code, it’s good stuff. But I wanted to so some stuff like turn his code into a function, so I could add it to an existing module I have. I wanted to move the JSON file from the root of the web to the Shared Documents library, innocent little changes like that. And his code had been written several years ago. PowerShell has matured since then, as coders we’ve matured, so I cleaned a few other little things up while I was in there. It was fun, and it kept me off the streets for a while.

    After I got done I reached out to Mikael to see if he was okay with me sharing it with all of you. Mikael, being the stand up guy that he is, was totally good with it. Then I reached out to Paul Bullock about getting it published to the PnP Script Samples. I’ve been meaning to start submitting some stuff to that, but I didn’t have anything I thought was worthy. Paul graciously accepted my script, so now you can all enjoy it too.

    While you’re there, check out all the other great script samples. There’s some gold in those hills.

    tk

    ShortURL: https://www.toddklindt.com/PoshReindexUPS

  • Introducing SharePoint Server… Subscription Edition

    There were a lot of fun things announced at Ignite this week. If you haven’t already done so, check out the Ignite Book of News. It’s one handy place for all of the announcements that came out. My favorite announcement, of course, was the General Availability of the next version of on-prem SharePoint, SharePoint Server Subscription Edition!!!

    You can read Microsoft’s announcement on Tech Community blog for the official word and links. Reading is boring though, so here’s the Download Link

    I haven’t kicked the tires much yet, so I don’t have any impressions to share. Don’t fret though, I have already created the official SharePoint Server Subscription Edition Builds List.

    As I play with it more I’ll let you all know how it goes.

    tk

    ShortURL: https://www.toddklindt.com/SharePointSubscriptionEdition

  • How to Get the Microsoft 365 Connected User with PnP PowerShell

    As I’ve alluded to before, I spend a lot of time in PowerShell, and most of it in the loving embrace of the PnP.PowerShell module. From time to time I find myself wanting to include logic in my scripts based on who the script is being run as, who connected to Microsoft 365. The majority of my connections where with the good old username and password combination. When that’s the case, I could use this to find how who I had connected as:

    Connect-PnPOnline -Url https://m365x995492.sharepoint.com/admin@M365x995492.onmicrosoft.com
    ((Get-PnPConnection).PSCredential).username

    It looks like this:

    That worked great, right up to the point where I didn’t just log in with username credentials. For instance, the Sympraxis tenant requires MFA so I have to connect with the –Interactive parameter:

    Old Faithful let me down. Back to the drawing board. Poking around the Internet I saw some smart folks were using this method:

    I haven’t tried it yet with Certificate authentication, so I’m not sure how it reports that. The good news is that method also works with a username and password login:

    I’ve created a Function, Get-TKPnPCurrentUser, to make that short and easy to use. I’ve added it to the TKM365Commands module​ I published in GitHub.

    tk

    ShortURL: https://www.toddklindt.com/POSHGetCurrentPnPUser

    edit 4/15/22 – Added link to GitHub

  • Delete Some File Versions in SharePoint Online with PowerShell

    I recently got a fun email from a client. Their tenant had run over its storage allocation. After some quick investigation they realized that they had a few dozen files with a lot of versions, the average number of versions was over 1200 per file. Some files had over 3000 versions. The kicker is that these files were big, dozens or hundreds of MBs each. Thousands of files, 100s of MBs a piece? Pretty soon you’re talking about some real storage space! His question to me was how he could easily delete these unneeded versions quickly and easily? PowerShell, of course!

    Before we get to the golden PowerShell nuggets at the end, how did they end up here in the first place? Versions have been around forever in SharePoint but in the last couple of years there was a change. As part of their strategy to protect us from ransomware, Microsoft turned on versioning for all Document Libraries in SPO, and set the maximum number of versions to 500. That way if malware encrypted your site you could just roll your documents back to an unencrypted version. Pretty clever approach. The bad news is that if you don’t know this is in place, like my customer didn’t, you can chew up a lot of space by frequently uploading large files. Back to our story…

    My mancrush on the PnP PowerShell is well documented, so of course that’s the first place I looked for a solution. Sure enough, there it was, shining like a beacon of hope on a foggy night, Remove-PnPFileVersion. Do you hear angels singing? I know I do. I sent that off to my customer, dusted off my hands, and leaned back, put my hands behind my head and basked in self satisfaction. It was glorious.  Until the customer replied…

    He didn’t want to delete all of the versions of a file. He wanted to something like delete all except the last 5 versions. Remove-PnPFileVersion has 2 parameter sets. One that deletes a single version (by its ID number) and one that deletes all versions. No middle ground. While my previous victory was short lived, I knew PowerShell would come through for me here too.

    Long story short, I scribbled down a quick PowerShell script that will delete the file versions beyond the number you wish to keep. This customer had a CSV file of the files they wanted to prune, so I added support for that. I have posted the files on GitHub (DeleteOldVersions.ps1 and VersionDelete.csv ) and I’ll go over the mechanics here.

    Here is what the CSV file looks like, if you want to use that:


    The Remove-PnPFileVersion cmdlet natively handles URLs in the forms of lines 2-5. I added support for the URL having the tenant name as well because a report the customer had included that and I wanted to make it easy for them to read. I’m good like that.

    Here’s the code:First I connect to the site:

    $SiteUrl = https://m365x995492.sharepoint.com/sites/blahConnect-PnPOnline -Url $SiteUrl

    You’ll need to adjust those to your own situation. Then I load up the CSV file. If you don’t want to do this with a CSV file you don’t have to. You can manually put the file name in.

    $FileList = Import-Csv .\VersionDelete.csv

    Then I pick how many file versions I want to keep:

    $VersionsToKeep = 5

    Next I walk through the $FileList.

    foreach($File in $FileList) {

    If the FileName property has the $SiteUrl in it I take it out.

    $Filename = $File.FileName.Replace($SiteUrl,””)

    Then I grab all the FileVersions of the file:

    $FileVersions = Get-PnPFileVersion -Url $Filename

    Get-PnPFileVersion does not show the Current Version, so it will always show one fewer version than what you see in the UI. If the number of versions is greater than the version we said we wanted to keep in $VersionsToKeep then I create a list of versions in $DeleteVersionList to delete:

    if ($FileVersions.Count -gt $VersionsToKeep) { 
    $DeleteVersionList = ($FileVersions[0..$($FileVersions.Count – $VersionsToKeep)])

    With that list in hand I walk through it and run Remove-PnPFileVersion against it. In the code in GitHub I have commented out the line (Line 33 as of 9/14/21) that actually deletes the version. You’ll have to uncomment that to do anything.

    foreach($VersionToDelete in $DeleteVersionList) {
    Remove-PnPFileVersion -Url $Filename -Identity $VersionToDelete.Id –Force

    To make piping easy I output the versions deleted as a CustomObject:

    $Output = [PSCustomObject]@{
    PSTypeName = ‘TKDeletedFileVersion’
    Filename     = $Filename
    DeletedVersion     = $($VersionToDelete.VersionLabel) 
                }

    $Output

    When you look at the code you’ll notice a line at the top,
    $VerbosePreference = “Continue” 

    If you uncomment that line it will light up the Write-Verbose statements in the code. Set it back to SilentyContinue to make them go away.

    This is what it looks like with Verbosity off:

    If you need to audit which versions are being deleted you can pipe that to Export-CSV and save it to a file.

    If you want to create some versions to test this with you can use the following PowerShell:

    $DocLib = “Shared Documents”
    Get-PnPListItem -List $Doclib | select Id,@{l=”FileLeafRef”;e={$_.FieldValues.FileLeafRef}}

    That’ll get you the files in the Document Library. You can use this command to touch them and create 6 new versions:

    0..5 | foreach {Set-PnPListItem -List $Doclib -Identity 4 -Values @{“FileLeafRef”=”Building materials licences to budget for Storytelling.docx”}}

    It is also possible to filter versions by date. That way instead of deleting all but the last 5 versions, you would be able to delete all of the versions older than 30 days. That’s a blog post for a different day though.

    tk

    ShortURL: https://www.toddklindt.com/PoshDeleteSPOFileVersions

  • What is a “Dev Tenant” and why would you want one?

    My fellow Sympraxian Julie Turner recently published an outstanding blog post on what a Microsoft 365 Dev Tenant is and why you should get one. I’ve been a long time user of Dev or Demo tenants and I find them to be an invaluable resource both for people trying to gain skills in Microsoft 365, but also grizzled old veterans like myself. Like the old saying goes, “The question isn’t whether you have a Test Site, it’s whether you have a Production Site.” If you don’t have a Dev or Demo Tenant to test things in then you’ve just demoted your Production Tenant to a Test Tenant. Don’t be that person. I did a session on the PnP PowerShell today for Petri.com. One of the people there was hesitant to try out PowerShell on their tenant. I recommended they get one of these Dev tenants and hone their skills there.

    Be one of the cool kids. Read Julie’s blog post and grab a Dev Tenant.

    tk

    ShortURL: https://www.toddklindt.com/GetDevTenant