Issue while joining vm to a domain using invoke-vmscript - powershell

I am trying to join a vm to a domain. Here is the script:
Invoke-VMScript -vm $hostName -GuestUser $VMLocalUser -GuestPassword $VMLocalPWord -ScriptType Powershell "Add-Computer -ComputerName $hostName -LocalCredential $VMLocalCredential -DomainName $domainName -Credential $VMLocalCredential -Restart -Force"
While executing the script freezes at 0% completion. Please let me know if am doing something wrong.

Running that add-computer command on the machine, I had trouble getting the ComputerName command to recognise which lead me to this
Issue Adding PC to domain and changing name at the same time
Alternatively use netdom.
Invoke-VMScript -VM $vmname -GuestUser $VMLocalUser -GuestPassword $VMLocalPWord -ScriptType Powershell "netdom join /d:mywork.domain computername /userd:domainaccount /passwordd:pwd"

Related

Executing CMD or EXE file using PSSession (remote powershell) caused Error 1603 access denied

I have the following script powershell command but it returns access denied. I assume the Error 1603 is caused by remote accessing the server. However, the $username has admin rights in the computer01 server.
To recheck if my hunch was right, I tried to test with the following and I got access denied:
Start-Process cmd -Credential $Cred
Update
The error was due to the $Cred . Removing the -Credential argument works fine.
End of Update
The commands have no problems executing directly in the computer01 machine using the cmd.exe.
I want to use cmd /c in this case as I need to get the real exit code from the SETUP.EXE installer.
See full script below:
$script = {
#Param(
# [String]$username,
# [String]$password
#)
# $Cred = New-Object System.Management.Automation.PSCredential ($username, $password)
$respfile = "$env:TEMP\test.resp"
echo 'key=value' > $respfile
$username = "$env:USERDOMAIN\$env:USERNAME"
Write-Host Hello $username
$Creds = (Get-Credential -Credential "$env:USERDOMAIN\$env:USERNAME" )
Start-Process cmd -Credential $Creds
#This command cannot be run due to the error: Access is denied.
# + CategoryInfo : InvalidOperation: (:) [Start-Process], #InvalidOperationException
# + FullyQualifiedErrorId : #InvalidOperationException,Microsoft.PowerShell.Commands.StartProcessCommand
# + PSComputerName : computer01
# cmd /c "$path\SETUP.EXE /INSTALL -s /RESPFILE:'$respfile'"
runas /user:$Username "SETUP.EXE" /INSTALL -s /RESPFILE:"$respfile"
echo $LASTEXITCODE
# Error 1603
}
#$username = 'domain/user'
#$password = 'password'
$server = 'computer01'
$Creds = New-Object System.Management.Automation.PSCredential
$session = New-PSSession -ComputerName $server
#Invoke-Command -Session $session -Scriptblock $script -Argumentlist $username, $password
Invoke-Command -Session $session -Scriptblock $script -Credential $Creds #updated based on #postanote advise
Remove-PSSession -ComputerName $server
I have found the following similar link install-remotely but do not want to use the ENTER-PSSession command. I do not want to exit the current PSSession and remotely join again in server just to install then exit.
Any suggestions how to use only PSSession and successfully executing installers in the remote server?
As one mentioned in the comments, you don't need cmd.exe. You can use the call/invocation operator - & - to specify that the next token on the line is a command:
& "$path\SETUP.EXE" /INSTALL -s /RESPFILE:$respfile
Of course, for this to work, the parameters to SETUP.EXE need to be correct (I don't know whether that's the case or not).
Never pass plain text passwords in scripts. It exposes you to uneeded risks.
Use proper secured credentials models.
• Working with Passwords, Secure Strings and Credentials in Windows PowerShell
• quickly-and-securely-storing-your-credentials-powershell
PowerShell remoting requires the use of an implicit (New-PSSession) or explicit (Enter-PSSession) session.
• About Remote Requirements
There are only a handful of cmdlets you can use as non-Admin ir run without PSRemoting enabled.
• Tip: Work Remotely with Windows PowerShell without using Remoting or WinRM
As noted in the Powershell Help file | MS Docs link above, with PSRemoting, you must be using an account that is an admin on the remote host.
In Windows OS proper, to install software, you must be an admin and running that in an admin session.
PowerShell runs in the context of the user who started it.
If you are trying to run in another user context, that is a Windows Security boundary, and you cannot do that without PowerShell natively, you'd need other tools like MS Sysinternals PSExec. See also:
Find-Module -Name '*Invoke*' | Format-Table -AutoSize
# Results
<#
Version Name Repository Description
------- ---- ---------- -----------
...
3.1.6 Invoke-CommandAs PSGallery Invoke Command as System/User on Local/Remote computer using ScheduleTask.
...
#>
Try this refactored option...
$script = {
$Creds = (Get-Credential -Credential "$env:USERDOMAIN\$env:USERNAME" )
$respfile = 'whatever this is'
& "SETUP.EXE /INSTALL -s /RESPFILE:'$respfile'"
Write-Output $LASTEXITCODE
}
$server = 'computer01'
$session = New-PSSession -ComputerName $server
Invoke-Command -Session $session -Scriptblock $script -Credential $Creds
Remove-PSSession -ComputerName $server
Details
# Get specifics for a module, cmdlet, or function
(Get-Command -Name Invoke-Command).Parameters
(Get-Command -Name Invoke-Command).Parameters.Keys
Get-help -Name Invoke-Command -Examples
# Results
<#
Invoke-Command -ComputerName server01 -Credential domain01\user01 -ScriptBlock {Get-Culture}
$s = New-PSSession -ComputerName Server02 -Credential Domain01\User01
$LiveCred = Get-Credential
Invoke-Command -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.exchangelabs.com/PowerShell -Credential $LiveCred -Authentication Basic
Invoke-Command -Session $s -ScriptBlock { Get-HotFix } -SessionOption $so -Credential server01\user01
Enable-WSManCredSSP -Delegate Server02
Set-Item WSMan:\Server02*\Service\Auth\CredSSP -Value $True
Invoke-Command -Session $s -ScriptBlock {Get-Item \\Net03\Scripts\LogFiles.ps1} -Authentication CredSSP -Credential Domain01\Admin01
#>
Get-help -Name Invoke-Command -Full
Get-help -Name Invoke-Command -Online
So, I was able to solve my problem.
1603 is the error thrown by the setup.exe.
Just to be sure, I manually executed first the following directly in the server using CMD and it was working!
$path\SETUP.EXE /INSTALL -s /RESPFILE:'$respfile'
I did a lot of testings. Researched and as mentioned from comments above, I did different ways to execute programs using powershell. I even used ACL to change ownership of installer directory/ files, switching to different user accounts (with different priviledges) but still getting access denied (including the Admin account).
It took days before I realized the difference in output file size of manual run in machine and the remote. The cause was the $respfile. It really is worth checking every possible reason/ scenario why there's access denied. Plus I cannot extract the setup.exe and its contents to troubleshoot.
The $respfile was created via powershell. I noticed the size created by powershell is doubled compared to a CMD size that was needed. With that, I assumed that the setup.exe reads file in UTF-8 format. I only know that it's working when triggered via CMD and not via powershell.
I suddenly bumped on this links differrent Powershell and CMD sizes and convert file content to CMD readable file - utf8. After converting the $respfile to UTF-8 format, I was able to run the exe successfully.
Hopefully, this can help others too!

