C# Modify Security Scopes on existing Task Sequence - c#

I can modify all properties in SMS_TaskSequencePackage except SecuredScopeNames
public void setSecurityScopes(WqlConnectionManager connection, string packageID, string newSecurityScopes)
{
try
{
// Take the new security scopes (Security Scopes are stored in strings' array)
string[] newScopes = { newSecurityScopes };
// Get the instance with WQLConnectionManager
IResultObject securityScopesToChange = connection.GetInstance(#"SMS_TaskSequencePackage.PackageID='" + packageID + "'");
securityScopesToChange["SecuredScopeNames"].StringArrayValue = newScopes;
// Apply the new Security Scopes
securityScopesToChange.Put();
}
catch (SmsException ex)
{
MessageBox.Show("Failed to set TS Security Scopes. Error: " + ex.Message);
}
}
I don't understand why my StringArray isn't stored.
With this method, I can change others properties in string format but not this one.
Thanks to help me.

The property SecuredScopeNames seems to be a read only parameter (as can be seen in the documentation for SMS_Package - although it seems to be a bit outdated) that has to be modified via an additonal class SMS_SecuredCategoryMembership.
You can add a scope like this (see more details here):
// Create a new instance of the scope assignment.
IResultObject assignment = sccmConnection.CreateInstance("SMS_SecuredCategoryMembership");
// Configure the assignment
assignment.Properties["CategoryID"].StringValue = scopeId; // CategoryID from SMS_SecuredCategory
assignment.Properties["ObjectKey"].StringValue = objectKey; // PackageID
assignment.Properties["ObjectTypeID"].IntegerValue = objectTypeId; // can get it from SMS_ObjectName with objectkey (probably fixed values)
// Commit the assignment
assignment.Put();
The CategoryID or ScopeId can be taken from SMS_SecuredCategory
The ObjectKey is is the Package Id of your Package or TaskSequence Package
The ObjectTypeId is probably always 20 for TaskSequencePackages but can be queried from SMS_ObjectName with the PackageID as ObjectKey (very sloq query if done without where clause because it has all objects of all types that are stored in the sccm db)
This is however not enough for a real modification because it will keep all existing scopes so if you want to get rid of default (or another one) you will also have to call a remove (more detail here):
// Find the existing scope assignement that matches our parameters.
IResultObject assignment = sccmConnection.GetInstance("SMS_SecuredCategoryMembership.CategoryID='" + scopeId + "',ObjectKey='" + objectKey + "',ObjectTypeID=" + objectTypeId.ToString());
// Make sure we found the scope.
if(assignment == null)
throw new Exception("Unable to find matching scope, object, and object type.");
else
assignment.Delete();
With the same three parameters (Default seems to have the reserved scopeID SMS00UNA but it is probably still best to get the details from SMS_SecuredCategory).

Related

Empty value in attribute | Plugin CRM C#

I change only 1 field in the interface - "telephone1", and leave the second one unchanged, in the end I want field 3 to contain both 1 changed field and 2 field unchanged, but for some reason it is empty, although it contains values, it also works and vice versa. "InputParametres" as I understand it is a bad idea, but what other options are there?
https://i.imgur.com/7G3rRVK.png
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
try
{
var createReq = new CreateRequest() { Parameters = context.InputParameters };
var res = createReq.Target; // Has type Entity
// Получить целевой объект из входных параметров
Entity entityInput = (Entity)context.InputParameters["Target"];
// entityInput.Attributes["telephone3"] = entityInput. + ";" + entityInput.Attributes["telephone2"];
entityInput.Attributes["telephone3"] = res.GetAttributeValue<string>("telephone1") + ";" + res.GetAttributeValue<string>("telephone2");
// service.Update(entityInput);
}
catch (Exception ex)
{
throw new Exception($"Error in update telephone3 - {ex.Message}");
}
}
else
{
throw new InvalidPluginExecutionException($"Плагин {nameof(Class1)} был зарегистрирован неправильно");
}
Target will have only changed attributes and it’s values. If you need the values from unchanged attributes (fields) you have to use PreImage to consume them.
You can register PreImage in Plug-in registration tool similar to steps, filtering attributes, etc.
Read more

Parse & Unity 3D : Update an existing row

