Is it possible to use connect-sposervice with appId and app secret? - powershell

Is it possible to use the Connect-SPOService cmdlet with an application identifier & secret? I need to get information about site collections within an azure function that are only available through the get-sposite cmdlet.
I'm trying to set up an Azure Function that uses the SharePoint Online PowerShell module to report all site collections that have external sharing enabled.
As I don't want to include my personal credentials in this Azure Function I set up an application identifier in Azure AD.
I am able to use this app id with the PnP Cmdlets (connect-pnponline -appid ...) but the pnp command get-pnpsite do not return the needed detail information.
Below is the code with pnp framework, where all Sharing* properties are empty.
Connect-PnPOnline -AppId $appid -AppSecret $appsecret -Url $adminUrl
$content = #()
Get-PnPTenantSite -Filter "Url -notlike ""*/personal*""" | ? {$_.SharingCapability -ne "Disabled" } | % {
$connection = Connect-PnPOnline -ReturnConnection -Url $_.url -AppId $AppId -AppSecret $AppSecret
$site = Get-PnPSite -Connection $connection;
$content += #{
title= $site.Title;
url=$site.Url;
owner=$site.Owner;
SharingCapability=$site.SharingCapability;
SharingDomainRestrictionMode=$site.SharingDomainRestrictionMode;
SharingAllowedDomainList=$site.SharingAllowedDomainList;
SharingBlockedDomainList=$site.SharingBlockedDomainList}
}
This Code works, but needs actural user credentials:
param (
# Parameter help description
[Parameter(Mandatory=$true)]
[string]$TenantName,
# Parameter help description
[Parameter(Mandatory=$true)]
[string]$DestinationPath
)
$dateStr = Get-Date -Format yyyy-MM-dd_HH-mm-ss
$filename = "ExternalSharingReport_$dateStr.csv"
$content = #()
$adminUrl = "https://$TenantName-admin.sharepoint.com"
Connect-SPOService -Url $adminUrl
$content += "Title; Url; Owner; SharingCapability; SharingDomainRestrictionMode; SharingAllowedDomainList; SharingBlockedDomainList"
Get-SpoSite | ? {$_.Url -notlike "*/personal*" -AND $_.SharingCapability -ne "Disabled" } | % {
$site = Get-SPOSite $_.url;
$content += "$($site.Title); $($site.Url); $($site.Owner); $($site.SharingCapability); $($site.SharingDomainRestrictionMode); $($site.SharingAllowedDomainList); $($site.SharingBlockedDomainList)"
}
$completPath = Join-Path -Path $DestinationPath -ChildPath $filename
$content > $completPath
I would expect to be able to use the default cmdlet like this:
Connect-SPOService $adminUrl -AppId $appId -AppSecret $appSecret

You have to grant permission to the app.
Either at site collection level or at tenant level.
Grant permission at site collection level :
Open https://yourtenant.sharepoint.com/sites/yoursite/_layouts/15/appinv.aspx
Paste your cilent ID in the first field and click Lookup. It should autopopulate the otherfields
Paste the app permission request in the later field. It may vary depending on the permission you want to give. Do not forget to grant AppOnly authentication. Ex: full trust on the site collection :
<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl" />
</AppPermissionRequests>
Grant to tenant level
Same as above, but using https://yourtenant-admin.sharepoint.com/_layouts/15/appinv.aspx
Full control in the whole tenant request is :
<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />
</AppPermissionRequests>

Related

Create azure dynamic group from azure functions powershell

