Create Folder in other Mailbox with EWS API - c#

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")
}
}
}

Related

How to read the ms-Exch-Mailbox-Security-Descriptor frm each Exchange Mailbox

When doing O365 migrations, part of the 'Planning' session includes an analysis of how users Share and give access to each others calendars and folders. I have this Function wrapped inside a ForEach loop which gets those permissions via native Exchange PS cmdlets:
Function Pull-MBXFolderPerms {
Param ([string]$MBXName)
Start-Sleep -Milliseconds 600
$Mailbox = '' + $MBXName
$Folders = Get-MailboxFolderStatistics $Mailbox | % {$_.folderpath} | % {$_.replace("/","\")}
Write-host "Processing folders on mailbox $Mailbox"
ForEach ($Fold in $Folders) {
$FolderKey = $Mailbox + ":" + $Fold
$Permissions = Get-MailboxFolderPermission -identity $FolderKey -ErrorAction silentlycontinue
$FolderPerms += $Permissions | ? {$_.User -notlike "Default" -and $_.User -notlike "Anonymous" -and $_.AccessRights -notlike "None" -and $_.AccessRights -notlike "Owner" } | Select-Object #{name='Mailbox';expression={$MBXName}},FolderName,#{name='UserWithAccess';expression={$_.User -join ','}},#{name='AccessRights';expression={$_.AccessRights -join ','}}
}
Return $FolderPerms
}
When doing this in bulk it takes days to complete in a large environment because there is an LDAP lookup on EACH ACE on every folder so that the User's Displayname can be shown in the results.
In order to speed this process up, I want to record the Security Descriptor off of the folder in its SDDL format to bypass the lookup on each ACE. I can then do th lookup later in bulk rather than opening and closing an LDAP session on each ACE
This code can be used to 'Loop' through ACEs for file systems:
$addACL=[System.Security.AccessControl.DirectorySecurity]::new($Fold,'Access')).GetSecurityDescriptorSddlForm(('Access'))
# Remove leading and trailing parenthesis from ACLs
$splitFirst = $addACL.split("(")
$splitDone = $splitFirst.TrimEnd(")")
# Filter for explicit permissions and remove implicit deny from each ACL
ForEach ($ACE in $splitDone) {
If ($ACE.Contains("ID")) {
continue
}
ElseIf ($FinalACE = $ACE | where {$ACE -notlike 'D:AI' -and $ACE -notlike 'D:PAI'}) {
$Script:ACLOutput += New-Object PSObject -Property #{
FullName = $Fold
sddlACE = $FinalACE
}
}
}
I am looking for a similar way of doing this with Exchange Mailbox folders and am at a loss as to how to get to the SDDL. We would also like to do this natively without using MFCMAPI
Any help would be appreciated!

How to add machine keys in GUIless server using Powershell for .net core applications

I have .Net core based applications hosted in MS azure on GUIless servers. I am using a load balancer as there are multiple servers.
I need to add same machinekey on both the GUIless server.
Can someone help me with the command to see and update machinekey on GUIless server using Powershell?
Appreciate help.
As Suggested by Chaodeng here is the PowerShell script for generating Machine key and also below are the few commands and steps on how to generate it.
You can save the below PowerShell script in your machine as .ps1 file and this will help you in generating machine key
# Generates a <machineKey> element that can be copied + pasted into a Web.config file.
function Generate-MachineKey {
[CmdletBinding()]
param (
[ValidateSet("AES", "DES", "3DES")]
[string]$decryptionAlgorithm = 'AES',
[ValidateSet("MD5", "SHA1", "HMACSHA256", "HMACSHA384", "HMACSHA512")]
[string]$validationAlgorithm = 'HMACSHA256'
)
process {
function BinaryToHex {
[CmdLetBinding()]
param($bytes)
process {
$builder = new-object System.Text.StringBuilder
foreach ($b in $bytes) {
$builder = $builder.AppendFormat([System.Globalization.CultureInfo]::InvariantCulture, "{0:X2}", $b)
}
$builder
}
}
switch ($decryptionAlgorithm) {
"AES" { $decryptionObject = new-object System.Security.Cryptography.AesCryptoServiceProvider }
"DES" { $decryptionObject = new-object System.Security.Cryptography.DESCryptoServiceProvider }
"3DES" { $decryptionObject = new-object System.Security.Cryptography.TripleDESCryptoServiceProvider }
}
$decryptionObject.GenerateKey()
$decryptionKey = BinaryToHex($decryptionObject.Key)
$decryptionObject.Dispose()
switch ($validationAlgorithm) {
"MD5" { $validationObject = new-object System.Security.Cryptography.HMACMD5 }
"SHA1" { $validationObject = new-object System.Security.Cryptography.HMACSHA1 }
"HMACSHA256" { $validationObject = new-object System.Security.Cryptography.HMACSHA256 }
"HMACSHA385" { $validationObject = new-object System.Security.Cryptography.HMACSHA384 }
"HMACSHA512" { $validationObject = new-object System.Security.Cryptography.HMACSHA512 }
}
$validationKey = BinaryToHex($validationObject.Key)
$validationObject.Dispose()
[string]::Format([System.Globalization.CultureInfo]::InvariantCulture,
"<machineKey decryption=`"{0}`" decryptionKey=`"{1}`" validation=`"{2}`" validationKey=`"{3}`" />",
$decryptionAlgorithm.ToUpperInvariant(), $decryptionKey,
$validationAlgorithm.ToUpperInvariant(), $validationKey)
}
}
Once you load the script in PowerShell using . . \(your.ps1file name), Now call the script by following command Generate-MachineKey which will make you generate the new machine key.

Could not create SSL/TLS secure channel error during TLS 1.2 connection when not in admin mode

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.

program control over azure vm start/stop

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

How do I recreate PowerShell $profile variable? It's empty in a custom Host

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.

Categories

Resources