Using the example code from the Unity Developer Guide | Parse
# https://www.parse.com/docs/unity_guide#objects-updating
// Create the object.
var gameScore = new ParseObject("GameScore")
{
{ "score", 1337 },
{ "playerName", "Sean Plott" },
{ "cheatMode", false },
{ "skills", new List<string> { "pwnage", "flying" } },
};
gameScore.SaveAsync().ContinueWith(t =>
{
// Now let's update it with some new data. In this case, only cheatMode
// and score will get sent to the cloud. playerName hasn't changed.
gameScore["cheatMode"] = true;
It just adds a new row and leaves the original row unchanged.
I guess i'm thinking Parse would do something "SQL like" such as UPDATE where primaryKey = 123.
Searching for an answer i found this code #
https://parse.com/questions/updating-a-field-without-retrieving-the-object-first, but there was no example in C#. All attempts to port this to C# result in multiple syntax errors.
UnityScript:
// Create a pointer to an object of class Point with id dlkj83d
var Point = Parse.Object.extend("Point");
var point = new Point();
point.id = "dlkj83d";
// Set a new value on quantity
point.set("quantity", 6);
// Save
point.save(null, {
success: function(point) {
// Saved successfully.
},
error: function(point, error) {
// The save failed.
// error is a Parse.Error with an error code and description.
}
});
Does Parse have some way to update a row that already exists using C#? And where is it in the docs? And how can their own example be so useless?
One of the posts related to my question stated "retrieve the object, then write it back with the changes" and i had not the faintest idea how to execute the stated objective (especially after the epic fail of Parse Documentation's example code)
Here is what i have been able to figure out and make work:
var query = new ParseQuery<ParseObject>("Tokens")
.WhereEqualTo ("objectId", "XC18riofu9");
query.FindAsync().ContinueWith(t =>
{
var tokens = t.Result;
IEnumerator<ParseObject> enumerator = tokens.GetEnumerator();
enumerator.MoveNext();
var token = enumerator.Current;
token["power"] = 20;
return token.SaveAsync();
}).Unwrap().ContinueWith(t =>
{
// Everything is done!
//Debug.Log("Token has been updated!");
});
the first part retrieves the object with the stated objectId, the second part sets the fields in the object. The third part reports all is well with the operation.
it's a monkey see, monkey do understanding at this point being that i do not understand the finer points in the code.
the code can be tested by creating a class named "Tokens". in that class create a tokenName field and a power field. make a few rows with Fire, water, mud as the tokenNames. Replace the objectId in the .WhereEqualTo clause with a valid objectId or any other search parameters you like. Execute the code and observe the changes in the Parse Data Browser.
For extra credit create the class required to implement the example code from the Chaining Tasks Together section of Parse's Documentation.
https://www.parse.com/docs/unity_guide#tasks-chaining

MongoDB: update only specific fields

I am trying to update a row in a (typed) MongoDB collection with the C# driver. When handling data of that particular collection of type MongoCollection<User>, I tend to avoid retrieving sensitive data from the collection (salt, password hash, etc.)
Now I am trying to update a User instance. However, I never actually retrieved sensitive data in the first place, so I guess this data would be default(byte[]) in the retrieved model instance (as far as I can tell) before I apply modifications and submit the new data to the collection.
Maybe I am overseeing something trivial in the MongoDB C# driver how I can use MongoCollection<T>.Save(T item) without updating specific properties such as User.PasswordHash or User.PasswordSalt? Should I retrieve the full record first, update "safe" properties there, and write it back? Or is there a fancy option to exclude certain fields from the update?
Thanks in advance
Save(someValue) is for the case where you want the resulting record to be or become the full object (someValue) you passed in.
You can use
var query = Query.EQ("_id","123");
var sortBy = SortBy.Null;
var update = Update.Inc("LoginCount",1).Set("LastLogin",DateTime.UtcNow); // some update, you can chain a series of update commands here
MongoCollection<User>.FindAndModify(query,sortby,update);
method.
Using FindAndModify you can specify exactly which fields in an existing record to change and leave the rest alone.
You can see an example here.
The only thing you need from the existing record would be its _id, the 2 secret fields need not be loaded or ever mapped back into your POCO object.
It´s possible to add more criterias in the Where-statement. Like this:
var db = ReferenceTreeDb.Database;
var packageCol = db.GetCollection<Package>("dotnetpackage");
var filter = Builders<Package>.Filter.Where(_ => _.packageName == packageItem.PackageName.ToLower() && _.isLatestVersion);
var update = Builders<Package>.Update.Set(_ => _.isLatestVersion, false);
var options = new FindOneAndUpdateOptions<Package>();
packageCol.FindOneAndUpdate(filter, update, options);
Had the same problem and since I wanted to have 1 generic method for all types and didn't want to create my own implementation using Reflection, I end up with the following generic solution (simplified to show all in one method):
Task<bool> Update(string Id, T item)
{
var serializerSettings = new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore
};
var bson = new BsonDocument() { { "$set", BsonDocument.Parse(JsonConvert.SerializeObject(item, serializerSettings)) } };
await database.GetCollection<T>(collectionName).UpdateOneAsync(Builders<T>.Filter.Eq("Id", Id), bson);
}
Notes:
Make sure all fields that must not update are set to default value.
If you need to set field to default value, you need to either use DefaultValueHandling.Include, or write custom method for that update
When performance matters, write custom update methods using Builders<T>.Update
P.S.: It's obviously should have been implemented by MongoDB .Net Driver, however I couldn't find it anywhere in the docs, maybe I just looked the wrong way.
Well there are many ways to updated value in mongodb.
Below is one of the simplest way I choose to update a field value in mongodb collection.
public string UpdateData()
{
string data = string.Empty;
string param= "{$set: { name:'Developerrr New' } }";
string filter= "{ 'name' : 'Developerrr '}";
try
{
//******get connections values from web.config file*****
var connectionString = ConfigurationManager.AppSettings["connectionString"];
var databseName = ConfigurationManager.AppSettings["database"];
var tableName = ConfigurationManager.AppSettings["table"];
//******Connect to mongodb**********
var client = new MongoClient(connectionString);
var dataBases = client.GetDatabase(databseName);
var dataCollection = dataBases.GetCollection<BsonDocument>(tableName);
//****** convert filter and updating value to BsonDocument*******
BsonDocument filterDoc = BsonDocument.Parse(filter);
BsonDocument document = BsonDocument.Parse(param);
//********Update value using UpdateOne method*****
dataCollection.UpdateOne(filterDoc, document);
data = "Success";
}
catch (Exception err)
{
data = "Failed - " + err;
}
return data;
}
Hoping this will help you :)

RavenDB query Store

Just got to grips with RavenDB - which is awesome - however I am getting a little stuck with a query. I running a foreach and using the Store() method to save some data and once complete using the SaveChanges() method.
Once I have stored this information, I need to reference this information to store some additional information (don't worry if you slightly confused at this point the code will make it clear!) but when I reference the information there is no information to be found.
So, first of all I add some data:
foreach (var development in developments)
{
Console.WriteLine(" - Working on Developmnent ID: " + development.devID);
Session.Store(new Domain.Development
{
Id = "D" + Convert.ToString(development.devID),
Name = development.devName,
Street = development.devStreet,
Town = development.devTown,
County = development.devCounty,
Postcode = development.devPostcode,
Country = development.devCounty,
Description = "",
Longitude = GeoData.Longitude(development.devPostcode),
Latitude = GeoData.Latitude(development.devPostcode)
});
}
Now, because of the limitations with the number of queries that can be ran within the session, I retrieve the whole dataset and store in memory:
var developmentList = from d in Session.Query<Domain.Development>()
select d;
Now when I add a break point at the end of this there is no data to be found. Do I need to create another session to retrieve this data?
I have also tried
var developmentList = Session.Query<Domain.Development>();
Here is the code where I create the session too:
internal static DocumentStore Store;
internal static IDocumentSession Session { get; set; }
internal <<Constructor>> ...
Store = new DocumentStore { ConnectionStringName = "RavenDB" };
Store.Initialize();
IndexCreation.CreateIndexes(Assembly.GetCallingAssembly(), Store);
Session = Store.OpenSession();
It's not recommended you do this. Goes back to safe by default concept of RavenDB.
If you just stored those values, why do you need to save them to the database and the re-load them from the database? Just use the in memory collection and that would be it.

Error creating an Entity in CRM 2011 - CRM doesn't like OptionSetValue

I'm trying to create an entity in CRM 2011 (not an out of the box kind, but what in CRM 4 would have been called a DynamicEntity... one with my custom attributes). The code below gives me this error and I'm not sure why. This exact same code works if I remove the new_accounttype attribute and try to use another custom attribute.
CRM seems to have taken issue with the "OptionSetValue" being set as the value for that key value pair. new_accounttype is a picklist (or OptionSet in CRM 2011) and that value of 100000003 was pulled from the front end so it's a valid value.
Error: A validation error occurred. The value of 'new_accounttype' on
record of type 'account' is outside the valid range.
What am I doing wrong?
public static void CreateAccount(string accountName, string accountType)
{
//Create properties
KeyValuePairOfstringanyType[] attributes = new KeyValuePairOfstringanyType[2];
attributes[0] = new KeyValuePairOfstringanyType() { key = "name", value = accountName ?? "" };
attributes[1] = new KeyValuePairOfstringanyType() { key = "new_accounttype", value = new OptionSetValue() { Value = 100000003 } };
////Create DynamicEntity
Entity accountToCreate = new Entity();
accountToCreate.LogicalName = "account";
accountToCreate.Attributes = attributes;
try
{
service.Create(accountToCreate);
}
}
I agree that what you have should work fine. This can only mean that the value isn't published or is incorrect. As #glosrob mentions, check that the changes are actually published. Confirm these values by looking at the published form and seeing if your new value is present (and perhaps double check by using IE Developer Tools - hit F12 - and confirm that the value in the select>option object in the HTML contains the integer you expect).
As an aside, your code looks more complex than necessary (IMHO!). I believe this is easier to read an no less efficient:
Try this:
public static void CreateAccount(string accountName, string accountType)
{
////Create DynamicEntity
Entity accountToCreate = new Entity();
accountToCreate.LogicalName = "account";
accountToCreate.Attributes = attributes;
//Append properties
accountToCreate.Attributes.Add("name", accountName ?? "" );
accountToCreate.Attributes.Add("new_accounttype", new OptionSetValue(100000003);
try
{
service.Create(accountToCreate);
}
}
Give this a shot: key = "new_accounttype", value = new OptionSetValue(100000003)

Categories