I am trying to create an azure function that has to create azure dynamic group when i execute the function from MS flow. I am using below code for this purpose.
$groupName = $Request.Query.Name
$groupDesc = $Request.Query.Desc
$domainnames = $Request.Query.DomainName
$dynamicrule = ""
Foreach($domainname in $domainnames.Split(";"))
{
$dynamicrule = $dynamicrule + "(user.userPrincipalName -contains ""_$domainname"") or";
}
$dynamicrule = $dynamicrule -replace ".{2}$"
$dynamicrule = $dynamicrule + "and (user.objectId -ne null)";
New-AzureADMSGroup -DisplayName $groupName -Description $groupDesc -MailEnabled $False -MailNickName "group" -SecurityEnabled $True -GroupTypes "DynamicMembership" -MembershipRule $dynamicrule -MembershipRuleProcessingState "On"
When i execute the above command, i am getting below error messgae.
ERROR: The term 'New-AzureADMSGroup' is not recognized as the name of a cmdlet, function, script file, or operable program.Check the spelling of the name, or if a path was included, verify that the path is correct and try again.Exception :Type : System.Management.Automation.CommandNotFoundExceptionErrorRecord
Can sombody please help me on how can i create dynamic groups using azure function app.
Thanks,
Venu
From the error message, you did not install AzureAD powershell module in your function app. And if you want to create a dynamic group, you need to use the -MembershipRule parameter, it is just available in the preview version i.e. AzureADPreview module. Though the doc looks like the parameter is available in AzureAD, but per my test, it is not available.
Actually it is easy to solve the issue, but if you want to create a dynamic group with New-AzureADMSGroup, there will be a few follow-up issues, you could follow the steps below.
1.Navigate to the function app in the portal -> Identity -> enable the system-assigned identity(MSI) for your app.
2.Navigate to App files -> host.json -> make sure the managedDependency is Enabled.
{
"version": "2.0",
"managedDependency": {
"Enabled": true
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
In the requirements.psd1, add the AzureADPreview like below, then it will install the AzureADPreview module for you automatically.
#{
'Az' = '5.*'
'AzureADPreview' = '2.0.2.129'
}
In the profile.ps1, remove all the things and add the lines below, this is used to solve the issue related to AzureAD powershell in function, without it, you will get an error, details here.
$64bitPowerShellPath = Get-ChildItem -Path $Env:Windir\WinSxS -Filter PowerShell.exe -Recurse -ErrorAction SilentlyContinue | Where-Object {$_.FullName -match "amd64"}
$env:64bitPowerShellPath=$64bitPowerShellPath.VersionInfo.FileName
3.If you want to use New-AzureADMSGroup to create group in Azure AD, you need the permission in Microsoft Graph, in this case, we use MSI to auth, so use the commands below to give the permission to your MSI.
Run the commands below in local with the Global admin user account, replace <functionapp-name>:
Connect-AzureAD
$MSI = (Get-AzureADServicePrincipal -Filter "displayName eq '<functionapp-name>'")
$MSGraphAppId = "00000003-0000-0000-c000-000000000000"
$GraphServicePrincipal = Get-AzureADServicePrincipal -Filter "appId eq '$MSGraphAppId'"
$PermissionName = "Group.ReadWrite.All"
$AppRole = $GraphServicePrincipal.AppRoles | Where-Object {$_.Value -eq $PermissionName -and $_.AllowedMemberTypes -contains "Application"}
New-AzureADServiceAppRoleAssignment -ObjectId $MSI.ObjectId -PrincipalId $MSI.ObjectId -ResourceId $GraphServicePrincipal.ObjectId -Id $AppRole.Id
4.After step 2, navigate to the kudu(in the Advanced Tools blade of the function app) -> data -> ManagedDependencies -> click the file with the format like 201208083153165.r(choose the newest one via the Modified time) -> check if the AzureADPreview module was installed successfully like below.
5.After the module was installed, in your function code, use the lines below, in my sample, I use this sample to test directly, you could change the code depends on your requirements, remember to replace 201208083153165.r with yours in step 4, it works fine on my side.
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."
# Interact with query parameters or the body of the request.
$name = $Request.Query.Name
if (-not $name) {
$name = $Request.Body.Name
}
$body = "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
if ($name) {
$body = "Hello, $name. This HTTP triggered function executed successfully."
}
$script = {
if ($env:MSI_SECRET) {
Disable-AzContextAutosave -Scope Process | Out-Null
Connect-AzAccount -Identity
}
$context = Get-AzContext
$graphtoken = (Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com").Token
$aadtoken = (Get-AzAccessToken -ResourceUrl "https://graph.windows.net").Token
Import-Module D:\home\data\ManagedDependencies\201208083153165.r\AzureADPreview
Connect-AzureAD -AccountId $context.Account -TenantId $context.Tenant -MsAccessToken $graphtoken -AadAccessToken $aadtoken
New-AzureADMSGroup -DisplayName "joyd1" -Description "Dynamic group created from PS" -MailEnabled $False -MailNickName "group" -SecurityEnabled $True -GroupTypes "DynamicMembership" -MembershipRule "(user.department -contains ""Marketing"")" -MembershipRuleProcessingState "On"
}
&$env:64bitPowerShellPath -WindowStyle Hidden -NonInteractive -Command $Script
# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]#{
StatusCode = [HttpStatusCode]::OK
Body = $body
})
Check the group in the portal:

delete user from all site collections

