How to remotely start service on Azure VM with powershell 5.1 - powershell

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}

Related

Azure DevOps Pipline: Login to RDS account with Service Principle

Did anyone try to add a user to a VM in a Host Pool using Azure DevOps pipeline and service principal?
I need t build a pipeline that I could add a user name and I would assigned to a host pool
$aadContext = Connect-AzureAD
$svcPrincipal = New-AzureADApplication -AvailableToOtherTenants $true -DisplayName $SPDEV
$svcPrincipalCreds = New-AzureADApplicationPasswordCredential -ObjectId $svcPrincipal.ObjectId
$creds = New-Object System.Management.Automation.PSCredential($svcPrincipal.AppId, (ConvertTo-SecureString $svcPrincipalCreds.Value -AsPlainText -Force))
Add-RdsAccount -DeploymentUrl "https://rdbroker.wvd.microsoft.com" -Credential $creds -ServicePrincipal -AadTenantId $aadContext.TenantId.Guid
#Add User to AVD Host Pool
if (Get-RdsAppGroupUser -TenantName Test -HostPoolName $hostpool -AppGroupName $HostPoolAppGroup -UserPrincipalName $user) -eq
Add-RdsAppGroupUser -TenantName $tenant -HostPoolName $hostpool -AppGroupName $HostPoolAppGroup -UserPrincipalName $user
# Assign the user to the app role
New-AzureADUserAppRoleAssignment -ObjectId $user.ObjectId -PrincipalId $user.ObjectId -ResourceId $sp.ObjectId -Id $appRole.Id
Update-AzWvdHostPool -ResourceGroupName $RG -Name $HostPool -PersonalDesktopAssignmentType Direct
#Add User to AVD Host Pool VM
New-AzRoleAssignment -SignInName $User -RoleDefinitionName "Desktop Virtualization User" -ResourceName $HostPool -ResourceGroupName $RG -ResourceType 'Microsoft.DesktopVirtualization/applicationGroups'
I have this but not sure how to build a pipeline around it.
Use azure powershell task in your pipeline. In addition, you need to connect your Service Principle via Service connections->Azure Resource Manager.

How to restart an Azure appservice from Azure Powershell

How can you restart an AppService from Azure's Powershell running in a Runbook in an Automation Account in an ARM subscription in Azure?
I thought the approach would be:
Restart-AzureWebsite -Name "your-appservice-name"
but that gets:
Restart-AzureWebsite : No default subscription has been designated.
Use select-AzureSubscription -Default #<subscriptionName> to set the default subscription.
There is no Restart-AzureRmWebApp available in Azure PowerShell.
All combinations of the following lead to just a bunch of other error messages:
$Cred = Get-AutomationPSCredential -Name 'your-credentials-name'
Add-AzureAccount -Credential $Cred
Add-AzureRMAccount -Credential $Cred
Get-AzureSubscription –SubscriptionName 'your-subscription-name' | Select-AzureSubscription -Default
Restart-AzureWebsite -Name "your-appservice-name"
There is no Restart-AzureRmWebApp available in Azure PowerShell.
As Walter - MSFT mentioned that we could import AzureRM.Websites, before that we need to update AzureRM.Profile to 4.0, more detail you could refer to the screenshot.
Before to do that we could create Azure AD service principal locally.
How to create service principal we could refer to this document
Login-AzureRmAccount
$sp = New-AzureRmADServicePrincipal -DisplayName exampleapp -Password "password"
Sleep 20
New-AzureRmRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $sp.ApplicationId
Run Restart-AzureRmWebApp command in the Runbook.
$azureAplicationId ="Application Id"
$azureTenantId= "tenant Id"
$azurePassword = ConvertTo-SecureString "password" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureAplicationId , $azurePassword)
Add-AzureRmAccount -Credential $psCred -TenantId $azureTenantId -ServicePrincipal
Restart-AzureRmWebApp -ResourceGroupName "ResourceGroup" -Name "WebApp Name"
This Powershell script works inside an Azure Automation Runbook:
Invoke-AzureRmResourceAction -ResourceGroupName "<your-resource-group-name>" -ResourceName "<your-resource-name>" -ResourceType 'Microsoft.Web/sites' -Action 'Restart' -Force
Edit
However the next script is probably better; it relies on #Tom Sun's answer above, i.e.
Upgrade the modules - go to Automation Accounts / Modules / Update Azure Modules.
Import the AzureRm.Websites module - go to Automation Accounts / Modules / Browse Gallery.
Create under Automation Accounts / Credentials.
$Cred = Get-AutomationPSCredential -Name '<your-credentials>'
Add-AzureRMAccount -Credential $Cred
Get-AzureRmSubscription –SubscriptionName '<your-subscription-name>' | Select-AzureRmSubscription
Restart-AzureRmWebApp -ResourceGroupName "office" -Name "<your-appservice-name>"

Azure Powershell how to get running services of a VM via Runbook?

