I have written a C# Tool where i can enter script parameters with an GUI which is generated based on the parmeter definitions of the script.
Now i want to have a dropdown list which offers me a dynamically generated set of values. The informations for this dropdown list should come from the parameter definition of the script.
(In my case i want to select an existing AD OU by Listing all Child-Objects of the Base OU.)
One way to get a list of valid parameters is to use "ValidateSet" for Parameter definition. There is abway to get te ValidateSet from the Script an build the dropdown list. But ValidateSet is a static deffinition and i have to update the script each time the list should be changed.
A good way for dynamic validation is "ValidateScript". The script command would be something like Test-Path. This would work for validation, but for my GUI i would not be able to generate a list of valid values.
Maby i can dynamically generate a custom enum type and use it as parameter type. A dropdown list for enum types is already implemented for GUI.
But i think i's not a good idea and may not work to generate a enum type dynamically.
So, any other ideas for a list of valid values which is dynamically built?
I tried doing that with an enum once, and it got problematic due to differences in the valid character sets between enum values and AD names.
If you've wanting to keep the GUI separate from the script, you might investigate using AST to extract the parameter validation code from the script, and then run it outside the script to build your list.
You can use a dynamic parameter in you Powershell script.
A good example a of a ValidateSet parameter attribute dynamically generated from a scriptblock and added to a dynamic parameter can be found here :
http://blogs.technet.com/b/pstips/archive/2014/06/10/dynamic-validateset-in-a-dynamic-parameter.aspx
DynamicParam works well for PowerShell.exe.
But i have Problems to read the ValidateSet with C# Program.
Here is the Code i use:
InitialSessionState initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new string[] { #"C:\Users\kritzinger\OneDrive\Test-DynamicValidateSet.psm1" });
Runspace runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.Commands.AddCommand("Get-Command").AddArgument("Test-DynamicValidateSet").AddParameter("ArgumentList", "Path");
Collection<PSObject> get_Command = ps.Invoke();
PSObject command = get_Command[0];
Dictionary<String, ParameterMetadata> parameters = command.Properties["parameters"].Value as Dictionary<String, ParameterMetadata>;
At the last line i get the following Exception when i try to access the Value:
An unhandled exception of type
'System.Management.Automation.GetValueInvocationException' occurred in
System.Management.Automation.dll
Additional information: Exception getting "Parameters": "Cannot
retrieve the dynamic parameters for the cmdlet. The pipeline has been
stopped."
I get the same Exeption when i try to access the Value in VisualStudio Watch window.
With a static ValidateSet deffinition the c# code works well.
Related
I'm trying to save data back to the database using Datatable.
I have done this in C# but I can't figure out what the correct syntax in PowerShell to the following C# code
DataTable changeTable = table.GetChanges(DataRowState.Deleted);
I tried the following PS script
$dtAdded = $Global:dtCalendars.GetChanges([DataRowState.Added])
it gave me the following error:
Unable to find type [DataRowState.Added]
Can anyone shed some light on this matter?
Thank you
Enum values are technically static fields of their respective enum type.
For this reason, you'll need to use the static member operator (::) to reference them:
[Namespace.TypeName]::ValueName
or, in your case:
[System.Data.DataRowState]::Added
I have a bit of a weird issue. Working in C# script with SSIS I have developed a need to build a List based off Dynamic Data.
Background
To explain it, a script task is fired that has a variable API URL, this goes off and pulls a JSON string back and then throws it into a strongly typed list using the following code.
var listobject = get_APIData<ApplicationOneDataSet>(url)
The class that does this is long winded and not really needed in the context of this issue.
ApplicationOneDataSet is a strongly typed match to one of the possible JSON results returned by get_APIData.
Now I have a need to change ApplicationOneDataSet to ApplicationTwoDataSet dynamically based on which API URL I pass to the script.
So what I have done is send through a second variable to the script called class name which contains the string "ApplicationDataSetOne" or "ApplicationDataSetTwo" based on which context I call it under.
The Question
My question is how can I dynamically vary this line:
var listobject = get_APIData<ApplicationOneDataSet>(url)
With the string variable passed into the script.
My original thinking was something along the lines of this:
var ClassType = (string) Dts.Variables["AppClassName"].Value;
Type type = Type.GetType(ClassType);
var listobject = get_APIData<type>(url)
Though it doesn't seem to like that. Any tips would be great!
As long as there is exactly two types you can use and you know them at compile time, I would not look further than a simple if. It works, it's easy, everyone understands it.
You can do it totally dynamic at runtime, but that's a huge pain in the... where you don't want it to be. If you really want to go down that rabbit hole, you can find more information here.
I'm not sure I fully understood what you are trying to do, but how about writing an interface ApplicationDataSet and then making a list of it? This way your list is going to be able to contain both types of data.
I've written a bunch of classes that reach out to an API and get JSON. When compiled, I get nice commands like get-host, get-version, get-app, etc.
each cmdlet takes an argument like -host or -app.
I've got about 160 of these that I can write but I'm now looking to write a more generic cmdlet that can accept arbitrary parameters and values.
From what I can see, I can't declare parameters as such where i can issue
get-info -app "appname"
or
get-info -host "hostname"
or
get-info -version "5.5"
unless i declare all the parameters of which there could be hundreds. Also, if the parameter is not declared, it throws a nice error
Get-Info : A parameter cannot be found that matches parameter name 'host'.
Is there a way I can not declare any parameters and then parse the arguments manually or is there a something in c# to automatically parse the list of arguments and then assign them to variables named appropriately?
for example
get-info -host "hostname" -backup "backupid"
and the variables host and backup would be set automatically?
Accept your arbitrary parameters as a HashTable:
get-mydata #{ Host = "hostname"; version = "1.0" }
That is how most of the built-in cmdlets handle arbitrary KVPs.
In a powershell cmdlet that I am writing in C#, I need to get the name of the script that has called me.
I have derived my cmdlet class from PSCmdlet; there is a ton of information attached to this class at runtime, but I don't see where I can get the information I am looking for.
Is it possible to get the script name? If so, where does it live?
The automatic variable $MyInvocation should contain the name of the script in the InvocationName property.
Thanks, mjolinor... put me on the right path.
MyInvocation.InvocationName gives you the name of the command that the cmdlet was invoked under, but the calling script name is right close by...
I found what I was looking for here (from within the PSCmdlet-derived class):
var callingScript = MyInvocation.ScriptName;
It contains the full path of the script that called the cmdlet.
MongoDB for C#, I started following their tutorial but the compile error I get is on this line:
http://www.mongodb.org/display/DOCS/CSharp+Driver+Quickstart
var update = Update.Set("Name", "Harry");
saying
System.Windows.Forms.Control.Update()' is a 'method', which is not
valid in the given context.
The only difference I see is that they have used a Console Application but I created a C#WinForms applications and pasted their code inside a button click .
Update is simply ambiguous in the context you are using the call. You need to qualify the Update statement to include the namespace it is in.
var update = MongoDB.Driver.Builders.Update.Set("Name", "Harry");
This will probably get annoying, so you can also create an alias in your header.
using U = MongoDB.Driver.Builders.Update;
Then, you can change your statement to be this:
var update = U.Set("Name", "Harry");
I guess your c#WinForms contains an method called Update, which c# tries to access instead of the MongoDB one. Have you checked that you're imported everything needed and that your accessing the right Object?