How can I create a site using Pnp.core - sharepoint-online

I am trying to crate a site using . This is the code:
using PnP.Framework;
TeamSiteCollectionCreationInformation modernteamSiteInfo = new TeamSiteCollectionCreationInformation
{
Description = siteDescription,
DisplayName = siteTitle,
Alias = siteUrl.AbsoluteUri,
IsPublic = true,
Lcid = (uint)lcid,
};
var createModernSite = await clientContext.CreateSiteAsync(modernteamSiteInfo);
I am not really sure how to initiate the ClientContext because I think it should use https://tenant-admin.sharepoint.com. How can I get the ClientContext object?
I tried to use the same object from the current ClientContext, but I got this error message:
App-Only is currently not supported, unless you provide a Microsoft
Graph Access Token.. StackTrace: at
PnP.Framework.Sites.SiteCollection.CreateAsync(ClientContext
clientContext, TeamSiteCollectionCreationInformation
siteCollectionCreationInformation, Int32 delayAfterCreation, Int32
maxRetryCount, Int32 retryDelay, Boolean noWait, String
graphAccessToken, AzureEnvironment azureEnvironment) at
Microsoft.SharePoint.Client.ClientContextExtensions.CreateSiteAsync(ClientContext
clientContext, TeamSiteCollectionCreationInformation
siteCollectionCreationInformation)

You can Create Sharepoint site using pnp core sdk like this.Before that You need to authentication for your application.
var context = await _pnpContextFactory.CreateAsync("Default");
var teamSiteToCreate = new TeamSiteOptions("Demo", "Demo")
{
Description = "My site description",
Language = Language.English,
Owners = new string[] { "test#xyz.onmicrosoft.com" },
};
SiteCreationOptions siteCreationOptions = new SiteCreationOptions()
{
UsingApplicationPermissions = true
};
var create = await context.GetSiteCollectionManager().CreateSiteCollectionAsync(teamSiteToCreate, siteCreationOptions);
return Ok(Create.Uri);

Related

Get polygon from Azure Maps Search

I'm trying to use Azure.Maps.Search to give me a polygon for a result. For example, if I search for "Birmingham" I would like a result for that municipality with a collection of geopoints defining the boundary.
Is this possible?
var credential = new AzureKeyCredential("............");
var client = new MapsSearchClient(credential);
Response<SearchAddressResult> searchResult = await client.SearchAddressAsync(
query: "Birmingham",
options: new SearchAddressOptions
{
ExtendedPostalCodesFor=new SearchIndex[] { SearchIndex.PointAddresses },
CountryFilter = new string[] { "GB" },
Top = 1,
EntityType = GeographicEntity.Municipality
});
Yes, this is possible. The search address API will contain a DataSources.Geometries.ID value in the results that is the ID of the unique boundary for that result. You can take this ID and pass it into the GetPolygonsAsync API in the Azure.Maps.Search Nuget package.
using Azure;
using Azure.Maps.Search;
using Azure.Maps.Search.Models;
namespace AzureMapsTest
{
internal class Program
{
private const string MapsApiKey = "...........";
static async Task Main(string[] args)
{
var credential = new AzureKeyCredential(MapsApiKey);
var client = new MapsSearchClient(credential);
SearchAddressOptions singleSearchResultOptions = new SearchAddressOptions { Top = 1 };
Response<SearchAddressResult> searchResult =
await client.SearchAddressAsync(
"Ealing, London, England",
singleSearchResultOptions);
Response<PolygonResult> polygons =
await client.GetPolygonsAsync(new string[] { searchResult.Value.Results[0].DataSources.Geometry.Id });
Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(polygons.Value.Polygons));
}
}
}

Programmatically modify ACL to give application pool all permissions to application (IIS)