Currently I have this script:
#Config Parameters
$AdminSiteURL="adminsite"
$UserAccount = "henk#test.nl"
#Connect to SharePoint Online Tenant Admin
Connect-SPOService -URL $AdminSiteURL -Credential (Get-Credential)
#Get all Site Collections
$SitesCollections = Get-SPOSite -Template STS#0 -Limit ALL
#Iterate through each site collection
ForEach($Site in $SitesCollections)
{
Write-host -f Yellow "Checking Site Collection:"$Site.URL
#Get the user from site collection
$User = Get-SPOUser -Limit All –Site $Site.URL | Where {$_.LoginName -eq $UserAccount}
#Remove the User from site collection
If($User)
{
#Remove the user from the site collection
#Remove-SPOUser -Site $Site.URL –LoginName $UserAccount
Write-host -f Green "`tUser $($UserAccount) has been removed from Site collection!"
}
}
Our domain is #companyname.nl so for example when I search for the user test#companyname.nl it finds the users in the site collection and it deletes the user.
But when I use an external email address for example test#gmail.com which is also in the sharepoint site collection as guest it cannot find it.
Why is that?
Per my test, to get external user, you should add #ext##companyname.nl at the end of the external email address.
For example:
Get-SPOUser -Site "https://yoursite" -LoginName "test_gmail.com#ext##contoso.onmicrosoft.com"

Upload files to SharePoint Online as System Account

How do I upload files and create folders to SharePoint Online through PowerShell while keeping their metadata (Modified By) as "System Account" instead of having the files using my account on the metadata?
I know I can change the metadata for files by doing this:
$user = Get-PnPUser -ErrorAction Stop | ? Email -eq $email
$newFile["Author"] = $user.id
$newFile["Editor"] = $user.id
$newFile["Modified"] = $currentFile.LastWriteTimeUtc
$newFile["Created"] = $currentFile.CreationTimeUtc
$newFile.Update()
But how about folders? If I use CSOM with PowerShell (see below) I can't find a way to modify the metadata properties for "Author" and "Editor":
$CSOM_credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($cred.UserName, $cred.Password)
$CSOM_context = New-Object Microsoft.SharePoint.Client.ClientContext("https://tenanturl.sharepoint.com")
$CSOM_context.Credentials = $CSOM_credentials
$ParentFolder = $CSOM_context.web.GetFolderByServerRelativeUrl("Samples")
$newFolder = $ParentFolder.Folders.Add("New Folder")
$ParentFolder.Context.ExecuteQuery()
$CSOM_context.Load($newFolder)
$CSOM_context.ExecuteQuery()
If I use the PnP PowerShell (Add-PnPFolder), I have the same problem I can't get a way to modify the same metadata
You can use "SHAREPOINT\System" to set Author and Editor to System Account.
$Id = 1024
$item = Get-PnPListItem -List "listNmae" -Id $Id
Set-PnPListItem -List "listNmae" -Identity $Id -Values #{"Author" = "SHAREPOINT\System";
"Editor" = "SHAREPOINT\System";
"Modified" = $item.FieldValues.Modified
}
Also you can get System Account user using
$sysaccount = Get-PnPUser | ? {$_.LoginName -eq "SHAREPOINT\System"}

Dynamic user credential generation with Powershell for Basic Auth Implementation

