User Profile
LeonPavesic
Joined 2 years ago
As a dedicated Microsoft enthusiast and certified professional, I specialize in Microsoft 365 Administration, Azure Administration, and application support. With a strong track record, I deliver practical solutions to meet clients' needs. My expertise spans Microsoft 365 services such as Office 365, Teams, Exchange Online, SharePoint Online, OneDrive for Business, and Power Platform. I hold certifications including Microsoft 365 Certified: Modern Desktop Administrator Associate, Microsoft Certified: Security Operations Analyst Associate, Microsoft 365 Certified: Teams Administrator Associate, and Azure Administrator Associate. I excel in identity and access management with Azure Active Directory, ensuring robust data security. Committed to staying current in the field, I continuously expand my skills to offer top-notch support. Proficient in managing Microsoft 365 systems and Azure cloud services, I handle tasks like imaging, configuration, installation, and maintenance.
User Widgets
Recent Discussions
PowerShell - GraphAPI - OneDrive Shared files - Error
Hello everybody, for changing the UPN for some number of users I need to export all the shared files in OneDrive for all users in the tenant. I have found an excellent script by the MVP Vasil Michev on the GitHub (PowerShell/Graph_ODFB_shared_files.ps1 at master · michevnew/PowerShell · GitHub). The script uses Entra ID App Registration with API permissions, GraphAPI and Powershell. I needed to change the script because it didn't export all the files, just some of them and i wanted to have a .csv export. After I changed the script, I get all the shared files, but the scripts stops after exporting the files from about half of my users (stops by the letter m in the UPN). This is the error that I am getting (for all the user until m in UPN the results are ok): ConvertFrom-Json : Cannot bind argument to parameter 'InputObject' because it is null. At C:\scripts\OneDrive_revised3.ps1:255 char:30 + return $result.Content | ConvertFrom-Json Is it an issue with a GraphAPI limitation (to many requests) or something else? How can I resolve this? Can I use a list of some users (from a csv file) to export the data only for these users? Here is the moddified script (I deleted Entra ID secrets and IDs): [CmdletBinding()] #Make sure we can use -Verbose Param([switch]$ExpandFolders,[int]$depth) function processChildren { Param( #Graph User object [Parameter(Mandatory=$true)]$User, #URI for the drive [Parameter(Mandatory=$true)][string]$URI, #Use the ExpandFolders switch to specify whether to expand folders and include their items in the output. [switch]$ExpandFolders, #Use the Depth parameter to specify the folder depth for expansion/inclusion of items. [int]$depth) $URI = "$URI/children" $children = @() #fetch children, make sure to handle multiple pages do { $result = Invoke-GraphApiRequest -Uri "$URI" -Verbose:$VerbosePreference $URI = $result.'@odata.nextLink' #If we are getting multiple pages, add some delay to avoid throttling Start-Sleep -Milliseconds 500 $children += $result } while ($URI) if (!$children) { Write-Verbose "No items found for $($user.userPrincipalName), skipping..."; continue } #handle different children types $output = @() $cFolders = $children.value | ? {$_.Folder} $cFiles = $children.value | ? {$_.File} #doesnt return notebooks $cNotebooks = $children.value | ? {$_.package.type -eq "OneNote"} #Process Folders foreach ($folder in $cFolders) { $output += (processFolder -User $User -folder $folder -ExpandFolders:$ExpandFolders -depth $depth -Verbose:$VerbosePreference) } #Process Files foreach ($file in $cFiles) { if ($file.shared) { $output += (processFile -User $User -file $file -Verbose:$VerbosePreference) } } #Process Notebooks foreach ($notebook in $cNotebooks) { if ($notebook.shared) { $output += (processFile -User $User -file $notebook -Verbose:$VerbosePreference) } } return $output } function processFolder { Param( #Graph User object [Parameter(Mandatory=$true)]$User, #Folder object [Parameter(Mandatory=$true)]$folder, #Use the ExpandFolders switch to specify whether to expand folders and include their items in the output. [switch]$ExpandFolders, #Use the Depth parameter to specify the folder depth for expansion/inclusion of items. [int]$depth) #prepare the output object $fileinfo = New-Object psobject $fileinfo | Add-Member -MemberType NoteProperty -Name "OneDriveOwner" -Value $user.userPrincipalName $fileinfo | Add-Member -MemberType NoteProperty -Name "Name" -Value $folder.name $fileinfo | Add-Member -MemberType NoteProperty -Name "ItemType" -Value "Folder" $fileinfo | Add-Member -MemberType NoteProperty -Name "Shared" -Value (&{If($folder.shared) {"Yes"} Else {"No"}}) #if the Shared property is set, fetch permissions if ($folder.shared) { $permlist = getPermissions $user.id $folder.id -Verbose:$VerbosePreference #Match user entries against the list of domains in the tenant to populate the ExternallyShared value $regexmatches = $permlist | % {if ($_ -match "\(?\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*\)?") {$Matches[0]}} if ($permlist -match "anonymous") { $fileinfo | Add-Member -MemberType NoteProperty -Name "ExternallyShared" -Value "Yes" } else { if (!$domains) { $fileinfo | Add-Member -MemberType NoteProperty -Name "ExternallyShared" -Value "No domain info" } elseif ($regexmatches -notmatch ($domains -join "|")) { $fileinfo | Add-Member -MemberType NoteProperty -Name "ExternallyShared" -Value "Yes" } else { $fileinfo | Add-Member -MemberType NoteProperty -Name "ExternallyShared" -Value "No" } } $fileinfo | Add-Member -MemberType NoteProperty -Name "Permissions" -Value ($permlist -join ",") } $fileinfo | Add-Member -MemberType NoteProperty -Name "ItemPath" -Value $folder.webUrl #Since this is a folder item, check for any children, depending on the script parameters if (($folder.folder.childCount -gt 0) -and $ExpandFolders -and ((3 - $folder.parentReference.path.Split("/").Count + $depth) -gt 0)) { Write-Verbose "Folder $($folder.Name) has child items" $uri = "https://graph.microsoft.com/v1.0/users/$($user.id)/drive/items/$($folder.id)" $folderItems = processChildren -User $user -URI $uri -ExpandFolders:$ExpandFolders -depth $depth -Verbose:$VerbosePreference } #handle the output if ($folderItems) { $f = @(); $f += $fileinfo; $f += $folderItems; return $f } else { return $fileinfo } } function processFile { Param( #Graph User object [Parameter(Mandatory=$true)]$User, #File object [Parameter(Mandatory=$true)]$file) #prepare the output object $fileinfo = New-Object psobject $fileinfo | Add-Member -MemberType NoteProperty -Name "OneDriveOwner" -Value $user.userPrincipalName $fileinfo | Add-Member -MemberType NoteProperty -Name "Name" -Value $file.name $fileinfo | Add-Member -MemberType NoteProperty -Name "ItemType" -Value (&{If($file.package.Type -eq "OneNote") {"Notebook"} Else {"File"}}) $fileinfo | Add-Member -MemberType NoteProperty -Name "Shared" -Value (&{If($file.shared) {"Yes"} Else {"No"}}) #if the Shared property is set, fetch permissions if ($file.shared) { $permlist = getPermissions $user.id $file.id -Verbose:$VerbosePreference #Match user entries against the list of domains in the tenant to populate the ExternallyShared value $regexmatches = $permlist | % {if ($_ -match "\(?\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*\)?") {$Matches[0]}} if ($permlist -match "anonymous") { $fileinfo | Add-Member -MemberType NoteProperty -Name "ExternallyShared" -Value "Yes" } else { if (!$domains) { $fileinfo | Add-Member -MemberType NoteProperty -Name "ExternallyShared" -Value "No domain info" } elseif ($regexmatches -notmatch ($domains -join "|")) { $fileinfo | Add-Member -MemberType NoteProperty -Name "ExternallyShared" -Value "Yes" } else { $fileinfo | Add-Member -MemberType NoteProperty -Name "ExternallyShared" -Value "No" } } $fileinfo | Add-Member -MemberType NoteProperty -Name "Permissions" -Value ($permlist -join ",") } $fileinfo | Add-Member -MemberType NoteProperty -Name "ItemPath" -Value $file.webUrl #handle the output return $fileinfo } function getPermissions { Param( #Use the UserId parameter to provide an unique identifier for the user object. [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string]$UserId, #Use the ItemId parameter to provide an unique identifier for the item object. [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string]$ItemId) #fetch permissions for the given item $uri = "https://graph.microsoft.com/beta/users/$($UserId)/drive/items/$($ItemId)/permissions" $permissions = (Invoke-GraphApiRequest -Uri $uri -Verbose:$VerbosePreference).Value #build the permissions string $permlist = @() foreach ($entry in $permissions) { #Sharing link if ($entry.link) { $strPermissions = $($entry.link.type) + ":" + $($entry.link.scope) if ($entry.grantedToIdentitiesV2) { $strPermissions = $strPermissions + " (" + (((&{If($entry.grantedToIdentitiesV2.siteUser.email) {$entry.grantedToIdentitiesV2.siteUser.email} else {$entry.grantedToIdentitiesV2.User.email}}) | select -Unique) -join ",") + ")" } if ($entry.hasPassword) { $strPermissions = $strPermissions + "[PasswordProtected]" } if ($entry.link.preventsDownload) { $strPermissions = $strPermissions + "[BlockDownloads]" } if ($entry.expirationDateTime) { $strPermissions = $strPermissions + " (Expires on: $($entry.expirationDateTime))" } $permlist += $strPermissions } #Invitation elseif ($entry.invitation) { $permlist += $($entry.roles) + ":" + $($entry.invitation.email) } #Direct permissions elseif ($entry.roles) { if ($entry.grantedToV2.siteUser.Email) { $roleentry = $entry.grantedToV2.siteUser.Email } elseif ($entry.grantedToV2.User.Email) { $roleentry = $entry.grantedToV2.User.Email } #else { $roleentry = $entry.grantedToV2.siteUser.DisplayName } else { $roleentry = $entry.grantedToV2.siteUser.loginName } #user claim $permlist += $($entry.Roles) + ':' + $roleentry #apparently the email property can be empty... } #Inherited permissions elseif ($entry.inheritedFrom) { $permlist += "[Inherited from: $($entry.inheritedFrom.path)]" } #Should have a Roles facet, thus covered above #some other permissions? else { Write-Verbose "Permission $entry not covered by the script!"; $permlist += $entry } } #handle the output return $permlist } function Renew-Token { #prepare the request $url = 'https://login.microsoftonline.com/' + $tenantId + '/oauth2/v2.0/token' $Scopes = New-Object System.Collections.Generic.List[string] $Scope = "https://graph.microsoft.com/.default" $Scopes.Add($Scope) $body = @{ grant_type = "client_credentials" client_id = $appID client_secret = $client_secret scope = $Scopes } try { Set-Variable -Name authenticationResult -Scope Global -Value (Invoke-WebRequest -Method Post -Uri $url -Debug -Verbose -Body $body -ErrorAction Stop) $token = ($authenticationResult.Content | ConvertFrom-Json).access_token } catch { $_; return } if (!$token) { Write-Host "Failed to aquire token!"; return } else { Write-Verbose "Successfully acquired Access Token" #Use the access token to set the authentication header Set-Variable -Name authHeader -Scope Global -Value @{'Authorization'="Bearer $token";'Content-Type'='application\json'} } } function Invoke-GraphApiRequest { param( [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string]$Uri ) if (!$AuthHeader) { Write-Verbose "No access token found, aborting..."; throw } try { $result = Invoke-WebRequest -Headers $AuthHeader -Uri $uri -Verbose:$VerbosePreference -ErrorAction Stop } catch [System.Net.WebException] { if ($_.Exception.Response -eq $null) { throw } #Get the full error response $streamReader = [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream()) $streamReader.BaseStream.Position = 0 $errResp = $streamReader.ReadToEnd() | ConvertFrom-Json $streamReader.Close() if ($errResp.error.code -match "ResourceNotFound|Request_ResourceNotFound") { Write-Verbose "Resource $uri not found, skipping..."; return } #404, continue #also handle 429, throttled (Too many requests) elseif ($errResp.error.code -eq "BadRequest") { return } #400, we should terminate... but stupid Graph sometimes returns 400 instead of 404 elseif ($errResp.error.code -eq "Forbidden") { Write-Verbose "Insufficient permissions to run the Graph API call, aborting..."; throw } #403, terminate elseif ($errResp.error.code -eq "InvalidAuthenticationToken") { if ($errResp.error.message -eq "Access token has expired.") { #renew token, continue Write-Verbose "Access token has expired, trying to renew..." Renew-Token if (!$AuthHeader) { Write-Verbose "Failed to renew token, aborting..."; throw } #Token is renewed, retry the query $result = Invoke-GraphApiRequest -Uri $uri -Verbose:$VerbosePreference } } else { Write-Verbose "Unexpected error: $errResp"; return } } #handle the output return $result.Content | ConvertFrom-Json } #Main script body #Make sure to define all the required variables $tenantId = "" $appID = "" $client_secret = "" #Use the ExpandFolders switch to specify whether to expand folders and include their items in the output. $ExpandFolders = $true #Use the Depth parameter to specify the folder depth for expansion/inclusion of items. $depth = 5 #Define the list of domains in the tenant $domains = @("contoso.com", "example.com") #Renew the token to ensure it's valid Renew-Token #Get all users in the tenant $users = Invoke-GraphApiRequest -Uri "https://graph.microsoft.com/v1.0/users?`$top=999" -Verbose:$VerbosePreference #Process each user foreach ($user in $users.value) { Write-Host "Processing $($user.userPrincipalName) OneDrive..." #Define the URI for the user's drive $uri = "https://graph.microsoft.com/v1.0/users/$($user.id)/drive/root" #Fetch items for the user's drive $items = processChildren -User $user -URI $uri -ExpandFolders:$ExpandFolders -depth $depth #Output the items for the user $sharedItems = $items | Where-Object { $_.Shared -eq "Yes" } if ($sharedItems.Count -gt 0) { $sharedItems | Export-Csv -Path "C:\temp\$($user.userPrincipalName)_OneDriveItems.csv" -NoTypeInformation -Force } } Write-Host "Export completed." Kindest regards, Leon Pavesic (LinkedIn) (Twitter)SolvedMultiple .onetoc2 OneNote files in SharePoint
Hello, in SharePoint library (from Microsoft Teams) I have found multiple .onetoc2 OneNote files in a different folder in the SharePoint library. Some of them are empty (cannot be opened), some of them can be opened (but they show only the structure - mirroring the structure of one SharePoint folder) and one of them contain the list and links to all OneNote files in SharePoint Library. Any idea why and how were these documents created? Kindest regards Leon410Views0likes1CommentOneNote document mirroring SharePoint Folder structure
Hello, i have a OneNote document in a SharePoint Library which is 1,5TB big. The document has no sites, just the structure of a folder in SharePoint. I know that it was created manually by a user, but I can't understand how the user managed to do this. The OneNote document INDESIGN has a similar structure like the INDESIGN_1 foder in the same SharePoint library, the INDESIGN_1 folder was created after the OneNote document. Anybody has an idea why and/or the OneNote document with just the folder structure and being 1,5 TB big was created? Kindest regards Leon293Views0likes0CommentsKiosk Mode - Edge Single App - Energy options
Hello, I have managed to set up a Kiosk Mode - Edge - Public browsing (InPrivate) - Single App. Everything works fine, but I can't seem to find the settings to turn off all posible sleep and hibernate options. I want the device to be always turned on without going to sleep or hibernate. What are exact settings to do that, I have tried these settings, but they don't work: Can I do it with PowerShell? Kindest regards LeonSolved551Views0likes1CommentSharePoint alternative - China
Hello, one of our departments provides images to external customers and agencies via SharePoint. Unfortunately, our Chinese agency does not have access there, as Microsoft is known to not work in China. The Agency in China does work with WPS office, which raises the question of whether we can use that instead or if there is another tool that we can use to work with China, to provide images in a secure way like with the SharePoint? Kindest regards, Leon Pavesic (LinkedIn)Solved1.5KViews0likes2CommentsFilter Users Calender entries - Shared Calendar
Hello everyone, I'm currently exploring the automation of an initiative proposed by one department in our company. Our IT employees follow a schedule of 2-3 days in home office and 2-3 days in the office. The suggestion is to create a shared calendar accessible to the entire company, displaying which IT department members are working remotely or in the office. The proposed workflow involves each IT employee adding a "whole day meeting - Home office" entry to their private calendar. Subsequently, these entries should automatically populate the shared calendar. My question is: Can this be achieved using PowerShell and a scheduled task? Is there any other solution for that? How can I get started? Kindest regards Leon PavesicSolved642Views0likes4Comments"The Microsoft Exchange Administrator has made a change that requires a restart of Outlook.” - error
Hi all, we are having this issue with some of our users. The message (error) appears just once, Outlook (M365 dekstop app) is restarted and everything is working well. Why is this happening, nothing is changed on Exchange Online and Exchange Server 2016 (we have a hybrid-mode)? Kindest regards Leon1.2KViews0likes0CommentsSharePoint Online - Report (export) all sites, folders, files with folder and file size and type
Hello, is it possible to make a report or to export all sites, folders, files from a SharePoint Online with all names, sizes and file types in a CSV file? Could this be done with directly from SharePoint Online, PowerShell or Microsoft Graph + PowerShell? I appreciate your answer. Kindest regards LeonSolved5.4KViews0likes1CommentWay to integrate a website in Microsoft Teams and have an icon in the main menu
Hi everybody, we are using simple Jira Cloud Service Management ticketing system. We have created a simple Help Desk website where the customers can create their tickets and report the issues to Jira Service Management Cloud project. I have a lot of question can we, or is it possible to integrate the Help desk website in Microsoft Teams? I know this is possible by adding a website to a channel tab, but the users wnat to have an icon (shortcut) on the Microsoft Teams main menu. Is it possible to create a simple Microsoft Teams app which opens a website in a browser (or integrated in Microsoft Teams) so they can have an icon in the main menu? Is it possible in any other way? I appreciate your reply. Kindest regards Leon PavesicSolved1.6KViews0likes2CommentsOffice 365 - Group Policy
Hello, we are using Group policies for our client computers to set the default saving document type to (Word --> .docx, for Excel --> .xslx). These GPO are having Office 2016 (and seperate Word 2016 and Excel 2016) ADMX files (settings). We are using for example User configuration / Adminisrative Templates / Micorosft Word 2016 / Word Options / Save / Default File Format --> enabled (.docx). Most of our users are getting the policy, so the standard file save type is for example .docx, but some of them (after gpudate) are not recieveing the same policy an for them the standard is .odt. Users are in the right place in AD where the GPO is assigned. All users have Office 365 version installed. Are there some new ADMX files to use? How to solve this issue? Kindest regards Leon2.4KViews0likes0Comments