Author Archives: Nicolas Riousset

Migrating a NAS based organization to Microsoft SharePoint and Microsoft 365 Groups

Here’s the context : you are a lawyer, working on many business cases. You rely on a local file server (NAS) to store all your contracts, documents, files. There’s one folder for each business case. You’re successful, and hire one employee, then another one. You also start collaborating with experts outside of your organization, and you need to manage collaborative work on all your Word, Excel, PowerPoint documents. You need to manage access to the files because not everyone has access to everything. Moreover, you’d like to follow who is doing what, and ease communication on each business case.

That’s when everything crumbles. Files get duplicated, you don’t know which version is the most up to date. Emails are out of control, because people tend to include the whole planet to ensure all persons concerned will receive their email, or at the opposite they click on “reply” instead of “reply all” and forget to keep updated a critical person.

Your wish list to Santa then becomes something like this :

  1. All my files should be stored in a single place, accessible from within and from outside my organization
  2. My files should be versionned, so that I can easily restore a previous version
  3. One must be able to edit concurrently a document, without facing potential painful merge process
  4. I should be able to easily grant or remove access to my files
  5. I would have a global strategy for access ocontrol to my documents, while still being able to fine tune permissions for specific resources or collaborators
  6. A web page or wiki, would give an overview of recent activity on each case
  7. A mail adress should be associated to the case, to ease document transmission
  8. I should be able to define tasks, and their owner, to keep track of Who’s doing What, When.
  9. A calendar would allow me to keep track of events related to each case

All this is what you would get by switching to a Microsoft 365 environment, through a SharePoint Team site for each case, coming with its associated Office 365 group, its default documents library, email addresse, home page, Ms planner plan for tasks management.

However, if you have an existing environment, with tens or hundreds of opened cases, migrating manually will require an awful lot of time, and will be error prone.

Happily, this can be automated using PowerShell scripts. Microsoft provides PowerShell extensions for its clound environments. However, we will rather use PnP PowerShell, “a cross-platform PowerShell Module providing over 650 cmdlets that work with Microsoft 365 environments”. This will make the creation of the SharePoint Team site, and of all the associated resources a breathe (or almost a breathe).

The PowerShell scripts below will take care of creating the SharePoint Team Site, and uploading to its documents library all files and folders from a local folder.

But first, you need PowerShell 7. On my Windows 11, the PowerShell Version was 5.1. You can manually download and install PowerShell 7 from the Windows Store, as described here.

Then, install Pnp PowerShell Module, as described here, or download the setup.ps1 script

Install-Module -Name PnP.PowerShell
Import-Module PnP.PowerShell

Then, given a folder, the targeted root SharePoint site, new site name and owner, and local folder to upload, the migrate.ps1 script will take care of creating the SharePoint site with the uploaded files. Ex :

.\migrate.ps1 https://riousset.sharepoint.com 'Affaire 123' '.\Affaire 123\' nicolas@riousset.onmicrosoft.com affaire-123 

The migrate.ps1 script :

if ($args.count -lt 5) {
	$scriptName = $MyInvocation.MyCommand.Name
	write-host "Utilisation:" $scriptName "<url racine du site sharepoint> <nom du site à créer> <répertoire à uploader> <owner email> <site email>"
	exit
}

#Config Variables
#$AdminSiteURL = "https://riousset.sharepoint.com"
$AdminSiteURL = $args[0]
$displayName = $args[1]
$folder = $args[2]
$owner = $args[3]
$mailNickname = $args[4]

$description = $displayName
 
Try {
	#Connect to PnP Online
	Connect-PnPOnline -Url $AdminSiteURL -Interactive
 
	#Create a new Office 365 group
	# New-PnPMicrosoft365Group -DisplayName $displayName -MailNickname "HRAdmin" -Owners $owner -Members @($owner) -IsPrivate
	$site = New-PnPMicrosoft365Group -DisplayName $displayName -Description $description -MailNickname $mailNickname -Owners $owner -Members @($owner) -IsPrivate 

	write-host ($site | Format-Table | Out-String)

	& "./upload.ps1" $site.SiteURL $folder
}
Catch {
    write-host -f Red "Error:" $_.Exception.Message
}

Whic itself calls the upload.ps1 script to populate the ShrePoint documents library from the given local folder :

# Upload file to site
# https://theitbros.com/powershell-upload-file-to-sharepoint/#penci-Install-the-PnP-PowerShell-Module

if ($args.count -lt 2) {
	$scriptName = $MyInvocation.MyCommand.Name
	write-host "Utilisation:" $scriptName "<url racine du site sharepoint> <répertoire à uploader>"
	exit
}

# What is the target SharePoint site URL for the upload? 
# $spoSite = 'https://riousset.sharepoint.com/sites/HRAdmin2/' 
$spoSite = $args[0] 

# What is the location of the files to upload? 
$localFolder = $args[1]

# What is the target document library relative to the site URL? 
$spoDocLibrary = "Documents partages"

Connect-PnPOnline -Url $spoSite -Interactive

Get-PnPSite

