Attach to an Azure ShareFile using WinRM and net use - powershell

Context:
I have setup an ARM deployment from the 201-winrm-windows in azure-quickstart-template.
The deployment run fine
I can access the VM using WinRM
I can run a script remotely using WinRM
The problem is that I'm trying to setup a storage file on that VM. The official documentation ask to run this command:
net use <drive-letter>: `
\<storage-account-name>.file.core.windows.net<share-name> `
/u:<storage-account-name> <storage-account-key>
# Result:
The command completed successfully.
The issue:
When the command is run locally (local powershell on the VM), I have a success message and the mount appear.
When the command is run through WinRM, I have the same success message but when I connect to the VM, I cannot access the mount.
My code:
$resourceGroupName = "resourcegroupname"
$username = "username"
$storageAccountName = "storageaccountname"
$zone = "westeurope"
$hostName = "$resourceGroupName.$zone.cloudapp.azure.com"
$shareFileName = "test"
$winrmPort = '5986'
$storageAccountKey = "......................"
$cred = new-object `
-typename System.Management.Automation.PSCredential `
-argumentlist $username, $password
$soptions = New-PSSessionOption -SkipCACheck
Invoke-Command `
-ComputerName $hostName `
-Credential $cred `
-Port $winrmPort `
-SessionOption $soptions `
-filepath .\provision.ps1 `
-UseSSL `
-ArgumentList `
$storageAccountName, `
$storageAccountKey, `
$shareFileName
And the provision file .\provision.ps1:
Param (
[Parameter(Mandatory=$True,Position=0)]
[string]$accountStorageName,
[Parameter(Mandatory=$True,Position=1)]
[string]$accountStorageKey,
[Parameter(Mandatory=$True,Position=2)]
[string]$shareFileName
)
net use w: `
\\$accountStorageName.file.core.windows.net\$shareFileName `
/user:$accountStorageName $accountStorageKey
Note:
my issue is similar to this one but the author have no response.

The problem you are hitting into in this case is that, WinRM runs as NetworkService. When you 'net use' through WinRM, the mount operation is done for NetworkService user, and you cannot access it through another user you connect to VM with. You'll need to ensure that the mount operation is done through same user context that you'll need to access the share as.

Just tried what you've done but I can access the mount successfully. A small difference is that I connect to the VM first and then mount the file share, I didn't combine these two steps into one like you did, not sure whether this is the issue but just like to share with you and for your reference.
I uploaded a file in my file share and I can access the file share and get the file as below snapshot shows:
Update access from RDP:

Related

How to remotely start service on Azure VM with powershell 5.1

How can I start a service on an Azure VM remotely? It seems impossible to do without Powershell being "Run as Administrator". Is there a way to launch as admin?
(I would pass in Get-Credential parameter, but unfortunately the 5.1 version Set-Service command does not accept that as a parameter like it does in Powershell version 7.x, and i am limited to 5.1 for now.)
My credentials do have admin level rights on the VM, but i can't seem to figure out a way to pass that via a command.
I am triggering the call like this, where $action is either 'stop' or 'start':
$runCommand = Invoke-AzVMRunCommand `
-ResourceGroupName $rg `
-VMName $vm `
-CommandId 'RunPowerShellScript' `
-ScriptPath $scriptPath `
-Parameter #{action = $action}
The linked script would then execute something like this:
$serviceNames = #("service1, service2")
foreach($serviceName in $serviceNames){
$service = Get-Service -Name $serviceName
if($service){
if($action -ieq "start"){
Set-Service -InputObject $service -Status "Running"
}
}
else{
Write-Output "Service $serviceName not found!"
}
}
When i run from my laptop - it hangs.
When i run from Azure portal via "Run Command" - it hangs.
When i run from the VM itself - it says:
"Service '' cannot be configured due to the following error:
Access is denied
When i run from the VM itself but start Powershell as admin - It works!
Make sure you have to connect with local administrator password which you already configured with your VM.
If you are not able to connect the VM you need to reset your local administrator password/ Remote Desktop Service Configuration as per MS-DOC. We can reset either Azure Portal / VM Access extension and PowerShell.
If you want to connect the Azure VM from your local, you have to signed in with respective Azure subscription.
Use Set-AzVMAccessExtension to reset the local administrator account password.
VM has a single Access Agent. Use the same VM Access Agent which you used earlier.
Workaround
Way 1
Add the user to your VM
$Uname = "<UserName>"
$password = "<Password>"
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
New-LocalUser $Uname -Password $securePassword -FullName $Uname -Description "test admin account"
Add-LocalGroupMember -Group "Administrators" -Member $Uname
Way 2
Reset the local Administrator password
$vm = Get-AzVM -ResourceGroupName "<ResourceGroup Name>" -Name "<Resource name>"
$Uname = "<UserName>"
$password = "<Password>"
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credentials= New-Object System.Management.Automation.PSCredential ($Uname, $securePassword)
Set-AzVMAccessExtension -Credential $credentials -ResourceGroupName $vm.ResourceGroupName -VMName $vm.Name -Location $vm.Location -Name VMAccessAgent -TypeHandlerVersion "2.0"
Access the Script file using specific login
Connect-AzAccount
$vm = Get-AzVM -Name "<your vm name>" -ResourceGroupName "<your vm resource group>"
$runCommand = Invoke-AzVMRunCommand `
-ResourceGroupName $rg `
-VMName $vm `
-CommandId 'RunPowerShellScript' `
-ScriptPath $scriptPath `
-Parameter #{action = $action}

