Todd’s Blog

  • Copilot Loves SharePoint Deck

    I just finished up my session at Collabdays New England. It was me and 35 of my closest friends talking about how much we love using Copilot with SharePoint. We talked about SharePoint Agents, the SharePoint Knowledge Agent, Copilot with OneDrive, and all the amazing things you can do with a Copilot Studio Agent and SharePoint. It was a blast. A couple of folks have asked me for the slide deck. Here it is. Enjoy. If you have any questions, leave them in a comment below.

    Thanks to the folks that organized CDNE 25 and all the folks that attended my session.

    tk

  • What’s new with Microsoft Copilot? Let Shane and I tell you!

    Shane Young and I love us some AI. We use AI for whatever can. One of the problems with AI these days is that it’s moving so fast we can barely keep up with it. Microsoft’s entry to the AI race, Copilot, is no exception. Every time I turn around, they’re adding new capabilities, or improving some aspect of Copilot’s performance. Shane and I were saying it was too bad there wasn’t a quick way to keep up to date on all this glorious improvement, so we decided to do something about it. We’re doing a quick, TL; DR style podcast on what’s new with Copilot. You can watch the first one now! For those of you that would prefer to read as opposed to watch us, we got you too! We will also be publishing a newsletter to go along with each episode. It can show up right in your inbox if you want.

    Let us know what you think. Do you like the rapid fire approach or would you like to hear more of that Shane and Todd banter about the topics? How often do you think we should release one of these? I promise that Shane and I read every comment on the YouTube video, so that’s a great way to tell us what you think.

    Thanks for watching.

    tk

  • Free Microsoft 365 Copilot Challenges for Enterprise Organizations webinar with me!

    My Sympraxis buddy Marc Anderson and I will be putting on a free webinar next week along with Syskit and we’d love each and every one of you to join us! It’s all about Microsoft 365 Copilot and the challenges you might face in your environment and how to deal with them.

    When is this amazing event?

    Wednesday, September 10th, 9:00 am (America/Chicago)

    How much is it?

    Free (as in beer)

    No way! How do I sign up??

    Go to this page and click “Save your spot.” The folks at Syskit will do the rest. They’re the best, aren’t they?

    If you have any questions hit me up on Twitter or Bluesky.

    tk

  • New Blog

    I’ve moved my blog over to WordPress because of the nasty SharePoint exploit that my beloved SharePoint 2010 is vulnerable to. While SharePoint is a fine blogging platform, I thought I’d go with something a little more conventional since I have to move. I’ll be spending the next few weeks figuring out how to get this all set up and getting my content moved over. Thanks for your patience.

    tk

  • 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

  • Creating a PnP.PowerShell App Registration with PowerShell

    The PnP team recently announced they were making changes to how the PnP.PowerShell and M365 CLI authenticate. The short story is that if you want to use the PnP.PowerShell module or the M365 CLI after September 9th, 2024, you’ll need to create your own Application Registration, also known as an App Reg. I know, I know, that sounds confusing and scary. Fortunately there’s nothing to it. I’ve got all the steps for you to follow along. You’ll be ready to go in no time.

    If you’re reading this, I assume you already have the PnP.PowerShell module installed. Good, because you’ll need that. The steps I’m going to show you will probably work with any version 2.0.0 or later, but I recommend updating to at least 2.9.0, which is the latest version as of this blog post. It’s got some extra sauce in it to make this go more smoothly.

    After you’ve got the PnP.PowerShell module installed, open up PowerShell. This module has supported using custom app regs for a while, so all of the plumbing is already there. We need to run the Register-PnPAzureADApp cmdlet (also aliases as Register-EntraIDApp, they’re the same thing) to create our own App Reg. Example #1 from the help is what I use. Here’s what it looks like:

    Register-PnPAzureADApp -ApplicationName PnP.PowerShell -Tenant 1kgvf.onmicrosoft.com -Store CurrentUser –Interactive

    The name of the App Reg we’re creating is “PnP.PowerShell.” My tenant is 1kgvf, but of course you’ll use your own. It’s going to create a certificate for us (we won’t need it) and store it in the CurrentUser Certificate Store. And finally, since I’m using MFA, like every good user does, I use the –Interactive switch to do browser based authentication. You’ll have to log in as a Global Admin, or a user the Global Admin has given permission to create App Regs to.

    After I log in Azure gets to work doing what it does. Since I didn’t pass any scopes to Register-PnPAzureADApp it uses its default set. You’ll get prompted to authenticate a second time then asked to consent to them.

    We’ll talk more about that in a bit.

    Once it’s done, you’ll get a screen like this:

    Here is where you’ll get the Client ID (also called AppID and AzureAppID, it’s all the same) you’ll need when you connect. In my example that’s 001ed5a0-be10-4bc3-a40c-a1cad0c987b7. You can also get that ID number by going into the Azure Portal and looking at the Enterprise applications.

    Find your App Reg and click it.

    Then you can copy it to your clipboard.

    Now that you have your ClientID, let’s use that to connect to Microsoft 365. In my case I would use this connect statement:

    Connect-PnPOnline -Url https://1kgvf.sharepoint.com/ -Interactive -ClientId 001ed5a0-be10-4bc3-a40c-a1cad0c987b7

    Of course you’ll use your own tenant name and the ClientID that you created. The one I created isn’t visible to your tenant.

    You’ll get prompted for a username and password, and hopefully some MFA. Then you’ll be connected to M365. Here’s how it all looks:

    As you can see, I’m connected and a quick function check looks like everything is working fine. Success!!! Well, sort of…

    We talked before about scopes, and how the Register-AzureADApp cmdlet used its default scopes since I didn’t specify any. Those scopes covered SharePoint, and Users, but not much else. For instance, if I try to get a list of the Teams in my tenant, I’m met with an authentication screen. After I authenticate (with a Global Admin) I get a page wanting more permission:

    Now it wants access to Read all groups, and more User permissions. I clicked Consent and then Accept. It returned my Teams to me.

    This adds some complication. If the user you normally use PnP.PowerShell with is a GA, then you’re golden. Every time you stumble onto something you can’t do, it’ll prompt you and you’ll consent. If you have a separate GA user, or someone else is doing the GA stuff for you, you’ll have to go into the Azure Portal and add the additional Scopes in there. That sounds like something that would fit really well in another blog post. Smile

    There’s another gotcha. By default, when Register-PnPAzureADApp creates the App Reg, it only gives the user that created it permission to use it. If anyone else needs to use it you’ll need to go into the Azure Portal, open the App Reg, go to the Users and Groups blade, and add the additional users. That won’t give them any additional permissions anywhere in M365, it simply gives them permission to use this App Reg when using PnP.PowerShell.

    I mentioned at the top that version 2.9.0 had some extra sauce to help with this. It can get a bit tedious adding the –ClientID SomeUglyGUID part every time you connect. This is particularly painful if you’ve got scripts and the like with connect statements that don’t have the -ClientID parameter. In 2.9.0 and later Connect-PnPOnline supports an environment variable ENTRAID_APP_ID. If no –ClientID is specified, and that variable has a value, Connect-PnPOnline will use that. Here’s what it looks like:

    That variable value will go away when you close PowerShell. If you put the $env:ENTRAID_APP_ID = "001ed5a0-be10-4bc3-a40c-a1cad0c987b7" line in your PowerShell profile it will get populated every time you open PowerShell. If you’re a local admin on your machine you can also set a persistent environment variable in an admin prompt with this line:

    [System.Environment]::SetEnvironmentVariable(‘ENTRAID_APP_ID’, ‘001ed5a0-be10-4bc3-a40c-a1cad0c987b7’, ‘User’)

    Or you can set it in the Control Panel. Again, you’ll want to use your Client ID, not mine.

    I hope that helps. If you have any questions, leave me a comment.

    tk

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

  • Happy Monday!

    I know Mondays can be rough. Fortunately I have something to help you through this particular Monday. I was recently interviewed on the “Mastering Mondays” podcast from the No More Bad Mondays guys. I had a blast catching up with Dave and Matt. We talk about our favorite tech and I recount an experience in my childhood that nearly scarred me for life. The time flew by. Give the episode a listen on your favorite platform and let me know what you think.

    tk

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

  • Syskit Blog Post on AI and PowerShell

    My buddies at Syskit and I were chatting recently and we realized we hadn’t worked together in far, far too long. We decided that needed to be remedied right away! So last week I wrote a blog post for them called Using AI to write PowerShell scripts. It’s even more fun than it sounds, I promise. In it I cover my process for using AI to write even cooler PowerShell scripts than I would be able to on my own. You can even use the free version of ChatGPT to write better PowerShell. 

    Give it a read and let us know what you think.

    tk

    Short URL: https://www.toddklindt.com/SyskitAIandPowerShell

  • How to use PowerShell 7 and PnP.PowerShell When You Can’t Install Software

    During the last Ask Sympraxis our friend Kasper Larsen relayed a question he had gotten recently, “Is it possible to run the PnP.PowerShell module if I’m not allowed to install it or PowerShell 7?” The question brought tears of sadness to my eyes. Then, my indomitable spirit kicked in, “We’ll help this person!”, it said. And here we are.

    The short answer to, “Can you run PnP.PowerShell if you can’t install anything” is a resounding, “Yes! Heck yes you can!” The answer to “how” comes in two parts. The first is to download the PowerShell 7 Zip file and run pwsh.exe out of there without installing it. The second part is to install the PnP.PowerShell module in the CurrentUser scope, so that it doesn’t try to write anything to a protected directory. After that, run PnP.PowerShell cmdlets to your heart’s content.

    Here’s what it looks like:

    There’s proof, the PowerShell way, that the user I’m logged in as isn’t an admin. First, I download the PowerShell 7 zip file and extract it to a folder in my Downloads folder.

    Then I CD to the directory and run pwsh.exe, like this:

    You can see from the $PSVersionTable that we’re running PowerShell 7. Now I install the PnP.PowerShell module to my user with the line Install-Module pnp.powershell –Scope CurrentUser.

    After I run the install I use Connect-PnPOnline like I normally would. At the bottom I highlighted where the module is installed, your personal Documents directory.

    One very important note, is that you (or anyone) won’t be able to connect if the PnP.PowerShell application registration hasn’t been approved in your tenant. This blog post, “How to Register the PnP.PowerShell App Registration if You’re not a Tenant Admin” covers it a bit. That App Registration is necessary in 99% of the use cases. You can connect and do a few SharePoint things without it, but that list is pretty short.

    I’m not sure how often this will come up, but hopefully this blog post is at least interesting. 

    tk

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

  • Simplifying Client Credentials with PowerShell: Add-ClientCredential

    If you’ve been around the block with SharePoint or Microsoft 365 administration, you know that handling client credentials can sometimes feel like juggling with fire. When I start a new engagement with a client I generally get credentials to access their tenant. Of course they immediately go into our password management tool. I also do a lot of PowerShell scripting for my clients, so I save them to the Windows Credential store too, so that I can connect with Connect-PnPOnline without having to enter them each time. And while that’s not a lot of work, I thought I could streamline it. That’s why I’ve put together a PowerShell command, Add-ClientCredential, that makes it a little easier.

    What Does Add-ClientCredential do?

    In a nutshell, this PowerShell command is designed to streamline the process of adding client credentials in a SharePoint or Microsoft 365 environment. It stores your credential for https://tenant.sharepoint.com and https://tenant-admin.sharepoint.com. If you don’t specify any credentials when you connect with Connect-PnPOnline it will look for them in the Windows Credential Store. If you have one assigned for the root of the tenant, https://tenant.sharepoint.com, it will also use that for other sites in the tenant, like https://tenant.sharepoint.com/sites/ToddisTheBest, if a credential is not saved for that specific site.

    Here’s a quick example:

    Add-ClientCredential -TenantName "contoso" -UserName admin@contoso.com

    I like this method because then my password will never show up in History or a Transcript if one is running. Since we didn’t pass it a password, it will prompt you for one. Then it will create credential entries for https://contoso.sharepoint.comhttp://contoso.sharepoint.com, and https://contoso-admin.sharepoint.com

    To pass it a password, do it like this:

    Add-ClientCredential -TenantName "contoso" -UserName admin@contoso.com -Password (ConvertTo-SecureString "YourPassword”
    -AsPlainText -Force)

    Keep in mind that will show up in plain text in PowerShell’s Get-History, or the Transcript file, if you have that running.

    I built in some smarts so that if there is already a credential stored for “Contoso” it will let you know and ask you if you want to overwrite it.

    If you want to get super fancy you can add the –TestCredential switch which will test the credentials you gave it by logging in with them. All of this is available if you run help Add-ClientCredential –Examples.

    In the background this function uses Add-PnPStoredCredential to store the credentials for you. It adds them for the root of the tenant, and the –admin URL.

    How to Get Started

    To get your hands on this little beauty, head over to my GitHub repository. You can download addclientcreds.psm1 itself, or clone the whole repo. Use Import-Module to import it into your PowerShell host and you’re ready to go.

    Wrapping Up

    addclientcreds.psm1 is my attempt to put a little more simplicity and sanity into the world of SharePoint and Microsoft 365 administration. I hope you find it as useful as I do. As always, I welcome your feedback and questions. Drop a comment below or shoot me a message on Twitter @ToddKlindt.

    tk

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