I have a process that creates an application and application pool using the Server Manager object in the Microsoft.Web.Administration namespace, the application pool is created first and then the application, assigning the newly created app pool to the application, code below.
protected TResult UseServerManagerWrapper<TResult>(Func<ServerManager, TResult> func)
{
using (var serverManager = new ServerManager())
{
return func(serverManager);
}
}
Application creation function
public void CreateApplication(String siteName, String parentApplicationName, String organisationName, String applicationName, String applicationPoolName)
{
UseServerManagerWrapper(serverManager =>
{
var site = serverManager.Sites[siteName];
var newApplication =
site.Applications.Add(
GetApplicationPath(parentApplicationName, organisationName, applicationName),
this.GetGeneratedApplicationPhysicalPath(siteName, parentApplicationName, organisationName, applicationName));
newApplication.ApplicationPoolName = applicationPoolName;
serverManager.CommitChanges();
return true;
});
}
and app pool creation.
public Boolean CreateApplicationPool(String applicationPoolName)
{
return UseServerManagerWrapper(serverManager =>
{
var appPool = serverManager.ApplicationPools.Add(applicationPoolName);
appPool.ManagedPipelineMode = ManagedPipelineMode.Integrated;
appPool.ManagedRuntimeVersion = "";
serverManager.CommitChanges();
return true;
});
}
This all works fine, the only problem I have is that I have to go into the application folder and manually assign permissions for the application pool.
I can't see anything in the ServerManager documentation that can help me and I can't figure out a way to use the Directory.SetAccessControl Method to give an application pool permissions. Is there anyway to do this in code?
Apologies if I'm using wrong terminology or anything, I'm new to publishing in general. Let me know if you need anymore info.
Ok, so after a lot of searching and some trial and error I've found the resolution and it's nothing to do with the ServerManager object. First of all to get this to work in ASP.NET Core 2.1 (1.x/2.x) I needed the System.IO.FileSystem.AccessControl Nuget and the Namespaces below.
using System.Security.AccessControl;
using System.Security.Principal;
These give the ability to modify the ACL of files and folders and then the CreateApplication function becomes the below.
public void CreateApplication(String siteName, String parentApplicationName, String organisationName, String applicationName, String applicationPoolName)
{
UseServerManagerWrapper(serverManager =>
{
var site = serverManager.Sites[siteName];
var generatedPath = this.GetGeneratedApplicationPhysicalPath(siteName, parentApplicationName, organisationName, applicationName);
var newApplication =
site.Applications.Add(
GetApplicationPath(parentApplicationName, organisationName, applicationName),
generatedPath);
newApplication.ApplicationPoolName = applicationPoolName;
var dInfo = new DirectoryInfo(generatedPath);
var acl = dInfo.GetAccessControl();
var acct = new NTAccount($"IIS APPPOOL\\{applicationPoolName}");
acl.AddAccessRule(new FileSystemAccessRule(acct, FileSystemRights.FullControl, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow));
dInfo.SetAccessControl(acl);
serverManager.CommitChanges();
return true;
});
}
The code between "newApplication.ApplicationPoolName = applicationPoolName" and "serverManager.CommitChanges()" gets the ACL from the newly generated directory giving the ability to modify it and reassign with a new FileSystemAccessRule.

How to add Owners to an Azure Active Directory Application

