How to get result as json from schedule task - c#

I'm working on a PowerShell script which is calling C# method to enable/ disable a specific task.
Everything is working fine But I only want to get the Json result. Instead I'm getting the below result, like TaskName , TaskPath and other unwanted white space . I'm using return $properties | ConvertTo-Json in my PowerShell script to convert it but looks like when we do Enable-ScheduledTask PowerShell automatically added TaskPath and TaskName.
Can anyone suggestion how I can avoid TaskName/TaskPath and get only Json data in {}.

I got my solution. I had to use out-null to suppress the output that's it.
Enable-ScheduledTask -TaskPath $TaskPath -TaskName $taskName | Out-Null
I followed this : https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/out-null?view=powershell-7.1

Related

Storing multiline RSA Key in .NET core User Secrets (JSON)

The recommended way to store secrets (like API keys and passwords) during development of an ASP.NET core 3 application is to use user secrets. While this approach works nicely I do have a multiline string which contains an RSA key. The key is copied from a provided .pem file.
Is there any easy way to store the key in secrets.json?
The problem seems to be that json does not support multiline strings. Thus simply copying the key into the file does not work. Workarounds like using an array for the different lines of the key does not play nicely with the Configuration class and binding retrieved secrets to an Options-class.
I have figured out that once I convert the key into a single line string it works. However, the need for a separate tool to convert the key from multiline to single line, seems to me too complex.
By the way, I do need this for building a GitHub-App.
There's nothing stopping you from using a multi-line string with user secrets. You can pass one directly to dotnet user-secrets
For example, some Powershell using a here-string:
$multiVal = #"
Your
Multi-line
Text
"#
dotnet user-secrets set "YourKeyName" "$multiVal"
Or with embedded new-line character `n:
dotnet user-secrets "YourKeyName" "Your`nMulti-line`nValue"
Or you could read in an entire text-based file:
$fileName = "/path/to/file"
$multiVal = Get-Content $fileName -Raw
dotnet user-secrets set "YourKeyName" "$multiVal"
A JSON string property also allows "multi-line" text, just not in the way you're thinking. The literal characters \ and n together inside of a string property will be deserialized as a new-line. For example, the following JSON has a string property with a multi-line value:
{
"YourKeyName": "Your\nMulti-line\nText"
}
You can achieve this in a variety of ways, for example doing a manual find-and-replace or with tools like Notepad++. You could also use some Powershell once again:
$inputFile = "/path/to/file"
$multiVal = Get-Content $inputFile -Raw
$obj = [pscustomobject]#{
YourKeyName = $multiVal
}
$outputFile = "/path/to/secrets.json"
$obj | ConvertTo-Json -Depth 50 | Out-File -FilePath $outputFile
Edit: you mentioned one of the parameters is not working in the final example. It's possible you are somehow running an older version of powershell (pre 3.0). You can try this instead:
$inputFile = "/path/to/file"
# no -Raw flag
$multiVal = (Get-Content $inputFile | Out-String)
# or alternatively
$multiVal = [System.IO.File]::ReadAllText($inputFile)
$obj = [pscustomobject]#{
YourKeyName = $multiVal
}
$outputFile = "/path/to/secrets.json"
# use redirection instead of Out-File
($obj | ConvertTo-Json -Depth 50) > $outputFile
Now with respect to RSA keys, according to this answer and its comments while the RSA spec calls for line breaks within the base-64 encoded payload it's possible that implementations may allow non-conformance. This means that depending on how you're using it, you might be able to get away with stripping out the new-lines entirely. You'd have to try it out to know for sure.
Edit: It turns out that dotnet user-secrets has/had a known bug where values cannot have a leading -. It's fixed now but I think only for 5.0+. I found that a leading space works and I would think that the RSA provider shouldn't balk at that. The following should work:
dotnet user-secrets set "PKeyPowerShell" " $multiVal"

Running a powershell script from C# ends in error

I want to trigger a site design from powershell. It works here but when I try to run it through c# I get this error:
Cannot convert value "param" to type
"Microsoft.Online.SharePoint.PowerShell.SPOSiteDesignPipeBind". Error:
"Guid should contain 32 digits with 4 dashes
(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
I have tested several versions of the addScript string but none have worked. This is the code I'm trying to run. And it works fine in powershell.
PowerShellInstance.AddScript("Invoke-SPOSiteDesign -Identity param($paramSiteDesignId) -WebUrl param($paramUrl)");
PowerShellInstance.AddParameter("paramSiteDesignId", "176d2af0-1772-41b2-9ad7-acfceefc8851");
PowerShellInstance.AddParameter("paramUrl", "https://TenantName.sharepoint.com/sites/TMVTest13");
Any help pointing me in the right direction is very appreciated.
I found a way doing it directly in C# with Tenant.ApplySiteDesign. It works great see link for more info https://laurakokkarinen.com/the-ultimate-guide-to-sharepoint-site-designs-and-site-scripts/#applying-site-designs-programmatically
As you can see on learn.microsoft.com, AddParameter doesn't work by replacing placeholders the way you are doing it, but instead works by adding parameter/value pairs to the given command as parameters.
Your code probably results in something like this:
Invoke-SPOSiteDesign -Identity param($paramSiteDesignId) -WebUrl param($paramUrl) -paramSiteDesignId 176d2af0-1772-41b2-9ad7-acfceefc8851 -paramUrl https://TenantName.sharepoint.com/sites/TMVTest13
According to the documentation, this should do what you want:
PowerShellInstance = PowerShellInstance.AddScript("Invoke-SPOSiteDesign");
PowerShellInstance = PowerShellInstance.AddParameter("Identity", "176d2af0-1772-41b2-9ad7-acfceefc8851");
PowerShellInstance = PowerShellInstance.AddParameter("WebUrl", "https://TenantName.sharepoint.com/sites/TMVTest13");```