Powercli script to join computer to the Domain

I'm tring to run Powercli script from VM that have all the modules nedded.
The script should insert other VM to domain.
$ScriptText ="Add-Computer -DomainName foofoo.com -DomainCredential " + $DomainC +" -OUPath 'OU=CACI,OU=Computers,OU=bla,OU=Regions,DC=bla,DC=com'"
echo $Script
Invoke-VMScript -vm $VMName -GuestCredential $AdminC -ScriptText $ScriptText
all the variables inserted correctly.
runing
Add-Computer -DomainName foofoo.com -DomainCredential $DomainC -OUPath 'OU=CACI,OU=Computers,OU=bla,OU=Regions,DC=bla,DC=com'
from the other vm poweshell console is running well and the output message WARNING: The changes will take effect after you restart the computer ..
$Script return:
Add-Computer -DomainName foofoo.com -DomainCredential System.Net.NetworkCredential -OUPath 'OU=CACI,OU=Computers,OU=bla,OU=Regions,DC=bla,DC=com'
but after that this script stuck and I have no error or other output.
Any idea what is the reason for that ?
The Add-Computer CMDlet takes a credential object for the domain credential parameter. By trying to convert that to a string in your $scripttext variable - you're losing the credential type in the conversion. You need to make a credential object inside your script text rather than passing in a variable containing the credential object. This adds some complexity because you generally want to pull a password from a secure vault. The below examples shows how to include the password as a plain text - but this isn't really advised for obvious reasons.
$scripttext = #'
$user = "UserName"
$password = ConvertTo-SecureString "bar" -AsPlainText -Force
$DomainC = New-Object PSCredential $user, $password
Add-Computer -DomainName foofoo.com -DomainCredential $DomainC -OUPath 'OU=CACI,OU=Computers,OU=bla,OU=Regions,DC=bla,DC=com'
'#
Invoke-VMScript -vm $VMName -GuestCredential $AdminC -ScriptText $ScriptText

