I've been trying to create a folder on a list of vm's in Azure using powershell.
Within the VM's I can use the below which works
$c = Get-Credential -Credential domain\AdminUser
$Comp = Get-Content C:\temp\list.txt
$s = $ExecutionContext.InvokeCommand.NewScriptBlock("mkdir c:\Whatyousaying")
Invoke-Command -ComputerName $Comp -ScriptBlock $s -Credential $c
However I have tried a few things but it doesn't recognise the AzureVm path.
I have tried something like
$ComputerName = Get-AzureRmVM | select Name
$DriveLetter = "C"
$Path = "NewDirectory"
foreach ($ComputerNames in $ComputerName)
{
New-Item -Path \\
$ComputerName\$DriveLetter$\$Path -type directory -Force
}
I m missing something obvious, I'm thinking DNS not finding the servers, so Ive tried using the public ip name and address, but they failed with winRM error, but this works in Azure. I have checked using Enable-PSRemoting, which is already enabled.
Thanks in advance
You are right, create a folder for Azure VM you can use Winrm.
About enable Azure VM winrm, you should add port 5985 to Azure NSG inbound rules and add port 5985 to windows firewall inbound rules.
You can 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 create new folder, you can use invoke-command to create it:
Invoke-Command -Session $s -ScriptBlock {new-item c:\newdirectory}
Also you need to filter Azure VMs' public IP addresses with Azure PowerShell.
Here a similar case about you, via Winrm to run powershell command, please refer to it.
Related
I need to run a common PowerShell command to trigger a Group Policy Update "gpupdate" on a remote computer out of a workflow.
The workflow runs in a system user context, which do not have the local admin permissions on the clients to force a remote "gpupdate".
For that reason, I import a PowerShell credential secure string with "Import-CliXml" to run that statement in scope of a user which is local admin on the clients.
But, the command I want to use, don't support the native credential parameter. And I need to use a parameter for the remote client.
Invoke-GPUpdate -Computer $client -RandomDelayInMinutes 0
I tried many approches from the internet, but it won't work for me:
Start-Process powershell.exe -Credential $credentials -ArgumentList $ProcessCommand -WorkingDirectory $env:windir -NoNewWindow -PassThru
Start-Process powershell.exe -wait -Credential $credentials -ArgumentList "-command &{Start-Process Powershell.exe -argumentlist '$($cmnd)' -verb runas -wait}"
If I test to send the remote gpupdate out of a PowerShell console started with a user which is local admin on the remote client, it works.
Did anyone has a solution for this problem?
Many thanks!
When I connect to remote computers using PowerShell to execute commands on those computers I normally run the following. I've left an example of my code for you to use to execute Invoke-GPUpdate
#Local Host Computer
#$RequestingServer = $env:COMPUTERNAME
#Server List From Text File
#$ServerList = Get-Content 'C:\temp\servicetest\servers.txt'
#Server List In Script
$ServerList = 'Computer1','Computer2','Computer3','Computer4'
#Domain Admin Account
[STRING]$DomainAccountName = (whoami)
[STRING]$DomainAccountName = $DomainAccountName.Split("\")[1]
[STRING]$DomainAccountPassword = "Password01" #Obviously Change Password
$DomainAccountSecurePassword = $DomainAccountPassword | ConvertTo-SecureString -AsPlainText -Force
$DomainCredentials = New-Object System.Management.Automation.PSCredential -ArgumentList $DomainAccountName, $DomainAccountSecurePassword
#Local Server Admin Account
[STRING] $LocalUser = "Administrator" #Obviously Change Account
[STRING] $LocalPassword = "Password01" #Obviously Change Password
$LocalSecurePassword = $LocalPassword | ConvertTo-SecureString -AsPlainText -Force
$LocalCredentials = New-Object System.Management.Automation.PSCredential -ArgumentList $LocalUser, $LocalSecurePassword
#If running on multiple computers / servers etc. - - See Lines 5 and 8
ForEach($ComputerName in $ServerList) {
#Update Windows Something Locally - See Line 2
#$DomainSession = New-PSSession -Computername $RequestingServer -Credential $DomainCredentials
#Update Windows Something Remotely - See Lines 5 and 8
$DomainSession = New-PSSession -Computername $ComputerName -Credential $DomainCredentials
Invoke-Command -Session $DomainSession -ScriptBlock {
#Some commands need the computername currently using localhost...
$GPUpdateServer = $Using:ComputerName
#$GPUpdateServer = $Using:RequestingServer
# enter code of what you plan to do...
Invoke-GPUpdate -Computer $GPUpdateServer -RandomDelayInMinutes 0
}
} End of ForEach Statement
#If running on multiple computers / servers etc. - - See Lines 5 and 8
ForEach($ComputerName in $ServerList) {
#Update Windows Something Locally - See Line 2
#$LocalSession = New-PSSession -Computername $RequestingServer -Credential $LocalCredentials
#Update Windows Something Remotely - See Lines 5 and 8
$LocalSession = New-PSSession -Computername $ComputerName -Credential $LocalCredentials
Invoke-Command -Session $LocalSession -ScriptBlock {
#Some commands need the computername currently using localhost...
$GPUpdateServer = $Using:ComputerName
#$GPUpdateServer = $Using:RequestingServer
# enter code of what you plan to do...
Invoke-GPUpdate -Computer $GPUpdateServer -RandomDelayInMinutes 0
}
} End of ForEach Statement
Facing this problem more in detail, I tested the approach above with the remote PowerShell session. This needs some more preparation in domain for deploying all necessary GPO settings to all clients to make WinRM work.
The remote PowerShell approach works, but I found out that the Invoke-GPUpdate command is only available on clients which have RSAT installed. So only works on a few in clients in IT department.
$Session = New-PSSession -Computername $clientname -Credential $domainAccountWithLocalAdminRights
Invoke-Command -Session $Session -ScriptBlock { Invoke-GPUpdate -Computer $env:ComputerName -RandomDelayInMinutes 0 }
$Session | Remove-PSSession
I switched over to a different approach which worked for me without using remote PS sessions. Completely silent on the client, you will find the triggered gpupdates only in Windows event viewer.
Invoke-Command -ComputerName $clientname -ScriptBlock { gpupdate } -Credential $domainAccountWithLocalAdminRights
Using this Powershell script I try to write and read a variable on VM from host.
$Username = 'administrator'
$Password = 'password'
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$pass
#Added value to a variable on VM
Invoke-Command -VMName VM_Windows_2016 -Credential $Cred -ScriptBlock {$InstallPath="C:\Install\install-1.ps1"}
#Trying to read the variable on VM but with no result
Invoke-Command -VMName VM_Windows_2016 -Credential $Cred -ScriptBlock {Write-Host($InstallPath)}
As you see the result is empty. Can anyone help me to show how to write and read an variable on VM from host machine? Thanks!
When using Invoke-Command to run a command remotely, any variables in the command are evaluated on the remote computer. So when you run the first Invoke-Command you are only defining the variable $InstallPath and terminating the remote PS session. When you are run the Invoke-Command second time it create entirely new PS session, hence InstallPath would be null. Instead of this you can define and read the variable in a single Cmdlet like this.
$remoteScriptblock = {
$InstallPath = "C:\Install\install-1.ps1"
Write-Host($InstallPath)
}
Invoke-Command -VMName VM_Windows_2016 -Credential $Cred -ScriptBlock $remoteScriptblock
If you still want to run this in multiple Cmdlets you may consider Run a command in a persistent connection
Good evening,
I'm trying to write a Powershell script that will connect to a remote server via SCP and upload or download files/folders. Ultimately this is the script that I would like Jenkins to run.
So far I'm using Posh-SSH and having good success. The only issue is, no matter what I have tried so far, it will always prompt me for my credentials. This, obviously, makes it not entirely automatic.
I have attached a few things I've tried. Hopefully someone can help me out with this!
The basic command I'm testing with:
get-scpfolder -computername '111.111.111.111' -credential $credential
-remotefile "/var/myFolder" -localfile 'C:\Users\Me\destFolder'
Again, this works, but it requires me to enter my credentials.
I saw this command online:
$Password = "pass"
$User = "admin"
$ComputerName = "111.111.111.111"
$Command = "get-scpfolder -computername $ComputerName -credential $Credentials -localfolder 'C:\Users\Me' -remotefolder '/var/destFolder"
$secpasswd = ConvertTo-SecureString $Password -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential($User, $secpasswd)
$SessionID = New-SSHSession -ComputerName $ComputerName -Credential $Credentials #Connect Over SSH
Invoke-SSHCommand -Index $sessionid.sessionid -Command $Command # Invoke Command Over SSH
However this returns ExitStatus 1 and nothing happens. I have tried a few variations of the $Command including the credentials or not, for example, and I can't get any of it to work.
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
I struggle a lot of time regarding this problem now and asked already in another forum, which helped to approach to the solution but finally I didn't achieve it.
I "simply" need to gather information about hosts inside clouds here in our company with the help of a powershell script. You can reach the clouds via a jumphost from the local network, the jumphost is a part of the cloud as well. Then from the jumphost you can reach all cloudhosts.
So I have tried this with 2 pssessions and used invoke-command (same password for jumphost and cloudhost):
$cred = Get-Credential ad\username -Message "Please insert the password for the jumphost and the cloudhost"
$session = New-PSSession -ComputerName jumphost -Credential $cred
$cldhost = Read-Host "Please insert the name of the cloudhost"
$script = {
Param (
$Credential,
$cloudhost
)
$ses = New-PSSession -ComputerName $cloudhost -Credential $Credential
Invoke-Command -Session $ses -ScriptBlock { Get-ChildItem C:\ }
Remove-PSSession $ses
}
Invoke-Command -Session $session -ScriptBlock $script -ArgumentList $cred, $cldhost
Remove-PSSession $session
But this always gives me the output of C:\ of the jumphost and not of the cloudhost.
In the other forum I was advised to use credssp or delegated sessions.
CredSSP is not possible here, because I get the error that the SPN is missing in the AD-account and I'm not allowed to add one and the delegated sessions don't help me, because I have admin rights on the jumphost and the cloudhost and don't need to delegate something.
But anyway I think it's not a problem of the credentials, because I get no "Access denied" error or something else and enter-pssession to the jumphost and from there invoke-command to the cloudhost works without a problem, but I can't use this in a script.
Something seems to be wrong in the logic of the nested pssessions code...
Do you have any idea to make this work proper here?
delegated admin rights:
http://blogs.technet.com/b/heyscriptingguy/archive/2014/04/03/use-delegated-administration-and-proxy-functions.aspx
CredSSP:
http://blogs.technet.com/b/heyscriptingguy/archive/2012/11/14/enable-powershell-quot-second-hop-quot-functionality-with-credssp.aspx
Thanks a lot,
Marc
By the way:
I've tried to use CredSSP, because it is recommend to use it for second hops:
Enable-WSManCredSSP -Role Client -DelegateComputer jumphost -Force
$cred = Get-Credential ad\username -Message "Please insert the password for the jumphost and the cloudhost"
$session = New-PSSession -ComputerName jumphost -Credential $cred
Invoke-Command -Session $session -ScriptBlock {Enable-WSManCredSSP -Role Server –Force; Set-Item wsman:\localhost\client\trustedhosts -value localcomputer -Force; Restart-Service winrm -Force}
$session2 = new-PSSession -ComputerName jumphost -Credential $cred -Authentication Credssp
After entering this last command I get the following error:
The WinRM client cannot
process the request. A computer policy does not allow the delegation of the user credentials to the target computer because the
computer is not trusted. The identity of the target computer can be verified if you configure the WSMAN service to use a valid
certificate using the following command: winrm set winrm/config/service '#{CertificateThumbprint="<thumbprint>"}' Or you can
check the Event Viewer for an event that specifies that the following SPN could not be created: WSMAN/<computerFQDN>. If you find
this event, you can manually create the SPN using setspn.exe . If the SPN exists, but CredSSP cannot use Kerberos to validate
the identity of the target computer and you still want to allow the delegation of the user credentials to the target computer,
use gpedit.msc and look at the following policy: Computer Configuration -> Administrative Templates -> System -> Credentials
Delegation -> Allow Fresh Credentials with NTLM-only Server Authentication. Verify that it is enabled and configured with an SPN
appropriate for the target computer. For example, for a target computer name "myserver.domain.com", the SPN can be one of the
following: WSMAN/myserver.domain.com or WSMAN/*.domain.com. Try the request again after these changes. Weitere Informationen
finden Sie im Hilfethema "about_Remote_Troubleshooting".
In Zeile:1 Zeichen:13
+ $session2 = new-PSSession -ComputerName jumphost -Credential $cred -Aut ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (System.Manageme....RemoteRunspace:RemoteRunspace) [New-PSSession], PSRemotingTransportE
xception
+ FullyQualifiedErrorId : -2144108124,PSSessionOpenFailed
I do not know what to avtivate further to use CredSSP, anyway it would be better to make it work without CredSSP.
Ok additionally:
It should work with delegated sessions, I have tried the following:
on the Jumphost:
Register-PSSessionConfiguration -Name PowerShell.Session -SessionType DefaultRemoteShell -AccessMode Remote -RunAsCredential 'ad\username' -ShowSecurityDescriptorUI –Force
And then granted access to the user 'ad\username' (Invoke and Read access).
After that I was able to use the session configuration on the jumphost with the follwoing commands:
$cred = Get-Credential ad\username -Message "Please enter the password for jumphost"
$session = New-PSSession -ConfigurationName PowerShell.Session -ComputerName jumphost -Credential $cred
So the session was connected and I entered my other commands:
$cldhost = Read-Host "Please enter the cloudhost name"
$script = {
Param (
$Credential,
$Hostname2
)
$ses = New-PSSession -ComputerName $Hostname2 -Credential $Credential
Invoke-Command -Session $ses -ScriptBlock { Get-ChildItem C:\ }
Remove-PSSession $ses
}
Invoke-Command -Session $session -ScriptBlock $script -ArgumentList $cred, $cldhost
Remove-PSSession $session
Unfortunately I get the output of Get-ChildItem C:\ of the jumphost again and not the output of the cloudhost...
Do you have any further idea? Is maybe the $script{} part somewhere wrong?
Finally it works:
$cred = Get-Credential ad\username -Message "Please insert the password for the jumphost"
$session = New-PSSession -ComputerName jumphost -Credential $cred
$cldhost = Read-Host "Please insert the cloudhost name"
$script = {
Param (
$Credential,
$Hostname2
)
$ses = New-PSSession -ComputerName $Hostname2 -Credential $Credential
Invoke-Command -Session $ses -ScriptBlock { Get-ChildItem C:\ }
Remove-PSSession $ses
}
Invoke-Command -Session $session -ScriptBlock $script -ArgumentList $cred, $cldhost
Remove-PSSession $session
This means I do not need the delegated sessions or CredSSP. But anyway, it works as well by manual setting the delegated configuration on the jumphost and then adding the users who should be able to connect to the session configuration in the pop-up -ShowSecurityDescriptorUI and delete the default users "interactive user" and local administrators:
Register-PSSessionConfiguration -Name PowerShell.Session -SessionType DefaultRemoteShell -AccessMode Remote -RunAsCredential 'ad\username' -ShowSecurityDescriptorUI –Force
If you now connect to the session configuration with a above specified user the commands will be executed in context of the user you have specified under -RunAsCredential.
It is also working directly from the local host, but you have to use -SecurityDescriptorSddl and this requires a function which deletes the default credentials for the session configurations and adds the new credential with ACLs automatically...means a lot of work.
Thanks a lot for the help!
Marc