I'm trying to write an Azure Powershell Runbook that will start a VM, and then check if a windows service on the VM is running or not and start it.
I can get the VM started, but enumerating the services isn't working. I'm brand new on Azure Runbooks so I could be doing something wrong. I limited the below code to only the Get-Service bit and not the VM starting.
# Returns strings with status messages
[OutputType([String])]
param (
[Parameter(Mandatory=$false)]
[String] $AzureConnectionAssetName = "AzureRunAsConnection",
[Parameter(Mandatory=$false)]
[String] $ResourceGroupName = ""
)
try {
# Connect to Azure using service principal auth
$ServicePrincipalConnection = Get-AutomationConnection -Name $AzureConnectionAssetName
Write-Output "Logging in to Azure..."
$Null = Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $ServicePrincipalConnection.TenantId `
-ApplicationId $ServicePrincipalConnection.ApplicationId `
-CertificateThumbprint $ServicePrincipalConnection.CertificateThumbprint
}
catch {
if(!$ServicePrincipalConnection) {
throw "Connection $AzureConnectionAssetName not found."
}
else {
throw $_.Exception
}
}
# If there is a specific resource group, then get all VMs in the resource group,
# otherwise get all VMs in the subscription.
if ($ResourceGroupName) {
$VMs = Get-AzureRmVM -ResourceGroupName $ResourceGroupName
}
else {
$VMs = Get-AzureRmVM
}
# Try and enumerate the VM's services
foreach ($VM in $VMs) {
Write-Output "Listing all services..."
Write-Output ("VM: {0}" -f $VM.Name)
$VM | Get-Service | Format-Table -AutoSize
Write-Output "Listing alternative method..."
Get-Service -ComputerName $VM.Name | Format-Table -AutoSize
Write-Output "Finished listing..."
}
And the output is this:
Logging in to Azure...
Listing all services...
VM: demo-0
Listing alternative method...
Finished listing...
Well, first of all, Starting VM is asynchronous, so you need to wait for the VM to actually boot, and the Get-Service wouldn't work anyway, as to get the services from a VM you need to authenticate against that VM, so either user PSsessions or invoke-command, something like that. Just look on how to remote into servers with powershell or how to issue powershell command to remote PC's. This case is nothing different. And it has nothing to do with how Azure Automation works.
When you are running Azure Automation runbooks, you have the choice of the azure queue or creating a hybrid worker. The azure queue is good for many processes, but it will not have access to the VMs directly to run commands such as get-service.
To expand on #4c74356b41 answer, you will need to use remote powershell to execute the command (using New-PSSession) but you will also have to ensure that those commands are running on an Azure Automation Hybrid Worker
In the comments below, you asked about credentials. You can set credentials in the Azure Automation account and then have them used by your script when creating a new session. See this link
You could try to use the following cmdlets. It works for me.
# Try and enumerate the VM's services
foreach ($VM in $VMs) {
Write-Output "Listing all services..."
Write-Output ("VM: {0}" -f $VM.Name)
$ResourceGroupName=$VM.ResourceGroupName
$Name=$VM.Name
$status=(Get-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $Name -Status).Statuses[1].code
if($status -like "PowerState/deallocated")
{
Write-Output "VM is stopped, starting VM"
if (Start-AzureRmVm -ResourceGroupName $ResourceGroupName -Name $Name)
{
Write-Output "Start VM successfuly"
}else
{
Write-Output "Start VM failed"
break
}
}
##get VM's Public IP
$nicName = ($VM.NetworkInterfaceIDs[0] -split '/')[-1]
$pip = (Get-AzureRmNetworkInterface -Name $nicName -ResourceGroupName $ResourceGroupName).IpConfigurations.publicipaddress.id
$PublicIP=(Get-AzureRmPublicIpAddress -ResourceGroupName shui -Name ($pip -split '/')[-1]).IpAddress
$Uri="http://$($PublicIP):5986"
Write-Output "Get ConnectionUri $Uri"
##get Credential from assets
$shui=Get-AutomationPSCredential -Name 'shui'
$session=New-PSSession -ConnectionUri $Uri -Credential $shui -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck)
$result=Invoke-Command -Session $session -ScriptBlock {ipconfig}
Write-Output "$result"
Write-Output "Finished listing..."
}
Before you use this script. Firstly,you should open ports 5896 on your VM's firewall and NSG, you could check as the following link. Please ensure you could telnet IP 5986 on your local PC.
You should import AzureRM.Network modules to your Automation Account. More information about how to import Modules please refer to this link.
3.Store your VMs's passord to Runbook, you could refer to this link. When you want to use the credentials, you could use the script below:
##get Credential from assets
$shui=Get-AutomationPSCredential -Name 'shui'
$session=New-PSSession -ConnectionUri $Uri -Credential $shui -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck)

Attach to an Azure ShareFile using WinRM and net use

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:

Install windows service via Powershell on Win2012 - Access Denied

I am running the below but can't work out why I get access denied at the call to New-Service:
param(
[string]$serviceName,
[string]$exePath,
[string]$username,
[string]$password
)
"Attempting to install service '$serviceName' - '$exePath'"
$secpassword = convertto-securestring -String $password -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($username, $secpassword)
$existingService = Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'"
if ($existingService)
{
"'$serviceName' exists already. Stopping."
Stop-Service $serviceName
"Waiting 3 seconds to allow existing service to stop."
Start-Sleep -s 3
$existingService.Delete()
"Waiting 5 seconds to allow service to be un-installed."
Start-Sleep -s 5
}
"Installing the service."
New-Service -BinaryPathName $exePath -Name $serviceName -Credential $cred -DisplayName $serviceName -StartupType Automatic
"Installed the service."
"Starting the service."
Start-Service $serviceName
"Complete."
I have double checked the credentials I pass to the script of course, using 'adminstrator' and 'workgroup\administrator' for the username. I am actually logged in to the machine as administrator.
Have you tried using an elevated Powershell console? Right-Click Powershell > Run as Administrator. This issue happens a lot when running scripts that modify system settings, specially in Windows 2012.