I am registering AAD Applications through the following code
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(serviceRoot, async () => await GetAppTokenAsync());
Application application = new Application()
{
AvailableToOtherTenants = false,
DisplayName = appName,
ErrorUrl = null,
GroupMembershipClaims = null,
Homepage = "http://"+appName,
IdentifierUris = new List<string>() { "https://"+appName },
KeyCredentials = new List<KeyCredential>(),
KnownClientApplications = new List<Guid>(),
LogoutUrl = null,
Oauth2AllowImplicitFlow = false,
Oauth2AllowUrlPathMatching = false,
Oauth2Permissions = new List<OAuth2Permission>(),
Oauth2RequirePostResponse = false,
// PasswordCredentials = new List<PasswordCredential>(),
PasswordCredentials = new List<PasswordCredential>(),
PublicClient = false,
ReplyUrls = new List<string>(),
// RequiredResourceAccess = new List<RequiredResourceAccess>(),
RequiredResourceAccess = new List<RequiredResourceAccess>(),
SamlMetadataUrl = null,
ExtensionProperties = new List<ExtensionProperty>(),
Manager = null,
ObjectType = "Application",
DeletionTimestamp = null,
CreatedOnBehalfOf = null,
CreatedObjects = new List<DirectoryObject>(),
DirectReports = new List<DirectoryObject>(),
Members = new List<DirectoryObject>(),
MemberOf = new List<DirectoryObject>(),
Owners = new List<DirectoryObject>(),
OwnedObjects = new List<DirectoryObject>(),
Policies = new List<DirectoryObject>()
};
I also have an object of type Microsoft.Azure.ActiveDirectory.GraphClient.User which contains all the information of a User that I want to add as owner of the application.
How can I do that?
The way I was trying that is by doing this
activeDirectoryClient.Applications.AddApplicationAsync(application).Wait();
ServicePrincipal newServicePrincpal = new ServicePrincipal();
if (application != null)
{
newServicePrincpal.DisplayName = application.DisplayName;
newServicePrincpal.AccountEnabled = true;
newServicePrincpal.AppId = application.AppId;
newServicePrincpal.Owners.Add(user);
try
{
activeDirectoryClient.ServicePrincipals.AddServicePrincipalAsync(newServicePrincpal).Wait();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
But when I navigate to the application manually in the Azure Portal, the only owner that appears is my own account and not also the other account I got in the user variable
Any idea how to add other owners to the application?
I can reproduce this issue too. The root cause for this issue is that the Azure AD Graph library doesn't provide the owner info when it try to create the service principal.
If you want to add the owner for the service principal, you can use code below after you creating the service principal:
var activeDirectoryClient = GraphHelper.CreateGraphClient();
var sp = (ServicePrincipal)activeDirectoryClient.ServicePrincipals.GetByObjectId("4af8365b-1b49-481c-8c47-7b3fab5611fc").ExecuteAsync().Result;
var user = new Users().GetUserByUserName(activeDirectoryClient, "user2#adfei.onmicrosoft.com").Result;
sp.Owners.Add(user);
sp.UpdateAsync();
And if you want to add the owner of application, here is the code for you reference:
var activeDirectoryClient = GraphHelper.CreateGraphClient();
var app = (Application)activeDirectoryClient.Applications.GetByObjectId("bd87934b-dd4f-446a-a025-7675d1b2464a").ExecuteAsync().Result;
var user = new Users().GetUserByUserName(activeDirectoryClient, "user2#adfei.onmicrosoft.com").Result;
app.Owners.Add(user);
app.UpdateAsync();
More detail about the difference between application and service principal please check this document.
And if you want the Graph client library to support adding the owner when creating the them, you can try to submit the feedback from here.
Update
public static ActiveDirectoryClient CreateGraphClient()
{
string accessToken = "";
string tenantId= "";
string graphResourceId = "https://graph.windows.net";
Uri servicePointUri = new Uri(graphResourceId);
Uri serviceRoot = new Uri(servicePointUri, tenantId);
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(serviceRoot, async () => await Task.FromResult(accessToken));
return activeDirectoryClient;
}
Add a runalbe code sample to add an owner for the service principal:
https://github.com/VitorX/AddServicePrincipalWithOwner
Update2
After you run the code sample in the above, you could capture the result using the Fiddler like below. And we can get the object id of service principal via the response of creating the service principal:
Then we can check the owners of principals via the REST like figure below:

Check admin privileges on cross-domain workstation C#

I am trying to check if a user is an admin on a particular machine.
I have the following code that works fine when the computer is on the same domain:
public bool CheckAdmins(string computerName)
{
var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
string branchnumber = computerName.Substring(0, 3);
bool admin = false;
if (logonUser.authenticate())
{
using (DirectoryEntry machine = new DirectoryEntry("WinNT://" + logonUser.Domain + "/" + computerName,logonUser.Domain + "\\" + logonUser.UserID,logonUser.Password))
{
//get local admin group
using (DirectoryEntry group = machine.Children.Find("Administrators","group"))
{
//get all members of local admin group
object members = group.Invoke("Members", null);
foreach (object member in (IEnumerable)members)
{
//get account name
string accountName = new DirectoryEntry(member).Name;
bool isAdmin = principal.IsInRole(accountName);
if (isAdmin == true) { admin = true; }
}
}
}
}
return admin;
}
However, across domain, this simply comes back with 'network path not found'.
I have been experimenting with LDAP but not getting too far. I have tried a number of methods and ideally need an example. This is what I am using currently:
String strPath = "LDAP://172.24.242.51/CN=258TP520,OU=258,DC=net,DC=test,DC=co,DC=uk";
DirectoryEntry myDE = new DirectoryEntry(strPath, "testdom\user", "password");
List<string> memberof = new List<string>();
foreach (object oMember in myDE.Properties["memberOf"])
{
memberof.Add(oMember.ToString());
}
However myDE.properties doesn't seem to contain anything. All help appreciated!
Thanks
I needed to append the FQDN to the computername, like so
using (DirectoryEntry machine = new DirectoryEntry("WinNT://" + computerName + ".net.test.co.uk",logonUser.Domain + "\\" + logonUser.UserID,logonUser.Password))
This fixed my issue.

Client Object Model Sharepoint How to get the Instance ID

So In my sharepoint site contents page i have an application.
Can anyone tell me how to get the instance id of it.
so that i can invoke the link :
http://testingwebcompany.sharepoint.com/_layouts/15/appredirect.aspx?instance_id={ <>}
I can't seem to get it when I'm searching ClientContext.Web.Lists.
Thanks
I got it, it seems that the instance id is auto generated. the real url of the application is located when looping through ClientContext.Web.Webs[].Title == "Application Name" then retrieving the ClientContext.Web.Webs[].Url.
The following example demonstrates how to retrieve an App by its title
public static class WebExtensions
{
public static IEnumerable<AppInstance> GetAppInstanceByTitle(this Web web,string appTitle)
{
var ctx = web.Context;
var apps = AppCatalog.GetAppInstances(ctx, web);
var result = ctx.LoadQuery(apps.Where(a => a.Title == appTitle));
return result;
}
}
Usage
using (var ctx = new ClientContext(webUri))
{
var appTitle = "\"Napa\" Office 365 Development Tools";
var result = ctx.Web.GetAppInstanceByTitle(appTitle);
ctx.ExecuteQuery();
var app = result.FirstOrDefault();
if (app != null) Console.WriteLine(app.Id); // print App Instance Id
}

Resources