You have modified the global:DefaultVIServer and global:DefaultVIServers system variables. This is not allowed. Invoke-VMScript

I am trying to run Invoke-VMScript inside a PowerShell workflow. The below code is working:
function Test-Workflow {
Connect-VIServer -Server 1.2.3.4 -Username admin -Password password123
# Invoke VMScript..
Invoke-VMScript -VM myVirtualMachine01 -GuestUser 'administrator' -GuestPassword password123 -ScriptText ls c:\
}
The above works correctly. However running as a workflow:
workflow Test-Workflow {
Connect-VIServer -Server 1.2.3.4 -Username admin -Password password123
# Invoke VMScript..
Invoke-VMScript -VM myVirtualMachine01 -GuestUser 'administrator' -GuestPassword password123 -ScriptText ls c:\
}
I get the error:
You have modified the global:DefaultVIServer and
global:DefaultVIServers system variables. This is not allowed. Please
reset them to $null and reconnect to the vSphere server.
What am I doing wrong?
PowerCLI used in conjunction with PoSh Workflows does some very odd things.
To work around some of the oddness, connect to the vCenter server prior to running the workflow and then pass the session secret through to the workflow.
For more detailed information, check out this blog post: http://www.lucd.info/2015/03/17/powercli-and-powershell-workflows/

Set-VMDvdDrive does not set my ISO media

I'm currently working on a task to mount my daily build image to a list of VMs by using powershell script Set-VMDvdDrive.
The problem is if I write the following code the image file will be mounted:
Invoke-Command –ComputerName HyperVHostName -Credential Get-Credential –ScriptBlock{Set-VMDvdDrive -VMName myVM -Path G:\build.ISO}
But if I use a variable then the image file will not be mounted and the code does not throw any expceptions like this:
$isoFile = "G:\build.ISO"
Invoke-Command –ComputerName HyperVHostName -Credential Get-Credential –ScriptBlock{Set-VMDvdDrive -VMName myVM -Path $isoFile}
Thanks guys in advance.

Azure Runbooks - Missing PowerShell Cmdlets Or Not Executing Against a VM