Requirement: Would like to have basic auth setup using custom php script.
Would like to :
Create user credentials dynamically
Create the cred php file with these credentials updated
Update the username & password to respective for Azure WebApp settings.
[ Note: FTPing the cred and auth files automatically if missing would be in upcoming post ]
Tools & Pre-requisites :
Azure Powershell 4.0+
Windows Powershell ISE
Knowledge of Storage Account ( Name, RG's )
Knowledge of WebApp for which backup is desired ( WebApp Name and RG )
Valid & Active Azure portal / AD login credentials
RESULT : On Azure Portal, The webapp in focus would have 'global_cred' variable key set with credentials generated stored as its value in application settings section as [username:password] format.
#######################
# Function to Generate dynamic 22char random string for password use
# Call custom function to write php constants for basic auth
Function writeFocusDomainCredFile{
param( $configObject, $hash, $farmprojectname )
#setting auth username:password
$configObject.authPasswordKey = (Get-RandomAlphanumericString -length 22 | Tee-Object -variable teeTime )
$hash['global_cred'] = [String]( $configObject.authUsernameKey + ':' + $configObject.authPasswordKey )
$prfilename = ( $configObject.ftpappdirectory + '\cred.php')
writeProjectBasicAuthCredOnNew -filename $prfilename -configObject $configObject
}
##########################
# Function to write the credentials to cred php file for basic auth use
# This file with other dependent files could be automatically ftp'd.
# Would share in another post
Function writeProjectBasicAuthCredOnNew{
param( $filename
,$configObject
)
writeDeployFileFiltersForDomain -ReportFileName $filename
Add-Content $filename ( "<?php" )
Add-Content $filename ("define('WPIZED_AUTH_USER', '" + $configObject.authUsernameKey + "');");
Add-Content $filename ("define('WPIZED_AUTH_PASS', '" + $configObject.authPasswordKey + "');");
}
###################################################################################################
# Configure Below as You prefer or desire #
$properties = #{
'ResourceName' = "AzureAppName";
'myResourceGroupName' = "{App Resource Group Name}";
'mySubscriptionName' = "{subscription name}";
'adminEmail' = "H.Bala#volunteering.com";
'ResourceGroupLocation' = "East US";
'authUsernameKey' = 'HBalaUsername'; #For this post, using fixed username as 'HBalaUsername'
'authPasswordKey' = '';
'PathFormatDate' = Get-Date -UFormat "%Y_%m_%d";
}
$configObject = New-Object –TypeName PSObject –Prop $properties
Write-Output $configObject
#Login cmdlet for active session
Login-AzureRmAccount
Get-AzureRmSubscription –SubscriptionName $configObject.mySubscriptionName | Select-AzureRmSubscription
(Get-AzureRmContext).Subscription
Select-AzureRMSubscription -SubscriptionName $configObject.mySubscriptionName
#Pull the Webapp details and configuration
$webApp = Get-AzureRMWebApp -ResourceGroupName $configObject.myResourceGroupName -Name $configObject.ResourceName
#Pull the Application Listing Environment / Configuration Variables
$appSettingList = $webApp.SiteConfig.AppSettings
$hash = #{}
ForEach ($kvp in $appSettingList) {
$hash[$kvp.Name] = $kvp.Value
}
writeFocusDomainCredFile -configObject $configObject -hash $hash
#[FTP Deploy Logic of this file and other basic auth or files shall cover in seperate topic ]
#[ Only setting the generated Credentials and saving to Application setting focused here ]
Set-AzureRMWebApp -ResourceGroupName $configObject.myResourceGroupName -Name $configObject.ResourceName -AppSettings $hash
Disclaimer: The intention is to share to another newbie who might find this helpful.

PowerShell to Export SharePoint Sites and Subsides with security groups

I'm attempting to come up with a powershell script that would allow me to export a list of sites and subsites and the permission groups there in to a CSV.
I'm familiar with using the cmdlts but not building whole scripts.
I'm able to use:
Get-SPOSiteGroup | Export-CSV C:\...
To export site groups to a CSV but it doesn't include the name of the sites they are in.
I also found a script online that would print out the sites and subsite in my site collection here:
https://sharepoint.stackexchange.com/questions/101176/powershell-to-list-all-sites-and-subsites-in-sharepoint-online
I'm not sure how to marry the information. I'm trying to export to a CSV a list of sites and subsites and the security groups there in.
I try to run:
get-sposite | Get-SPOSiteGroup **webdite**
And get this error message:
"Get-SPOSiteGroup : The input object cannot be bound to any parameters
for the command either because the command does not take pipeline
input or the input and its properties do not match any of the
parameters that take pipeline input"
I'm not sure how to get all of this to work together.
Get-SPOSiteGroup cmdlet accepts Site parameter, so site groups per every site collection within a tenant could be retrieved like this:
Connect-SPOService -Url $adminUrl
$sitesInfo = Get-SPOSite
#Retrieve and print all sites
foreach ($site in $sitesInfo) {
Write-Host 'Site collection:' $site.Url
Get-SPOSiteGroup -Site $site.Url
Write-Host '-----------------------------'
}
To retrieve in addition groups per every web site, the following script could be utilized:
$adminUrl = "https://<tenant>-admin.sharepoint.com"
$UserName = "<username>#<tenant>.onmicrosoft.com"
$Password = "--password goes here--"
$SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force
$creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $SecurePassword)
$pscreds = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $userName, $SecurePassword
Connect-SPOService -Url $adminUrl -Credential $pscreds
$sitesInfo = Get-SPOSite
foreach ($site in $sitesInfo) {
Write-Host 'Site collection:' $site.Url
#1. Retrieve and print site info
#Get-SPOSiteGroup -Site $site.Url
$AllWebs = Get-SPOWebs -Url $site.Url -Credential $creds
#2.Retrieve and print webs info (groups Title property in this case)
foreach ($web in $AllWebs) {
$web.Context.Load($web.RoleAssignments.Groups)
$web.Context.ExecuteQuery()
$web.RoleAssignments.Groups.GetEnumerator() | % { Write-Host $_.Title }
}
Write-Host '-----------------------------'
}
Key points:
to retrieve webs within a site collection Get-SPOWebs.ps1 is utilized
here
to get groups per web site Web.RoleAssignments.Groups is used