Iterate through a list of VMs in Azure - powershell

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.

Related

Kerberos Delegation Issue Copying Files to Remote Session with 2008 R2 Domain functional Level

When running the below code, i can put anything in the block at the bottom - I'm trying to copy a folder across to run an exe from a local folder and perform an install of that exe during the remote session to remote machines. I am getting Access Denied Errors. I read, i cant use the Kerberos Delegation Cmdlets which are only for a forest level of 2012 and above. Current Site has Domain Functional Level 2008 R2. Is there another way to achieve copying the files across during each remote session to the computers specified in the text file?
Thanks in advance
########################################
$Cred = Get-Credential DOMAIN\USER
$Computers = Get-Content C:\tab.txt | Where-Object { $_ }
ForEach ($Computer in $Computers)
# {
# if (Test-Connection -ComputerName $Computer -BufferSize 16 -Count 1 `
-Quiet)
{
# Creates a new remote PowerShell Session and script block - enter
the code you want to execute remotely from this block
$Session = New-PSSession $computer -Credential $cred
Invoke-Command -Session $Session -ScriptBlock {
Copy-Item -Path "\\print-server\pcclient\win\*" -Destination
"c:\pcclient" -Force -Recurse -Verbose
# Start-Sleep -s 10
# Start-Process "\\Print-Server\PCClient\win\client-local-install.exe" -ArgumentList "/SILENT"
}
}
Remove-PSSession -Session $Session
# }
This is because you're on a remote machine, trying to access another network resource. When you connect to the remote machine in PowerShell, you're effectively connected/authenticated to that machine only, (unless you specify otherwise) it doesn't have access to your credentials to access the network share, so the connection to the network share is treated as unauthenticated, hence the failure.
This article https://blogs.technet.microsoft.com/heyscriptingguy/2012/11/14/enable-powershell-second-hop-functionality-with-credssp/ covers it well, essentially in you will need to run this locally (to allow your machine to pass credentials):
Enable-WSManCredSSP -Role Client -DelegateComputer * -Force
On the server run (to allow the server to accept these credentials):
Enable-WSManCredSSP -Role Server –Force
And update your New-PSSession command to:
$Session = New-PSSession $computer -Credential $cred -Authentication CredSSP
If you want, you can share your credentials with only specific machines, or subsets of a domain using *.yourdomain.lan or whatever, if you connect to multiple machines, then it's easier to use -DelegateComputer *.

Running a remote cmd command in PowerShell