PowerShell Computer StartUp-Script - Switch user-context?

Through Microsoft Group Policy I did define to run a Powershell-Script on Computer Start-Up. Also I have the requirement to run a Powershell-Script as Scheduled Task without saving credentials.
On both scenarios I have the same problem ...
I want to run a Citrix Powershell-Command (PSSnapIn) like:
Set-BrokerMachine -MachineName "domain.local\$env:COMPUTERNAME" -AdminAddress "RemoteServer.domain.local" -InMaintenanceMode $True
Manual: https://citrix.github.io/delivery-controller-sdk/Broker/Set-BrokerMachine/
Of course only users who have the permission could run those Citrix-commands. I would be able to give a domain-user the permission to run the command "Set-BrokerMachine", but in the mentioned scenarios the PowerShell-scripts run in context of the system-user.
I did simulate the system-user by PSExec:
Error running as System-User
My scripts do other things of course and I want to keep them running as System-User, but now I am looking for a clean solution to get those Citrix-commands running.
If possible, I don't want to save credentials in my scripts.
EDIT #1:
I would be able to workaround with the following code:
$Username = "MySpecialUser"
$Password = 'MyPassword'
$SecurePassword = ConvertTo-SecureString $Password -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential $Username, $SecurePassword
$Result = Invoke-Command -Session ( New-PSSession -ComputerName "RemoteServer.domain.local" -Credential $Credential ) -ScriptBlock {
Add-PSSnapin Citrix*
Set-BrokerMachine -MachineName "domain.local\$args" -InMaintenanceMode $True
} -ArgumentList $env:COMPUTERNAME -HideComputerName
Remove-PSSession -InstanceId $Result.RunspaceId
I don't like this because:
The code has to contain credentials (ofc I could encrypt it ...)
I have to create a permission-system for this special user in Citrix
I have to put the special-user into a local-group on every server, to allow the remote-administration (security-risk)
I don't like to use PSSession
...
Is there a better/cleaner solution? Any ideas?

How to copy file to VM using Powershell?

Sounds very simple, but most of the answers given on the internet assume both computers are on the same network. What if they are not, e.g. I want to copy a file to Azure VM. There is a thread Windows Azure Powershell Copying file to VM , but its four years old and the answers require many steps.
Agree with Rasmusgude, you can upload file to Azure File Share then mount Azure File Share to that VM.
Are you administrator of that VM?
If yes, you can enable WinRM and use WinRM to upload files to it.
About enable Azure VM WinRM, you should add port 5985 to Azure VM's NSG inbound rules and add port 5985 to windows firewall inbound rules.
Then use this script to create a session:
$username = 'user'
$pass = ConvertTo-SecureString -string 'password' -AsPlainText -Force
$cred = New-Object -typename System.Management.Automation.PSCredential -argumentlist $username, $pass
$s = New-PSSession -ConnectionUri 'http://xx.xx.xx.xx:5985' -Credential $cred -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck)
About upload files to that VM, you can use this PowerShell command Send-File -Path C:test.xml -Destination C: -Session $session.
Here a blog about sending files over WinRM, please refer to it.
Hope this helps.
You could use Azure File Share (AFS), and then:
Mount the AFS as a drive on the VM
Use the REST Api or a library to upload the files to the AFS

How Connect to a Azure Windows VM and run a remote script with PowerShell?