Retrieving GetExecutingRequests from PowerShell into c# object

I am trying to retrieve data from PowerShell into a c# object. The data I am looking for is returned from a PowerShell Invoke() of GetExecutingRequests on a remote web server. The issue I'm having is that I am not getting an error code, but the results from the Invoke() that I'm looking for are nowhere in the return data, or on the PowerShell object.
using (Runspace runspace = RunspaceFactory.CreateRunspace(cxn))
{
runspace.Open();
using (PowerShell ps = PowerShell.Create())
{
ps.Runspace = runspace;
string script = String.Format("Get-WmiObject
WorkerProcess -Namespace root\\WebAdministration -ComputerName {0} |
Invoke-WmiMethod -Name GetExecutingRequests", server);
ps.AddScript(script);
ps.AddParameter("OutputElement", new HttpRequest[0]);
var result = ps.Invoke();
}
}
This code executes, and returns a Collection with 29 items. However, none of them show the GetExecutingRequests results, and there is nothing relevant on the PowerShell object either.
I would like to get the output of GetExecutingRequests into a c# object, so I can do further processing. the PSDataStreams on the ps object also have no results.
Any help would be appreciated.
MORE INFO:
I was able to solve this with a change to the PowerShell script I was sending:
string script = String.Format("Get-WmiObject WorkerProcess -Namespace root\\WebAdministration -ComputerName {0} | Invoke-WmiMethod -Name GetExecutingRequests | %{{ $_ | Select-Object -ExpandProperty OutputElement }}", server);
I'm not quite sure if I can resolve the results directly, but I'd advise running below command to get some some more information on the object being returned. From there, you could look into how you'd handle that returning in C#.
Get-WmiObject -Class $(<scriptblock>) | get-member
Define the object types in C# & see if you're able to capture it in that way first.
If you're not able to make any progress with capturing the object type being returned in powershell yourself, it may be worth posting here to see if anyone else might be able to offer any insight/experience with workarounds for interfacing those objects types into C#.
If above really isn't possible, forcing the powershell to return everything from standard out would help find if it's writing anything meaningful that you can scrape/format in C#. I think the best way to do that in your quoted powershell command would be like so:
return $(Get-WmiObject
WorkerProcess -Namespace root\WebAdministration -ComputerName {0} |
Invoke-WmiMethod -Name GetExecutingRequests | *>&1)
This returns all 5+ standard outs from powershell to the return object (for those reading, see these docs on ps streams). Youshould definitely be able to capture the return in your results variable, but it can't hurt to make sure you're able to throw/capture errors from overflow.
Hope this helps to continue the digging!

how to set Set-VMFirmware on a single line in powershell

i am trying to make a small c# application to create my Hyper V VM's but i has got a problem with powershell in c# so i just running every powershell cmdlet using cmd.exe
but now i cant get how to set dvddrive as firstbootdevice in generation 2 virtual machine in just one line
for powershell script i use
$VMNAME= "SQL3"
$VMDVD = Get-VMDvdDrive -VMName $VMNAME
Set-VMFirmware -VMName $VMNAME -FirstBootDevice $VMDVD
but how can i do it in a single line
As a general rule, any variable reference can be substituted by a subexpression ($()):
Set-VMFirmware -VMName "SQL3" -FirstBootDevice $(Get-VMDvdDrive -VMName "SQL3")
If you have multiple DVD drives and know the ISO file
$DvdBootDrive = Get-VMDvdDrive -VMName $VmName | where {$_.Path -Like "*AutoInstall.iso*" }
Set-VMFirmware -VMName $VmName -FirstBootDevice $DvdBootDrive

Run powershell from c# most efficient way to create multiple mailcontacts in Exchange Online

I wish to create multiple mailcontacts (external Contacts) in the GAL in Microsoft Online by running Powershell command from C#. The code below works, but is very slow and takes about 15-20 min to run for 400 mailcontacts.
foreach(EmailAdressVM emailAddressVM in emailList.emailAddresses1)
{
//Create New MailContact.
Pipeline pplNewMailContact = runspace.CreatePipeline();
Command cmdNewMailContact = new Command("New-MailContact");
cmdNewMailContact.Parameters.Add("Name", emailAddressVM.sExternalEmailAddress);
cmdNewMailContact.Parameters.Add("Displayname", emailAddressVM.sFullName.Trim());
cmdNewMailContact.Parameters.Add("Lastname", emailAddressVM.sLastName.Trim());
cmdNewMailContact.Parameters.Add("Firstname", emailAddressVM.sFirstName.Trim());
cmdNewMailContact.Parameters.Add("ExternalEmailAddress", emailAddressVM.sExternalEmailAddress.Trim());
pplNewMailContact.Commands.Add(cmdNewMailContact);
pplNewMailContact.Invoke();
pplNewMailContact.Stop();
pplNewMailContact.Dispose();
}
I am guessing that this is slow since I create a new Pipeline for every new mailcontact that is added and there has to be a more eficient way of doing this since running...
import-csv <filename> | ForEach {
new-mailcontact -name $_.emailaddress -displayname $_.FullName -lastname $_.lastname -firstname $_.firstname -externalemailaddress $_.emailaddress -alias $_.alias
}
...is much faster.
I have found some references after many hours of searching the web that you can do something similar to using a CSV when running Powershell commands from C#, i.e. send a list (or array) of values to a command (in this case the "new-mailcontact" command). But, I have not found any good example of how to send more than one value to a command and I need to supply many values (for example: -name $.emailAddress -displayname $.FullName, etc.) to the "new-mailcontact" command.
Is it possible to send a list (or array) in a similar way as the "import-csv" command (when using regular powershell) and will this be faster, or is there an evan better way? Would I get better performance if I use Powershell 3 instead of 1 (as I am using now).
Please provide working sample code i C#!
Please note that I cannot save a CSV file to disk and the execute powershell from CMD since I do not have write access to disk and that I do not think that I can run an entire script remotely (since remote scripting probably is disabled on Exchange Online).
The biggest reason I would think is because for each address you are creating a new Powershell instance and you are not multithreaded.
You code looks something like this from above:
Foreach email address{
Declare a new Powershell process
Add attributes to call later
Start Powershell and pipe stuff in
Close Powershell instance
}
I think you would be better off creating the Powershell instance / pipe once and then sending each object into it. More along the lines of:
Create PS Pipe
Foreach email address{
PS.SendArguments(Email, Name, DN, etc.);
}
I am not in an environment to get something working or tested right now, so hopefully this gives you at least most of what you need...

Categories

Resources