I would like my program to be able to start and stop an azure vm. I managed to write a powershell script that starts and stops the VM but I would like to do it from my C# directly (that is, without calling the powershell script. I did not manage to find the way to do this translation and I will appreciate the help.
Here is the PowerShell script
function stopvm($resourcegroup,$vmname)
{
Stop-AzureRmVM -ResourceGroup $resourcegroup -Name $vmname
}
function startvm($resourcegroup,$vmname)
{
Start-AzureRmVM -ResourceGroup $resourcegroup -Name $vmname
}
################################################################
# Please Change These Variables to Suit Your Environment
#
$subscriptionname = "Subscription Name"
$resourcegroup = "Resource Group Name"
$vmname = "VM name"
################################################################
Login-AzureRmAccount -SubscriptionName $subscriptionname
write-host "Choose the options to Start and Stop your Azure VMS"
write-host "1. Start VM"
write-host "2. Stop VM"
$answer = read-host "Please Select Your Choice"
Switch($answer)
{
1{ StartVM $resourcegroup $vmname}
2{ StopVM $resourcegroup $vmname}
}
The main obstacle is to find the C# translation of Login-AzureRm
Thank you in advance
Here is the code that you can use to start your VM:
AuthenticationContext context = new AuthenticationContext("[OAUTH2 AUTHORIZATION ENDPOINT]");
UserCredential userCred = new UserCredential("[CO-ADMINISTRATOR E-MAIL]", "[CO-ADMINISTRATOR PASSWORD]");
AuthenticationResult result = context.AcquireTokenAsync("https://management.core.windows.net/", "[APPLICATION CLIENT ID]", userCred).Result;
TokenCloudCredentials credentials = new TokenCloudCredentials("[SUBSCRIPTION ID]", result.AccessToken);
using (ComputeManagementClient computeClient = new ComputeManagementClient(credentials))
{
computeClient.VirtualMachines.Start("[CLOUD SERVICE NAME]", "[DEPLOYMENT NAME]", "[VM NAME]");
}
EDIT:
This requires you to install the following NuGet packages:
Microsoft.WindowsAzure.Management.Compute
Microsoft.IdentityModel.Clients.ActiveDirectory
Related
I've spent last two days searching for answers and still have no idea as to where to begin my investigation.
I've got both a C# .net standard library as well as a powershell script that allows me to fetch data from a REST api. The powershell script looks like this.
$cert = Get-ChildItem -Path Cert:\LocalMachine\My\<Thumbprint>
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri “https://some.url.to.get.my.data” -Method Get -Certificate $cert
Both, this script and C# code mentioned here was working for me until recently (not running as administrator). Now it is giving me trouble and returning an error message:
Invoke-WebRequest : The request was aborted: Could not create SSL/TLS secure channel.
At line:3 char:1
+ Invoke-WebRequest -Uri “https://some.url.to.get.my.data ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
Same problem exist in my C# application. I've set
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
I set the X509 Certificate (not shown here) and make a call using
HttpClient.GetStringAsync(string requestUri).Result;
The call hangs and never returns.
The interesting thing here is that both the Powershell and C# code works fine if I'm running the Powershell or Visual Studio in Administrator mode.
In my frustration, I tried looking at the calls between my client and the server via wireshark. By comparing the call pattern between working and non working call, I can tell that the handshaking appears to be working correctly. At least initially until just before the server is suppose to send the data. The client for some reason sends a [FIN, ACK] call to the server and the connection terminates.
I welcome any suggestion you might have.
Thanks.
I had a similair issue with another .NET Application, please verify if below registry keys have been set, also note that a specific patch may be reqruired based on your .NET and or OperatingSystem version for more information see: https://learn.microsoft.com/en-us/dotnet/framework/network-programming/tls
$RegistryKeys = #(
#{
Path = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319"
Name = "SystemDefaultTlsVersions"
Value = "1"
PropertyType = "DWord"
}
#{
Path = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319"
Name = "SchUseStrongCrypto"
Value = "1"
PropertyType = "DWord"
}
#{
Path = "HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319"
Name = "SystemDefaultTlsVersions"
Value = "1"
PropertyType = "DWord"
}
#{
Path = "HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319"
Name = "SchUseStrongCrypto"
Value = "1"
PropertyType = "DWord"
}
#{
Path = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server"
Name = "Enabled"
Value = "1"
PropertyType = "DWord"
}
#{
Path = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server"
Name = "DisabledByDefault"
Value = "0"
PropertyType = "DWord"
}
#{
Path = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client"
Name = "Enabled"
Value = "1"
PropertyType = "DWord"
}
#{
Path = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client"
Name = "DisabledByDefault"
Value = "0"
PropertyType = "DWord"
}
)
Some code to test this with:
$ErrorActionPreference = 'Stop'
$VerbosePreference = 'Continue'
Foreach ($RegistryKey in $RegistryKeys) {
# * Validate Path
# This code will check if the Path exists.
Write-Verbose "Processing '$($RegistryKey.Path)' '$($RegistryKey.Name)'"
Write-Verbose "Validating if path '$($RegistryKey.Path)' exists"
If (-Not (Test-Path -Path $RegistryKey.Path)) {
Write-Warning "Path '$($RegistryKey.Path)' doest not exist"
Continue
}
Write-Verbose "Path '$($RegistryKey.Path)' exists"
# * Validate Property
# This code will check if the property exists.
Write-Verbose "Reading properties for'$($RegistryKey.Path)'"
$Properties = Get-ItemProperty -Path $RegistryKey.Path
Write-Verbose "Validating if property '$($RegistryKey.Name)' exists"
If (-Not ($RegistryKey.Name -in ($Properties | Get-Member).Name)) {
Write-Warning "Property '$($RegistryKey.Name)' doest not exist"
Continue
}
Write-Verbose "Property '$($RegistryKey.Name)' exists"
# * Validate Property value
# This code will check if the configured value is correct.
Write-Verbose "Validating if property value is set to '$($RegistryKey.Value)'"
If (-Not ((Get-ItemProperty -Path $RegistryKey.Path -Name $RegistryKey.Name)."$($RegistryKey.Name)" -eq $RegistryKey.Value)) {
Write-Warning "Property value is incorrect for '$($RegistryKey.Path)' '$($RegistryKey.Name)'"
Continue
}
Write-Verbose "Property value is correct for '$($RegistryKey.Path)' '$($RegistryKey.Name)'"
}
In my case, it turns out that the problem indeed was fetching the certificate. I initially had the certificate in the Current User account during development which worked without any issue. Once I had moved the certificate under the Local Machine account, I started having this issue.
The solution was to give my user account permission to access the specific certificate via Certificate Manager > Right click on the Certificate > All Tasks > Manage Private Keys. Then add my user account to the list.
I'm using the .NET client libraries for VSTS/TFS (https://learn.microsoft.com/en-us/vsts/integrate/concepts/dotnet-client-libraries?view=vsts) to retrieve a list of tasks for all Build Definitions for all Team Projects. I'm using the v16.139.0-preview version of the NuGet package Microsoft.TeamFoundation.ExtendedClient (I need to because I need to retrieve Release Definition workflow as well for which you need Microsoft.VisualStudio.Services.Release.Client which has a dependency requirement for the ExtendedClient). The server (on-prem) is a TFS 2017.2. In no way I'm able to retrieve the tasks/phases/process. This is my code:
VssConnection connection = new VssConnection(new Uri("http://tfsserver:8080/tfs/defaultcollection"), new VssClientCredentials());
ProjectHttpClient projectClient = connection.GetClient<ProjectHttpClient>();
IEnumerable<TeamProjectReference> projects = projectClient.GetProjects().Result;
BuildHttpClient buildClient = connection.GetClient<BuildHttpClient>();
foreach (var project in projects)
{
IPagedList<BuildDefinition> buildDefinitions = buildClient.GetFullDefinitionsAsync2(project: project.Name, name: null).Result;
foreach (BuildDefinition buildDefinition in buildDefinitions)
{
// get the tasks
}
}
I have tried to re-retrieve the Build Definition using buildClient.GetDefinitionAsync without additional effect
The "Steps" property (which is going to be deprecated) is always null
The "Process" property is empty
There is no "phases" property available (which seems logical looking at the options to have multiple phases in a Build Definition
There is a contract available for BuildDefinitionStep: https://learn.microsoft.com/en-us/vsts/extend/reference/client/api/tfs/build/contracts/builddefinitionstep?view=vsts
The REST API documentation doesn't have a property called "Step": https://learn.microsoft.com/en-us/rest/api/vsts/build/definitions/get?view=vsts-rest-4.1#builddefinition
Does anyone have an idea on how to solve this?
Just try below C# sample using .NET client libraries, test on TFS 2017.3 and VSTS, both work. (No TFS 2017.2 on my side, If I remember correctly, TFS 2017.2 has the similar build process with TFS 2015, It has no the "Process" and "phases" attribute. )
using System;
using Microsoft.TeamFoundation.Build.WebApi;
using Microsoft.VisualStudio.Services.Client;
using Microsoft.VisualStudio.Services.Common;
namespace RetrieveTaskList
{
class Program
{
static void Main(string[] args)
{
//For TFS :
var tfsUrl = "http://ws-tfs2017:8080/tfs/DefaultCollection";
var buildClient = new BuildHttpClient(new Uri(tfsUrl), new VssAadCredential());
//For VSTS:
//var tfsUrl = "https://{account}.visualstudio.com";
//var buildClient = new BuildHttpClient(new Uri(tfsUrl), new VssBasicCredential(string.Empty, "PAT here"));
var definitions = buildClient.GetFullDefinitionsAsync(project: "ScrumProject");
foreach (var definition in definitions.Result)
{
Console.WriteLine(string.Format("\n {0} - {1}:", definition.Id, definition.Name));
// Get BuildDefinitionStep to array, each of which has a task property that contains things like the name of the task and the inputs.
var tasks = definition.Steps.ToArray();
//Get each step/task from the array
foreach (var task in tasks)
{
Console.WriteLine(task.DisplayName);
}
}
Console.ReadLine();
}
}
}
You can also use the REST API to retrieve the list of tasks from a build definition.
PowerShell for example:
Param(
[string]$baseurl = "http://server:8080/tfs/DefaultCollection",
[string]$projectName = "ProjectName",
[string]$buildDefinitionID = "26",
[string]$user = "domain\user",
[string]$token = "password"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$uri = "$baseurl/$($projectName)/_apis/build/definitions/$buildDefinitionID"
Write-Host $uri
$result = (Invoke-RestMethod -Uri $uri -Method Get -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)})
$tasks = $result.process.phases.steps.displayName
foreach ($task in $tasks)
{
write-host $task
}
You can also try the REST Client, please reference this thread : Retrieve VSTS/TFS Build task name list
A bit late to the party, but if you're wanting to iterate over the Build tasks using the AzDO .NET Client library you need to cast the Process to a DesignerProcess/DockerProcess/YamlProcess.
var buildDefinitions = await _buildClient.GetFullDefinitionsAsync(project.Id);
foreach (var buildDefinition in buildDefinitions)
{
if (buildDefinition.Process != null && buildDefinition.Process is Microsoft.TeamFoundation.Build.WebApi.DesignerProcess designerProcess)
{
foreach (var phase in designerProcess.Phases)
foreach (var step in phase.Steps)
Console.WriteLine($"taskname={step.DisplayName}");
break;//lets exit the loop early
}
}
Demo repo, https://github.com/f2calv/azdo-api-net-client-issue
With the help of #Andy I was able to solve the problem. I used Fiddler call the REST Api (http://server:8080/tfs/DefaultCollection/MyProject/_apis/build/definitions/1) and read the JSON response. I discovered that the "build" property contains the collection of tasks. I fixed the PowerShell script provided by #Andy:
Param(
[string]$baseurl = "http://server:8080/tfs/DefaultCollection",
[string]$projectName = "MyProject",
[string]$buildDefinitionID = "530",
[string]$user = "domain\user",
[string]$token = "PersonalAccessToken"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$uri = "$baseurl/$($projectName)/_apis/build/definitions/$buildDefinitionID"
Write-Host $uri
$result = (Invoke-RestMethod -Uri $uri -Method Get -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)})
foreach ($task in $result.build)
{
Write-Host $task.displayName
}
If you implement a custom PowerShell Host with System.Management.Automation (SMA), all of the automatic variables are avaialable, except it seems that $PROFILE is empty. How would one go about recreating it?
Is it always in UserProfile + \Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1? Or do I need to be worried about it being in other places?
To clarify, I only care about CurrentUserCurrentHost profile.
Details
Given this PowerShell script:
Write-Output "_Profiles_"
Write-Output "CurrentUserCurrentHost = '$($Profile.CurrentUserCurrentHost)'"
Write-Output "CurrentUserAllHosts = '$($Profile.CurrentUserAllHosts)'"
Write-Output "AllUsersCurrentHost = '$($Profile.AllUsersCurrentHost)'"
Write-Output "AllUsersAllHosts = '$($Profile.AllUsersAllHosts)'"
Running it against system PowerShell has the following output:
_Profiles_
CurrentUserCurrentHost = 'C:\Users\rob\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1'
CurrentUserAllHosts = 'C:\User\rob\Documents\WindowsPowerShell\profile.ps1'
AllUsersCurrentHost = 'C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.PowerShell_profile.ps1'
AllUsersAllHosts = 'C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1'
Running it with a Custom C# PowerShell Host (a System.Management.Automation.Host.PSHost implementation) shows:
_Profiles_
CurrentUserCurrentHost = ''
CurrentUserAllHosts = ''
AllUsersCurrentHost = ''
AllUsersAllHosts = ''
Background
https://github.com/chocolatey/choco/issues/667
This has been tested in PowerShell v3 / System.Managment.Automation (SMA) v3 but it could easily be proven out in other PowerShell versions.
As a possible fix, this is what I've come up with. However it does mean that $profile is always expected to be in the Documents folder.
var documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.DoNotVerify);
var currentUserCurrentHostProfile = _fileSystem.combine_paths(documentsFolder, "WindowsPowerShell\\Microsoft.PowerShell_profile.ps1");
var profileFix = #"
if ((Test-Path(""{0}"")) -and ($profile -eq $null -or $profile -eq '')) {{
$global:profile = ""{1}""
}}
".format_with(documentsFolder, currentUserCurrentHostProfile);
pipeline.Commands.Add(new Command(profileFix, isScript: true, useLocalScope: false));
This is done this way due to special accounts like LocalSystem that would not have a profile folder.
Note: .format_with is a string formatter, so the {{ and }} you see will be converted to { and } when it finishes the string formatting.
I try to create a contact folder in an other mailbox. Since Powershell can't do this I downloaded a c# sample over this MSDN site:
https://code.msdn.microsoft.com/exchange/Exchange-2013-Create-35e4948c/view/Discussions#content
Then I modified the createFolder_CS.cs to this:
class Ex15_CreateFolder_CS
{
static ExchangeService service = Service.ConnectToService(UserDataFromConsole.GetUserData(), new TraceListener());
static void Main(string[] args)
{
CreateFolder(service, "Test", WellKnownFolderName.MsgFolderRoot);
Console.WriteLine("\r\n");
Console.WriteLine("Press or select Enter...");
Console.Read();
}
static void CreateFolder(ExchangeService service, string DisplayName, WellKnownFolderName DestinationFolder)
{
// Instantiate the Folder object.
Folder folder = new ContactsFolder(service);
// Specify the name of the new folder.
folder.DisplayName = DisplayName;
// Create the new folder in the specified destination folder.
folder.Save(DestinationFolder);
Console.WriteLine("Folder created:" + folder.DisplayName);
}
}
After the change I started the program. I entered my e-mail and the password and it created the contact folder in my mailbox. But when I use a different e-mail address the program did not work.
I compiled it and started the exe-file as (other user) domain/exchange-admin but it still did not work for another mailbox.
So I read something about a ImpersonatedUserId but this is already included in the program.
Maybe you can give me some tipps how to make this working since I am a starter at c#?
The problem with your code is you not telling it what Mailbox you want to save the new folder in. You need to use the FolderId overload to specify this or its always going to save it to the Mailbox of the credentials its running under eg modify you sub like
static void CreateFolder(ExchangeService service, string DisplayName, WellKnownFolderName DestinationFolder,String TargetMailboxSMTPAddress)
{
// Instantiate the Folder object.
Folder folder = new ContactsFolder(service);
// Specify the name of the new folder.
folder.DisplayName = DisplayName;
FolderId ParentFolder = new FolderId(DestinationFolder,TargetMailboxSMTPAddress);
// Create the new folder in the specified destination folder.
folder.Save(ParentFolder);
Console.WriteLine("Folder created:" + folder.DisplayName);
}
If you want to use Impersonation then you just need to add One more line in the code
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress,TargetMailboxSMTPAddress);
You will need to be assigned the ApplicationImpersonation RBAC role to use this https://msdn.microsoft.com/en-us/library/office/bb204095(v=exchg.140).aspx
If your creating a console app to run in poweshell I would suggest you just use the Managed API in Powershell eg here a script module that will create Folders in Mailbox using the Managed API
function Connect-Exchange{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$MailboxName,
[Parameter(Position=1, Mandatory=$true)] [PSCredential]$Credentials
)
Begin
{
Load-EWSManagedAPI
## Set Exchange Version
$ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1
## Create Exchange Service Object
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)
## Set Credentials to use two options are availible Option1 to use explict credentials or Option 2 use the Default (logged On) credentials
#Credentials Option 1 using UPN for the windows Account
#$psCred = Get-Credential
$creds = New-Object System.Net.NetworkCredential($Credentials.UserName.ToString(),$Credentials.GetNetworkCredential().password.ToString())
$service.Credentials = $creds
#Credentials Option 2
#service.UseDefaultCredentials = $true
#$service.TraceEnabled = $true
## Choose to ignore any SSL Warning issues caused by Self Signed Certificates
Handle-SSL
## Set the URL of the CAS (Client Access Server) to use two options are availbe to use Autodiscover to find the CAS URL or Hardcode the CAS to use
#CAS URL Option 1 Autodiscover
$service.AutodiscoverUrl($MailboxName,{$true})
Write-host ("Using CAS Server : " + $Service.url)
#CAS URL Option 2 Hardcoded
#$uri=[system.URI] "https://casservername/ews/exchange.asmx"
#$service.Url = $uri
## Optional section for Exchange Impersonation
#$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName)
if(!$service.URL){
throw "Error connecting to EWS"
}
else
{
return $service
}
}
}
function Load-EWSManagedAPI{
param(
)
Begin
{
## Load Managed API dll
###CHECK FOR EWS MANAGED API, IF PRESENT IMPORT THE HIGHEST VERSION EWS DLL, ELSE EXIT
$EWSDLL = (($(Get-ItemProperty -ErrorAction SilentlyContinue -Path Registry::$(Get-ChildItem -ErrorAction SilentlyContinue -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Exchange\Web Services'|Sort-Object Name -Descending| Select-Object -First 1 -ExpandProperty Name)).'Install Directory') + "Microsoft.Exchange.WebServices.dll")
if (Test-Path $EWSDLL)
{
Import-Module $EWSDLL
}
else
{
"$(get-date -format yyyyMMddHHmmss):"
"This script requires the EWS Managed API 1.2 or later."
"Please download and install the current version of the EWS Managed API from"
"http://go.microsoft.com/fwlink/?LinkId=255472"
""
"Exiting Script."
exit
}
}
}
function Handle-SSL{
param(
)
Begin
{
## Code From http://poshcode.org/624
## Create a compilation environment
$Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
$Compiler=$Provider.CreateCompiler()
$Params=New-Object System.CodeDom.Compiler.CompilerParameters
$Params.GenerateExecutable=$False
$Params.GenerateInMemory=$True
$Params.IncludeDebugInformation=$False
$Params.ReferencedAssemblies.Add("System.DLL") | Out-Null
$TASource=#'
namespace Local.ToolkitExtensions.Net.CertificatePolicy{
public class TrustAll : System.Net.ICertificatePolicy {
public TrustAll() {
}
public bool CheckValidationResult(System.Net.ServicePoint sp,
System.Security.Cryptography.X509Certificates.X509Certificate cert,
System.Net.WebRequest req, int problem) {
return true;
}
}
}
'#
$TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
$TAAssembly=$TAResults.CompiledAssembly
## We now create an instance of the TrustAll and attach it to the ServicePointManager
$TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
[System.Net.ServicePointManager]::CertificatePolicy=$TrustAll
## end code from http://poshcode.org/624
}
}
function Get-FolderFromPath{
param (
[Parameter(Position=0, Mandatory=$true)] [string]$FolderPath,
[Parameter(Position=1, Mandatory=$true)] [string]$MailboxName,
[Parameter(Position=2, Mandatory=$true)] [Microsoft.Exchange.WebServices.Data.ExchangeService]$service,
[Parameter(Position=3, Mandatory=$false)] [Microsoft.Exchange.WebServices.Data.PropertySet]$PropertySet
)
process{
## Find and Bind to Folder based on Path
#Define the path to search should be seperated with \
#Bind to the MSGFolder Root
$folderid = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$MailboxName)
$tfTargetFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)
#Split the Search path into an array
$fldArray = $FolderPath.Split("\")
#Loop through the Split Array and do a Search for each level of folder
for ($lint = 1; $lint -lt $fldArray.Length; $lint++) {
#Perform search based on the displayname of each folder level
$fvFolderView = new-object Microsoft.Exchange.WebServices.Data.FolderView(1)
if(![string]::IsNullOrEmpty($PropertySet)){
$fvFolderView.PropertySet = $PropertySet
}
$SfSearchFilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$fldArray[$lint])
$findFolderResults = $service.FindFolders($tfTargetFolder.Id,$SfSearchFilter,$fvFolderView)
if ($findFolderResults.TotalCount -gt 0){
foreach($folder in $findFolderResults.Folders){
$tfTargetFolder = $folder
}
}
else{
Write-host ("Error Folder Not Found check path and try again")
$tfTargetFolder = $null
break
}
}
if($tfTargetFolder -ne $null){
return [Microsoft.Exchange.WebServices.Data.Folder]$tfTargetFolder
}
else{
throw ("Folder Not found")
}
}
}
#######################
<#
.SYNOPSIS
Creates a Folder in a Mailbox using the Exchange Web Services API
.DESCRIPTION
Creates a Folder in a Mailbox using the Exchange Web Services API
Requires the EWS Managed API from https://www.microsoft.com/en-us/download/details.aspx?id=42951
.EXAMPLE
Example 1 To create a Folder named test in the Root of the Mailbox
Create-Folder -Mailboxname mailbox#domain.com -NewFolderName test
Example 2 To create a Folder as a SubFolder of the Inbox
Create-Folder -Mailboxname mailbox#domain.com -NewFolderName test -ParentFolder '\Inbox'
Example 3 To create a new Folder Contacts SubFolder of the Contacts Folder
Create-Folder -Mailboxname mailbox#domain.com -NewFolderName test -ParentFolder '\Contacts' -FolderClass IPF.Contact
#>
########################
function Create-Folder{
param(
[Parameter(Position=0, Mandatory=$true)] [string]$MailboxName,
[Parameter(Position=1, Mandatory=$true)] [PSCredential]$Credentials,
[Parameter(Position=2, Mandatory=$true)] [String]$NewFolderName,
[Parameter(Position=3, Mandatory=$false)] [String]$ParentFolder,
[Parameter(Position=4, Mandatory=$false)] [String]$FolderClass
)
Begin
{
$service = Connect-Exchange -MailboxName $MailboxName -Credentials $Credentials
$NewFolder = new-object Microsoft.Exchange.WebServices.Data.Folder($service)
$NewFolder.DisplayName = $NewFolderName
if(([string]::IsNullOrEmpty($folderClass))){
$NewFolder.FolderClass = "IPF.Note"
}
else{
$NewFolder.FolderClass = $folderClass
}
$EWSParentFolder = $null
if(([string]::IsNullOrEmpty($ParentFolder))){
# Bind to the MsgFolderRoot folder
$folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$MailboxName)
$EWSParentFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)
}
else{
$EWSParentFolder = Get-FolderFromPath -MailboxName $MailboxName -service $service -FolderPath $ParentFolder
}
#Define Folder Veiw Really only want to return one object
$fvFolderView = new-object Microsoft.Exchange.WebServices.Data.FolderView(1)
#Define a Search folder that is going to do a search based on the DisplayName of the folder
$SfSearchFilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$NewFolderName)
#Do the Search
$findFolderResults = $service.FindFolders($EWSParentFolder.Id,$SfSearchFilter,$fvFolderView)
if ($findFolderResults.TotalCount -eq 0){
Write-host ("Folder Doesn't Exist")
$NewFolder.Save($EWSParentFolder.Id)
Write-host ("Folder Created")
}
else{
Write-error ("Folder already Exist with that Name")
}
}
}
I have recently began using C# to invoke powershell scripts, with some success :)
$spWeb = Get-SPWeb -Identity http://127.0.0.1
$listTemplate = [Microsoft.SharePoint.SPListTemplateType]::DocumentLibrary
$spWeb.Lists.Add($args, "", $listTemplate) > $myDirectory
$spWeb.Lists.Add returns a SharePoint GUID.
Question:
I simply wish to pass in the directory/filename in which the GUID will
be written. How could that be done?
I have posted on the MSDN forums here: http://goo.gl/5p0oz but have continued my search on stackoverflow due to a seemingly dead end thread. This post is a cumulative gathering of the information found through MSDN responses.
You can try using the Set-Content cmdlet instead, like this. You need to pass the $myFile as a string and Set-Content will do the rest for you -
Inside your script i.e. MyScript.ps1 here, you will have this piece of code -
param([string]$parameter, [string]$myFile)
try
{
$spWeb = Get-SPWeb -Identity http://127.0.0.1
$listTemplate = [Microsoft.SharePoint.SPListTemplateType]::DocumentLibrary
$guid = $spWeb.Lists.Add($parameter, "", $listTemplate)
$guid | Set-Content $myFile
}
catch
{
throw ("Failed. The error was: '{0}'." -f $_ )
}
How to Run:
Open Powershell Prompt and type this
.\MyScript.ps1 "someparam1" "D:\Output.txt"
C# Bit -
private PowerShell _ps;
_ps = PowerShell.Create();
var parameter = new List<string>
{
parameter,
myFile
};
var sr = new StreamReader(#"C:\MyScript.ps1");
_ps.AddScript(sr.ReadToEnd()).AddParameters(parameter);
_ps.Invoke();