I uploaded some files to a remote host with PowerShell, by FTP. On this host runs Windows 7 Embedded.
It turns out there is EWF (Enhanced Write Filter). So after a restart the uploaded files were gone. For saving the changes it needs commit them in cmd (at the remote host) by: ewfmgr d:-commit How can I include this command in my PowerShell code?
The code:
Enable-PSRemoting -Force
Set-Item wsman:\localhost\client\trustedhosts -Value * -Force
Restart-Service WinRm
Test-WSMan $line
Invoke-Command -ComputerName $line -scriptblock {cmd.exe /c "ewfmgr d: -commit"} -credential $FTPCredential
When I run Enable-PSRemoting -Force manually on the remote computer, it works, but it is uncomfortable and take lots of time. Is there another way to do this once for many hosts simultaneously?
Example-Code:
$session = New-PSSession -ComputerName yourRemoteComputer
Invoke-Command -Session $session -Scriptblock {ewfmgr d: -commit}
Remove-PSSession -Session $session
You have to enable Powershell Remoting on your host to invoke a command like this (https://technet.microsoft.com/en-us/library/ff700227.aspx)
If you need to transmit Credentials to your remote host, you can add the -Credential-Parameter to New-PSSession. This article describes how to add valid Credentials to your script (https://technet.microsoft.com/en-us/library/ff700227.aspx)
Greetings, Ronny

How to solve Powershell Invoke-Command New-VM error "... the VM management operation or both do not have the required access to the file share"

I am using an Azure runbook to run a powershell script on an Azure VM that attempts to create a simple VM on a physical Windows 2012 R2 server. Hyper-V and remote Powershell are available on the server. The directory the VM is going to be created in is for this test, shared with Everyone, full control. The Powershell call is as follows:
Import-Module Hyper-V
$session = New-PSSession -ComputerName $DeviceName -Credential $creds
$result = Invoke-Command -Session $session `
-ScriptBlock{(New-VM -Name $args[0] -Path $args[1] -MemoryStartupBytes $args[2] -NewVHDPath $args[3] -NewVHDSizeBytes $args[4] -SwitchName $args[5] )} `
-ArgumentList $VMName, $VMDirectory, $MemoryStartUpSize, $vhdPath, $vmDiskSize, $SwitchName
The account in $creds is in the list of Hyper-V Administrators on the physical server.
The New-VM Cmdlet actually creates the vhdx Hard Disk Image File in the path $vhdPath. It also creates a new folder named 'Web01TestVM02' ($VMName) and a subfolder called Virtual Machines. But then I get the error message:
'Web01TestVM02' failed to add device 'Virtual Hard Disk'. (Virtual machine ID ...)
'Web01TestVM02': The Machine Account 'domainname\servername$' or the user initiating the VM management operation or both do
not have the required access to the file share '\servername\e$\VirtualMachines\VMTest02\Web01TestVM02.vhdx'. Please
ensure that the computer machine account and the user initiating the VM management operation have full access to the
file share as well as the file system folder backing the file share. Error: 'General access denied error'
Any ideas how to solve or debug this is much appreciated.

New-PsDrive Remote copy from DFS share errors: A specified logon session does not exist

So to recap the situation: I am at one computer trying to run powershell using enter-pssession computername, then from the remote session, run the logic below:
$DFSPath = "\\DFSpath.com"
$RDL1 = [char](1+[char](gdr ?)[-1].name)
New-PSDrive -Name $RDL1 -PSProvider FileSystem -Root $DFSPath -Persist -credential domain\UN
The get-variable shows the variables properly. But when I try to create with New-PSDrive, it gives:
New-PSDrive : A specified logon session does not exist. It may already have
been terminated
I did look at this: PowerShell 2.0: Accessing Windows Shares during a Remote Session but wasn't able to get it to work. Also I wouldn't know how to devise it in my script above (which will be run on multiple computers). Is there anything newer? I am using v3 powershell. Thanks so much!
From the looks of things it appears that you are experiencing the dreaded "Double-Hop". If you only what to remote to a few computers it's pretty easy to setup the "fix" for the "Double-Hop". On the computers that you want to remote to you need to run the following commands:
Enable-PSRemoting
Enable-WSManCredSSP Server
Then on the computer you want to remote from you need to run the command:
Enable-WSManCredSSP Client –DelegateComputer [<FQDN of the server>][*]
In place of the fully qualified domain name you can put a * instead. That will allow you to send your credentials to any computer (that could be dangerous).
Now how would you work this into a script? There is a command called Invoke-Command. If you look at the parameters of Get-Help Invoke-Command -Parameter *, you'll see that it take a Credential and a Authentication. Here's how you would run a command on multiple computers.
$MyCred = Get-Credential
Invoke-Command -ComputerName Computer1,Computer2 -Credential $MyCred -Authentication Credssp -ScriptBlock {Get-ChildItem $args[0]} -ArgumentList '\\Server\Share' -ErrorAction SilentlyContinue
Now if you'll be remoting onto many machines and you know how to use Group Policy. I'd recommend setting up PSRemoting and enabling WSManCred with the Group Policy.

Powershell remote application(.cmd) deployment

I am beginner with PowerShell and struggling to get this around with the help from different sites, My requirement and scenario is
I have a windows server 2008(rktdepy) with PowerShell installed and I have packaged application with a .cmd file. When I click this .cmd file the application will be deployed.
The server name is rktdepy and I want to create a PowerShell script which will connect to other servers in the network (the server names should be picked up from a txt files) and install the application accessing the file remotely from rktdepy server. The files are not supposed to be copied to any server and should not use psxec for security reason.
So far I have used invoke and mapping the network drive but still I have issues
$Comsession = Get-content c:\adminfiles\scripts\deploy.txt | new-pssession -throttlelimit 50
Invoke-command -computername RKTDEPLY54 -scriptblock { (new-object -comobject wscript.network).mapnetworkdrive("R:", "\\rktdepy\deploy", $true) }
Invoke-command -session $comsession -scriptblock {"CMD /C r:\QR_DEPLOY.CMD"}
The above script throws error,
I dont want to use any password in the script and it should fetch the current logged in user password from rktdepy server. I is ok if the scripts prompts for a user name and password which will have admin access to all servers.
It looks like you are dealing with a couple problems. One is that the session where you map the drive is gone when you run the next Invoke-Command that uses the mapped drive. You could move that into the same script block to fix a problem like that. The second one is a "second hop" issue. See a resource like Don Jones' Secrets of PowerShell Remoting free ebook on http://powershell.org/wp/books.
Steve
I have testing the following on my machine and it is working so far. There is also another method you can try out listed below.
Method1:
1. I have txt file with a list of computers named allcomputers.txt. It contains name of machines on each line.
Machine10
Machine20
Machine30
Machine40
The deployment script (mydeploytest.ps1) which accepts Computername, Username and Password as input and creates a new PSSession and then invokes command.
param(
[string]$ComputerName,
[string]$User,
[string]$pass
)
Get-PSSEssion | Remove-PSSession
$session = New-PSSession -ComputerName $ComputerName
Invoke-Command -Session $session -ScriptBlock {
param(
[string]$ComputerName,
[string]$Username,
[string]$Password
)
$net = new-object -ComObject WScript.Network
$net.MapNetworkDrive("U:", "\\RKTDEPY\deploy", $false, $Username, $Password)
Invoke-Expression "CMD /C U:\deploy.cmd"
$net.RemoveNetworkDrive("U:")
} -args $ComputerName,$User,$pass
Get-PSSEssion | Remove-PSSession
Powershell commandline oneline to accomplish deployment task.
PS C:> Get-Content C:\scripts\allcomputers.txt | Foreach { C:\scripts\mydeploytest.ps1 $_ "yourserviceaccount" "password"}
Method2:
The help method for Invoke-Command has an example on how to solve the doublehop issue stevals is mentioning in the answer.
PS C:\> Enable-WSManCredSSP -Delegate Server02
PS C:\>Connect-WSMan Server02
PS C:\>Set-Item WSMan:\Server02*\Service\Auth\CredSSP -Value $true
PS C:\>$s = New-PSSession Server02
PS C:\>Invoke-Command -Session $s -ScriptBlock {Get-Item \\Net03\Scripts\LogFiles.ps1} -Authentication CredSSP
-Credential Domain01\Admin01
I think with little modification to method 2 you can achieve what you want.