I am familiar with Linux envs and using SSH to run remote scripts and programs and automatic scripts from my desktop.
I would like to have a similar workflow with Windows VMs that I have on my Azure Account. However, I canĀ“t find a straight forward instructions on how to build my local PowerShell scripts.
I need only to connect to a VM and call some scripts within it.
The best I could find would be this guide from MS
https://learn.microsoft.com/en-us/azure/virtual-machines/windows/winrm
Or this a litte older blog post.
http://fabriccontroller.net/using-remote-powershell-with-windows-azure-virtual-machines/
According to your description, we can use New-Pssession to execute script to stop/start service, like this:
$username = 'jason'
$pass = ConvertTo-SecureString -string 'password' -AsPlainText -Force
$cred = New-Object -typename System.Management.Automation.PSCredential -argumentlist $username, $pass
$s = New-PSSession -ConnectionUri 'http://23.99.82.2:5985' -Credential $cred -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck)
Invoke-Command -Session $s -ScriptBlock {Get-Process PowerShell}
Result like this:
Another way, we can use Azure custom script extension to run script, we can upload script to Azure storage account, and use Set-AzureRmVMCustomScriptExtension to set custom script:
PS C:\> Set-AzureRmVMCustomScriptExtension -ResourceGroupName "ResourceGroup11" -Location "Central US" -VMName "VirtualMachine07" -Name "ContosoTest" -TypeHandlerVersion "1.1" -StorageAccountName "Contoso" -StorageAccountKey <StorageKey> -FileName "ContosoScript.exe" -ContainerName "Scripts"
But custom script only can run one time, if you want to re-run this script, we should remove it with this command Remove-AzureRmVMCustomScriptExtension, then re-set it.
More information about Azure custom script extension, please refer to this link.
I ran into a lot of trouble using the accepted answer, and found I wanted to use SSL in my remote execution. I could not find anywhere this was succinctly put, so here's what worked for me. Essentially, use the built-in Azure command to enable remote PowerShell on the VM, and then run secure remote sessions to your heart's content!
Invoke-AzureRmVMRunCommand -ResourceGroupName $vmResourceGroupName -Name $vmName -CommandId 'EnableRemotePS'
$cred = New-Object -typename System.Management.Automation.PSCredential -argumentlist $username, $secureStringPassword
$sessionOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck
Invoke-Command -ComputerName $ipAddress -Credential $cred -UseSSL -SessionOption $sessionOptions -FilePath $scriptPath

Iterate through a list of VMs in Azure

i have about 10 VMs hosted on Auzre, i need to iterate through each of them and then execute a powershell script on each of them, lets say 'Set-Date'
whats the best way to connect to each VM, execute the ps script and then disconnect?
You can use PowerShell Remoting or custom scripts via extensions to execute PowerShell code on the remote VM.
For both solutions you get your list of VMs with the PowerShell command Get-AzureVM. Use a loop to iterate those VMs. I skip that part here because iterating are PowerShell basics.
1. PowerShell Remoting
For this you need PowerShell Remoting enabled on the remote VM and have an open port for PowerShell Remoting. Both is a default setting for new VMs.
Advantage: this solution is very handy for interactive sessions with a remote VM. Disadvantage of this solution is, that you need to authenticate to each VM and have to keep connected while execution.
With each VM you can do something like this. This is a shortened example where I have installed ADDS on the remote VM.
# Prepare credentials for remote session.
$secpasswd = ConvertTo-SecureString $AdminPassword -AsPlainText -Force
$credentialDC1 = New-Object System.Management.Automation.PSCredential ($AdminUsername, $secpasswd)
$EndpointDC = Get-AzureWinRMUri -ServiceName testlab-dc -Name dc1
#$EndpointDC = Get-AzureVM -ServiceName testlab-dc -Name dc1 | Get-AzureEndpoint -Name WinRmHTTPs
$psso = New-PSSessionOption -SkipCACheck
$sessionDC = New-PSSession -ComputerName testlab-dc.cloudapp.net -Port $EndpointDC.Port -Credential $credentialDC1 -UseSSL -SessionOption $psso
Invoke-Command -Session $sessionDC -ScriptBlock {
# Set-Date or other command
# or for example
# Install-WindowsFeature AD-Domain-Services
}
Remove-PSSession -Session $sessionDC
2. Custom Scripts via Extensions
Here you can upload a PowerShell file into your BLOB storage and then let execute that file on your VMs. Requirement is that the VM agent has to be installed on the VM. (Default for new VMs from the gallery.)
Advantage: you do not need to authenticate to each VM and you do not need to keep connect while execution.
Disadvantage: you have to prepare a separate PowerShell file to upload. Getting results is asynchronous.
Example:
# Upload PowerShell file
Set-AzureStorageBlobContent -Container extensions -File "Install-ADForest.ps1" -Blob "Install-ADForest.ps1"
# Install AD services and forrest
Get-AzureVM -ServiceName demoext -Name demoext |
Set-AzureVMCustomScriptExtension -ContainerName extensions -FileName "Install-ADForest.ps1" |
Update-AzureVM
The container has to exist. Create that container before you upload the file.