function Upload-Folder {
	param (
        	$localFolder,
        	$remoteFolder
    	)

    Write-host 'Uploading folder' $localFolder.toString() ' to ' $remoteFolder.toString()

    $resolvedRemoteFolder = Resolve-PnPFolder -SiteRelativePath $remoteFolder


    $files = Get-ChildItem $localFolder -File

    foreach ($file in $files) { 
        write-host 'Uploading file ' $file.FullName.ToString()
	$uploadedFile = Add-PnPFile -Path ($file.FullName.ToString()) -Folder $remoteFolder -Values @{"Title" = $($file.Name) } 
    }

    $subfolders = Get-ChildItem $localFolder -Directory
    foreach ($subfolder in $subfolders) { 
	$folderName = Split-Path $subfolder.FullName -Leaf
        Upload-Folder -localFolder $subfolder.FullName -remoteFolder "$remoteFolder/$folderName/"
    }

}


Upload-Folder -localFolder $localFolder -remoteFolder $spoDocLibrary

If the scripts, you should see the new site appear in your SharePoint admin portal, usually https://<tenant>-admin.sharepoint.com/

How to delete a 0 Kb file reported as a not found by Windows ?

I ran into this incredibly frustrating issue while generating some CSV files for GPT Assistants : a 0 kb file had been created, and when trying to delete, it failed with a windows error message reporting that the file didn’t exist :

The file properties didn’t look odd, except for the 0 Kb size, and the missing extension :

After testing some command lines with “del”, trying to rename the file, move it, delete the whole folder using third party tools like Total Commander, the only thing that worked was that command line to remove the whole folder :

rd /s "\\?\d:\code\xml2csv\target\test-classes"

And eventually, I found the issue : the problematic filename was generated automatically by an app, and contained invalid characters : “Code civil – Titre préliminaire : De la publication, des effets et de l’application des lois en général.csv”, which were responsible of the invalid file state. The filename was displayed only up to the “:”.

Release Failed when publishing to Sonatype

While trying to publish a new version of my fork of mysql-backup4j, the release of the latest version failed with error “Event: Failed: Repository Writable”, whether I tried to publish using “mvn deploy” (whatever the value of the autoReleaseAfterClose setting), or from the nexus repository manager portal.

The maven “mvn deploy” command returned the following error

[ERROR]
[ERROR] Nexus Staging Rules Failure Report
[ERROR] ==================================
[ERROR]
[ERROR] Repository "frneolegal-1040" failures
[ERROR]   Rule "RepositoryWritePolicy" failures
[ERROR]     * Artifact updating: Repository ='releases:Releases' does not allow updating artifact='/fr/neolegal/mysql-backup4j/1.2.3/mysql-backup4j-1.2.3.jar'

While the Nexus Repository manager displayed this one

Once identified, the issue was kind of obvious. My maven “target” folder hadn’t been cleaned prior to the compilation, and the artefacts of the previous version were still present. The deploy operation was pushing the new and old artefacts, triggering a release failure, since the previous version had already been released.

Deleting the “target” folder manually – or even better using the “mvn clean” command – solved the issue. And to prevent any future occurence, just use the following maven command :

mvn clean deploy

How to create email folders in Microsoft Office 365 Groups ?

Let’s say you have a Ms Office 365 “Support” group, whose emails are managed by your tech support. You need to create emails folders and rules to organize your Support mailbox. Yet, nowhere is a menu to Create these folders in Outlook.

It came to me as a surprise, but this feature is not supported by default. However, as a Ms 365 admin, you can partially enable it, provided that your users rely only on Outlook Web Access (OWA), and not on the Outlook desktop application, because the group folders will on be visible on the web version of Outlook.

Microsoft documented the procedure here. In brief, you’ll have to use PowerShell to :

  1. Enable folders and rules creation, using :
    Set-OrganizationConfig -IsGroupFoldersAndRulesEnabled $true
  2. Authorize folders and rules creation, using :
    Set-OrganizationConfig -IsGroupMemberAllowedToEditContent $true

But if you are Ms 365 newbie, like me, you may have to first setup your powershell environment. Here is the complete – summarized – sequence :

  1. Ensure your Ms Office 365 account is an admin account
  2. On your Windows Machine, run PowerShell as an administrator, so that you’ll be able to Install the Exchange Online Powershell module (as documented by Microsoft here), and run the following commands.
  3. Install-Module -Name PSWSMan
  4. Install-Module -Name ExchangeOnlineManagement
  5. Update-Module -Name ExchangeOnlineManagement
  6. Import-Module ExchangeOnlineManagement;
  7. Connect-ExchangeOnline -UserPrincipalName <your_user_name>
  8. Set-OrganizationConfig -IsGroupFoldersAndRulesEnabled $true
  9. Set-OrganizationConfig -IsGroupMemberAllowedToEditContent $true

Once the configuration modified, there’s a delay for the change to be taken into account. You may immediately see the “Create subfolder” menu appear when right clicking on your group in OWA, yet you may get a “Permission denied” error for a while. However, after half an hour, I was able to create and view Group folders, but only in OWA, as documented by Microsoft.