Recently we wrote a flow that will run daily once and will pick all the tasks due in the last 24 hours i.e. schedule end date less than equal to utcNow() and greater than equal to addDays(UTCNow(),-1)
Interestingly we observed one of the task records not picked.
The scheduled end date on the task record was – 2024-07-22T20:00:00Z
And for the flow the filter condition was –
scheduledend le 2024-07-23T20:00:35.5173871Z and scheduledend ge 2024-07-22T20:00:35.5173943Z
If we look at the date for the greater than equal condition, we can see that the seconds part is 35, the exact time when the List rows step would have run, and in case of that particular task record is 00, so it was not picked.
Then we applied the below formatDateTime function, excluding the time part.
(scheduledend le ‘@{formatDateTime(utcNow(),’yyyy-MM-dd’)}’ and scheduledend ge ‘@{formatDateTime(addDays(utcNow(),-1),’yyyy-MM-dd’)}’ and _regardingobjectid_value ne null and statecode eq 0)
Again we saw few tasks not picked,
The records that were not picked had scheduledenddate as
2024-07-25 18:00:00.000
2024-07-25 19:00:00.000
And as per new condition
scheduledend = ‘2024-07-24’ which essentially was
scheduledend = ‘2024-07-24 00:00:00.0000’
Eventually we updated the flow’s Filter Rows condition to include only the hour and minutes, ignoring the seconds/milliseconds because of which we got the issue in the first place.
(scheduledend le ‘@{formatDateTime(utcNow(),’yyyy-MM-dd HH:mm’)}’ and scheduledend ge ‘@{formatDateTime(addDays(utcNow(),-1),’yyyy-MM-dd HH:mm’)}’ and _regardingobjectid_value ne null and statecode eq 0)
One more example for more clarity –
Below we are creating a contact record and setting values for 3 date time fields, UTC1, UTC2, UTC3.
Sharing the sample code that we can use for checking if a particular folder exists and if not then create it in SharePoint Online. It uses PnP Framework and Azure Ad App only permissions.
We will be checking for and creating the folder at the below location.
On a successful run, we can see the folder named “MyFolder” created the document library.
Below is the sample code
static void Main(string[] args)
{
var siteUrl = "https://w72tk.sharepoint.com/sites/MyTeamSite";
var applicationId = "d7eaeeb7-ef0a-474d-9b94-567013576c14";
var password = "xyz";
var domain = "w72tk.onmicrosoft.com";
var certPath = @"C:\SharePointApp\MyTestCertificate.pfx";
var authManager = new AuthenticationManager(applicationId, certPath, password, domain);
var foldertoCheck = "MyFolder";
using (var clientContext = authManager.GetContext(siteUrl))
{
var currentWeb = clientContext.Web;
var folderExists = currentWeb.DoesFolderExists(foldertoCheck);
if (!folderExists)
{
var list = clientContext.Web.Lists.GetByTitle("Documents");
list.RootFolder.Folders.Add(foldertoCheck);
clientContext.ExecuteQuery();
}
}
}
#Requires -RunAsAdministrator
<#
.SYNOPSIS
Creates a Self Signed Certificate for use in server to server authentication
.DESCRIPTION
.EXAMPLE
.\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21
This will create a new self signed certificate with the common name "CN=MyCert". During creation you will be asked to provide a password to protect the private key.
.EXAMPLE
.\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21 -Password (ConvertTo-SecureString -String "MyPassword" -AsPlainText -Force)
This will create a new self signed certificate with the common name "CN=MyCert". The password as specified in the Password parameter will be used to protect the private key
.EXAMPLE
.\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21 -Force
This will create a new self signed certificate with the common name "CN=MyCert". During creation you will be asked to provide a password to protect the private key. If there is already a certificate with the common name you specified, it will be removed first.
#>
Param(
[Parameter(Mandatory=$true)]
[string]$CommonName,
[Parameter(Mandatory=$true)]
[DateTime]$StartDate,
[Parameter(Mandatory=$true)]
[DateTime]$EndDate,
[Parameter(Mandatory=$false, HelpMessage="Will overwrite existing certificates")]
[Switch]$Force,
[Parameter(Mandatory=$false)]
[SecureString]$Password
)
# DO NOT MODIFY BELOW
function CreateSelfSignedCertificate(){
#Remove and existing certificates with the same common name from personal and root stores
#Need to be very wary of this as could break something
if($CommonName.ToLower().StartsWith("cn="))
{
# Remove CN from common name
$CommonName = $CommonName.Substring(3)
}
$certs = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object{$_.Subject -eq "CN=$CommonName"}
if($certs -ne $null -and $certs.Length -gt 0)
{
if($Force)
{
foreach($c in $certs)
{
remove-item $c.PSPath
}
} else {
Write-Host -ForegroundColor Red "One or more certificates with the same common name (CN=$CommonName) are already located in the local certificate store. Use -Force to remove them";
return $false
}
}
$name = new-object -com "X509Enrollment.CX500DistinguishedName.1"
$name.Encode("CN=$CommonName", 0)
$key = new-object -com "X509Enrollment.CX509PrivateKey.1"
$key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
$key.KeySpec = 1
$key.Length = 2048
$key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
$key.MachineContext = 1
$key.ExportPolicy = 1 # This is required to allow the private key to be exported
$key.Create()
$serverauthoid = new-object -com "X509Enrollment.CObjectId.1"
$serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1") # Server Authentication
$ekuoids = new-object -com "X509Enrollment.CObjectIds.1"
$ekuoids.add($serverauthoid)
$ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
$ekuext.InitializeEncode($ekuoids)
$cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1"
$cert.InitializeFromPrivateKey(2, $key, "")
$cert.Subject = $name
$cert.Issuer = $cert.Subject
$cert.NotBefore = $StartDate
$cert.NotAfter = $EndDate
$cert.X509Extensions.Add($ekuext)
$cert.Encode()
$enrollment = new-object -com "X509Enrollment.CX509Enrollment.1"
$enrollment.InitializeFromRequest($cert)
$certdata = $enrollment.CreateRequest(0)
$enrollment.InstallResponse(2, $certdata, 0, "")
return $true
}
function ExportPFXFile()
{
if($CommonName.ToLower().StartsWith("cn="))
{
# Remove CN from common name
$CommonName = $CommonName.Substring(3)
}
if($Password -eq $null)
{
$Password = Read-Host -Prompt "Enter Password to protect private key" -AsSecureString
}
$cert = Get-ChildItem -Path Cert:\LocalMachine\my | where-object{$_.Subject -eq "CN=$CommonName"}
Export-PfxCertificate -Cert $cert -Password $Password -FilePath "$($CommonName).pfx"
Export-Certificate -Cert $cert -Type CERT -FilePath "$CommonName.cer"
}
function RemoveCertsFromStore()
{
# Once the certificates have been been exported we can safely remove them from the store
if($CommonName.ToLower().StartsWith("cn="))
{
# Remove CN from common name
$CommonName = $CommonName.Substring(3)
}
$certs = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object{$_.Subject -eq "CN=$CommonName"}
foreach($c in $certs)
{
remove-item $c.PSPath
}
}
if(CreateSelfSignedCertificate)
{
ExportPFXFile
RemoveCertsFromStore
}
Specify the password and note it down as it will be used for connection.
Upload the certificate to the Azure AD App registered.
For the console app, we installed the PnP.Framework Nuget Package
The sample code –
try
{
var authManager = new AuthenticationManager(applicationId, certPath, password, domain);
using (ClientContext clientContext = authManager.GetContext(siteUrl))
{
var folder = clientContext.Web.GetFolderByServerRelativeUrl(folderRelativeUrl);
clientContext.Load(folder);
clientContext.Load(folder.Files);
clientContext.ExecuteQuery();
foreach (var file in folder.Files)
{
if (countFilesToImport < maxFilesPerCycle)
{
_filesToImport.Add(file);
}
countFilesToImport++;
}
}
}
catch (Exception ex)
{
System.Console.WriteLine("Error: " + ex.Message);
if (ex.InnerException != null)
{
System.Console.WriteLine("Inner Exception: " + ex.InnerException.Message);
}
}
}
We can see our app is successfully connected.
The other option is to use the SharePoint app-only, which is not recommended by Microsoft.
We can see the following message for it.
Starting April 2, 2026, Azure Access Control service (ACS) usage will be retired for SharePoint in Microsoft 365 and users will no longer be able to create or use Azure ACS principals to access SharePoint. Learn more about the Access Control retirement
Microsoft has introduced a new feature, through which we can now specify a particular app as a start-up app, that will open up when we launch the Power Apps mobile, instead of waiting for the home page / or selecting it from favorites.
Below we can select the option Open at Startup to specify the Customer Service Hub app as the startup app as an example.
Or we can swipe left to mark an app as “Startup App”
We can see an icon next to the app.
Now launching the Power Apps mobile app will directly open the Customer Service Hub app.
Using the Remove from startup option we can remove it as the startup app
We can only have one app set as a startup app, if we try setting up another app as a startup we get the notification that it will replace the existing app.