I need to execute PowerShell on VMs from an Azure Automation Runbook, akin to a WinRm execution/PowerShell Remoting.
I have created an Azure Runbook through the Azure Automation GUI, and am trying to run a script that works perfectly against physical and virtual machines to get key system information and ports. I am able to authenticate in Azure and it appears that I can execute some aspects of the script (unless it's only running against the Azure Automation Worker) via the Azure Runbook, such as getting the installed PowerShell Version of the targeted VMs using: $PSVersionTable.PSVersion so I am not having issues with security/access from what I can tell.
However, several other components fail as follows, and I don't know if I need to import a Module to Azure Automation and if so, which ones. Or if this is failing because it is running against the Worker and not the VMs.
Here are some of the code snippets I am running:
$computerSystem = Get-CimInstance Win32_ComputerSystem
"CPU: " + $computerCPU.Name
Get-WmiObject -Class Win32_LogicalDisk |
Where-Object {$_.DriveType -ne 5} |
Sort-Object -Property Name |
Select-Object Name, VolumeName, FileSystem, Description, `
#{"Label"="DiskSize(GB)";"Expression"={"{0:N}" -f ($_.Size/1GB) -as [float]}}, `
#{"Label"="FreeSpace(GB)";"Expression"={"{0:N}" -f ($_.FreeSpace/1GB) -as [float]}}, `
#{"Label"="%Free";"Expression"={"{0:N}" -f ($_.FreeSpace/$_.Size*100) -as [float]}} |
Format-Table -AutoSize
Get-NetAdapter -Name "*" | Format-Table
Get-NetOffloadGlobalSetting | Format-List
Test-NetConnection -Port 80
Here are the error messages, which I strongly suspect are EITHER due to missing PowerShell Modules that I need to upload, but am unsure where to find these OR is this a situation where I am not targeting the VM correctly and instead running this against the AZ Host? (if so, any good examples of how to target a single VM):
Get-CimInstance : The specified service does not exist as an installed
service.
Get-WmiObject : The specified service does not exist as an installed
service.
Get-NetAdapter : The term 'Get-NetAdapter' is not recognized as the
name of a cmdlet, function, script file, or operable program.
Get-NetOffloadGlobalSetting : The term 'Get-NetOffloadGlobalSetting'
is not recognized as the name of a cmdlet, function, script file, or
operable program.
Test-NetConnection : The term 'Test-NetConnection' is not recognized
as the name of a cmdlet, function, script file, or operable program.
If it is an issue with targeting the VM properly, I need some guidance. I suspect that I am targeting the Worker running the Runbooks and not the actual VMs. I am using the RunAs account/the new Azure Automation security methods (not classic) so I don't believe certificates come into play. Here is how I am trying to target the VM (which I suspect is incorrect/should be changed):
$Resources = Get-AzureRmResource -ResourceType "Microsoft.Compute/virtualMachines" -ResourceGroupName "MyTestGroup" -ResourceName "MyTestVM"
ForEach ($Resource in $Resources)
{
# PowerShell Code from Above here
}
UPDATE 1:
Now that we have determined that I am not targeting the VM properly, I tried Joe's recommendation, but when I try to run the following I get an error on the WinRm. I found the Connect-AzureVM.ps1, but am unsure if this is old or aligns to the newer RunAs Connection I am using. Here is my current script that attempts to connect to the VM and Invoke PowerShell.
param(
[parameter(Mandatory=$true)][String] 'https://myvmname.eastus.cloudapp.azure.com:5986,
[parameter(Mandatory=$true)][String] 'MyVMName'
)
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
# Get credentials to Azure VM
$Credential = Get-AutomationPSCredential -Name $VMCredentialName
Invoke-Command -ConnectionUri $Uri -Credential $Credential -ScriptBlock {
# My PowerShell Here
}
This is the error the script produces. I suspect its because I need to import/create a WinRM certificate on the VM I am targeting, but unsure if the Connect-AzureVM.ps1 is the right script to use or if there is another/more updated method to use for WinRM access:
[myvmname.eastus.cloudapp.azure.com] Connecting to remote server
myvmname.eastus.cloudapp.azure.com failed with the following error
message : WinRM cannot complete the operation. Verify that the
specified computer name is valid, that the computer is accessible
over the network, and that a firewall exception for the WinRM service
is enabled and allows access from this computer. By default, the
WinRM firewall exception for public profiles limits access to remote
computers within the same local subnet. For more information, see the
about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (myvmname.eastus.cloudapp.azure.com:String) [],
PSRemotingTransportException
+ FullyQualifiedErrorId : WinRMOperationTimeout,PSSessionStateBroken
Run this inside the VM at an elevated prompt
https://gist.github.com/jeffpatton1971/2321f0db8025e48ad8ec13c243153045
From inside your Runbook do whatever you normally to wire it up but create some session options to pass along your invoke-command.
$SessionOption = New-PSSessionOption -SkipCACheck -SkipCNCheck
Invoke-Command -ComputerName $VMname -Credential $Credential -UseSSL -SessionOption $SessionOption -ScriptBlock { }
You need to either add the VMs you want to run these scripts on as Azure Automation hybrid workers, so that you can target the script to run on them, or you need to, from your runbook running on Azure Automation's own workers, remote into each VM and from within the remoting block run the commands.
For the former, see: https://learn.microsoft.com/en-us/azure/automation/automation-hybrid-runbook-worker
For the ladder:
Invoke-Command -ConnectionUri $Uri -Credential $Credential -ScriptBlock {
$computerSystem = Get-CimInstance Win32_ComputerSystem
"CPU: " + $computerCPU.Name
Get-WmiObject -Class Win32_LogicalDisk |
Where-Object {$_.DriveType -ne 5} |
Sort-Object -Property Name |
Select-Object Name, VolumeName, FileSystem, Description, `
#{"Label"="DiskSize(GB)";"Expression"={"{0:N}" -f ($_.Size/1GB) -as [float]}}, `
#{"Label"="FreeSpace(GB)";"Expression"={"{0:N}" -f ($_.FreeSpace/1GB) -as [float]}}, `
#{"Label"="%Free";"Expression"={"{0:N}" -f ($_.FreeSpace/$_.Size*100) -as [float]}} |
Format-Table -AutoSize
Get-NetAdapter -Name "*" | Format-Table
Get-NetOffloadGlobalSetting | Format-List
Test-NetConnection -Port 80
}