Pre/Post patching scripts - Run script and get output from VM - windows

I want to run Pre/Post patching Powershell scripts with Azure Automaton account and get an output of the command which ran Inside the VM, i.e. "Get-service"
I just followed instructions on Microsoft: https://learn.microsoft.com/en-us/azure/automation/update-management/pre-post-scripts#interact-with-machines
and their script:
https://github.com/azureautomation/update-management-run-script-with-run-command
Additionally I've found a way to run command and it's executing on VM, but NO Output.
$ServicePrincipalConnection = Get-AutomationConnection -Name 'AzureRunAsConnection'
Add-AzAccount -ServicePrincipal -TenantId $ServicePrincipalConnection.TenantId -ApplicationId $ServicePrincipalConnection.ApplicationId -CertificateThumbprint $ServicePrincipalConnection.CertificateThumbprint
$rgname ="raimundas-rg"
$vmname ="test-win-vm1"
$ScriptToRun =
#"
get-service "wuauserv"
"#
Out-File -InputObject $ScriptToRun -FilePath ScriptToRun.ps1
Invoke-AzVMRunCommand -ResourceGroupName $rgname -Name $vmname -CommandId 'RunPowerShellScript' -ScriptPath ScriptToRun.ps1
Remove-Item -Path ScriptToRun.ps1
However it did not did the trick since it's using old AZrm cmdlet. and did not get output in logs. any suggestions how to run scripts on multiple Azure VMs and get output?

Related

Having issue outputting the results of script to .txt file in Powershell

New to scripting, currently trying to write a script that will Invoke command to every computer located within domain. My issue is I am trying to direct the output of each computer to a text file.
# Name:
# Date: 02/10/2023
# Desc: Runs remote commands for every computer within domain to collect general information
#Defining variable that reads the computer names from the .txt file
$ADCS = Get-Content -Path "C:\computers.txt"
# Loop through each computer name in the list
foreach ($ADC in $ADCS) {
# Run the Invoke-Command cmdlet for each computer
Invoke-Command -ComputerName $ADC -ScriptBlock {
# Write message to indicate which computer commands are being run on.
Write-Output "Running command on $ADC"
#systeminfo | find "Host Name"
Get-computerinfo
out-file -FilePath C:\Users\aembrey\Documents\ComputerInfo.txt
}
} | out-file -FilePath C:\Users\aembrey\Documents\ComputerInfo.txt
This is what I am currently working with. I have tried multiple difference ways of using Out-file and have failed to redirect the output.
I tried formatting the command like you would as a standard command
"get-computerinfo | out-file -filepath C:\Users\X\X"
But I receive "An empty pipe element is not allowed." error.
I am sure this is a simple issue, but I am stumped.
Basically just trying to get the computer info of all computers, then save it to a text file.

Running UserData with Powershell >= 7.0 on Windows Server 2022 on EC2

UserData by default will run with Powershell V5.1 on the Windows Server 2022 AMI on an AWS EC2 instance that spins up. However, I want to use some cmdlets that are only supported in Powershell version 7 and greater.
How am I best able to run a script with Powershell 7+ when booting the instance with UserData?
I currently have a script that installs powershell 7, but then from that point I am not sure how to use v7 to run the rest of the commands that I have.
Invoke-WebRequest -Uri https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/PowerShell-7.3.1-win-x64.msi -OutFile PowerShell.msi
Start-Process msiexec.exe -ArgumentList '/i PowerShell.msi /quiet' -Wait
I am using the WINDOWS_SERVER_2022_ENGLISH_FULL_BASE AMI.
I have tried using something like Invoke-Expression, and also have tried to get the script to call itself recursively with some conditionals, e.g.
# First Run with ps 5.1
if ($PSVersionTable.PSVersion -lt [Version]"7.0") {
Invoke-WebRequest -Uri https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/PowerShell-7.3.1-win-x64.msi -OutFile PowerShell.msi
Start-Process msiexec.exe -ArgumentList '/i PowerShell.msi /quiet' -Wait
cd "C:\Program Files\PowerShell\7"
# Run this same script with ps7
./pwsh $PSCommandPath
exit
}
#
if ($PSVersionTable.PSVersion -gt [Version]"7.0") {
# Do the things I need to do with ps7...
}
Both of my attempts have been silently failing, and with ec2 userdata it is very hard to get info on why.
The approach that ended up working was to have 2 different scripts. The first script installs PS7, and then downloads the second script from S3 and executes it using PS7.
User Data exectued with PS5:
#init.ps1
<powershell>
Invoke-WebRequest -Uri https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/PowerShell-7.3.1-win-x64.msi -OutFile PowerShell.msi
Start-Process msiexec.exe -ArgumentList '/i PowerShell.msi /quiet' -Wait
cd "C:\Program Files\PowerShell\7"
mkdir (Split-Path -Path 'C:/temp/setupGateway.ps1' ) -ea 0
Read-S3Object -BucketName 'my-bucket' -key 'setupGateway.ps1' -file 'C:/temp/setupGateway.ps1' -ErrorAction Stop
& "C:\Program Files\PowerShell\7\pwsh" "C:\temp\setupGateway.ps1"
</powershell>
<persist>true</persist>
PS7 script, executed separately:
# setup.ps1
Write-Output $PSVersionTable
Write-Output "Hello from PS7"
All that needs to happen to make this work is to make sure that you copy the setup.ps1 script to an S3 location. Which can be achieved in lots of different ways depending on the rest of your setup.

PowerShell Invoke-Command with Start-Process outputs different result

I have an update script for running the Dell Command Update tool. In short dcu-cli.exe. The thing now is than when i run the same script code on the computer local then everything runs OK but when i run the exact same code in a script with invoke-command(and yes i have full admin rights) than the exitcode is 2 meaning An unknown application error has occurred instead of 0 (everything OK)
It is a very large script so i created a new one to debug this. This is the shorted code:
Invoke-Command -ComputerName "MyComputer" -ScriptBlock {
$ExitCode = 0
#Declare path and arguments
$DcuCliPath = 'C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe'
$DellCommand = "/applyUpdates -autoSuspendBitLocker=enable -outputLog=C:\Dell_Update.log"
#Verify Dell Command | Update exists
If (Test-Path -Path $DcuCliPath) {
$objWMI = Get-WmiObject Win32_ComputerSystem
Write-Host ("Dell Model [{0}]" -f $objWMI.Model.Trim())
$serviceName = "DellClientManagementService"
Write-Host ("Service [{0}] is currently [{1}]" -f $serviceName, (Get-Service $serviceName).Status)
If ((Get-Service $serviceName).Status -eq 'Stopped') {
Start-Service $serviceName
Write-Host "Service [$serviceName] started"
}
#Update the system with the latest drivers
Write-Host "Starting Dell Command | Update tool with arguments [$DellCommand] dcu-cli found at [$DcuCliPath]"
$ExitCode = (Start-Process -FilePath ($DcuCliPath) -ArgumentList ($DellCommand) -PassThru -Wait).ExitCode
Write-Host ("Dell Command | Update tool finished with ExitCode: [$ExitCode] current Win32 ExitCode: [$LastExitCode] Check log for more information: C:\Dell_Update.log")
}
}
When i remove the Invoke-Command -ComputerName "MyComputer" -ScriptBlock { and then copy + run the script local on the PC then the exitcode = 0
What i also noticed than when i run the command via 'Invoke-Command' then there is also no log file created as i passed along in the arguments... So my best guess is something is going wrong with local an remote paths?
So what am i missing? I'm guessing it is something simple but i spend several hours to get this running without any luck...
Try running it this way. You should be able to see any output or error messages. I typically add to the path first rather than using & or start-process.
invoke-command mycomputer {
$env:path += ';C:\Program Files (x86)\Dell\CommandUpdate';
dcu-cli /applyUpdates -autoSuspendBitLocker=enable -outputLog=C:\Dell_Update.log }
Using start-process inside invoke-command seems pretty challenging. I can't even see the output of findstr unless I save it to a file. And if I didn't wait the output would be truncated. By default start-process runs in the background and in another window. There's a -nonewwindow option too but it doesn't help with invoke-command.
invoke-command localhost { # elevated
start-process 'findstr' '/i word c:\users\joe\file1' -wait -RedirectStandardOutput c:\users\joe\out }
#js2010, thanks for your additional help. Unfortunately this didn't helped either.
So i did some more debugging and it turns out it was a bug in the dcu-cli version running on my test machine, DOH...!!
On the test machine version 3.1.1 was running and on another machine version 4.0 was running and that worked fine via remote Powershell. So i looked for the release notes, which i found here: https://www.dell.com/support/kbdoc/000177325/dell-command-update
And as you can see in version 3.1.3 there was this fix:
A problem was solved where dcu-cli.exe was not executed in an external interactive session of PowerShell.

Remote Installation of Python using Powershell fails using Invoke-Command

I am trying to use this script to install Python on the remote computer. If I run this file directly on the server. This is the Python_Pip_Proxy_PyWinAuto.ps1 file. It works.
Set-ExecutionPolicy -ExecutionPolicy Unrestricted
Write-Host("Hi")
$installer="C:\temp\python-3.6.2.exe"
& $installer /quiet PrependPath=1 InstallAllUsers=1 TargetDir="C:\Python36"
However if I run the Invoke-Command using the following script to run this remotely on the same server, It print's the Hi message so I know that the file is running but Python doesn't get installed.
# Getting the list of servers from a .txt file to an array #
$SRVListFile = "C:\Scripts\ServerList.txt"
$SRVList = Get-Content $SRVListFile -ErrorAction SilentlyContinue
# Copying the .exe file from a shared location to each server in the array #
# Invoking the .ps1 file which runs natively on each server #
Foreach($computer in $SRVList) {
Get-Service remoteregistry -ComputerName $computer | start-service
Copy-item -Path "E:\Software\python-3.6.2.exe" -Destination \\$computer\c$\temp -Recurse
Copy-item -Path "C:\My Files\Work\Episode 003 - MongoDB Back Up\Python_GUI.py" -Destination \\$computer\c$\temp -Recurse
Invoke-Command -ComputerName $computer -FilePath "C:\My Files\Work\Episode 003 - MongoDB Back Up\Python_Pip_Proxy_PyWinAuto.ps1"
}
What is going wrong. What should I change the code to?
Try using the -scriptblock {Your command here} parameter to execute the command inside the scriptblock parenthesis on the remote computer.
Perhaps you can do it like
$Scriptblock = {
PowerShell -file "C:\My Files\Work\Episode 003 - MongoDB Back Up\Python_Pip_Proxy_PyWinAuto.ps1"
"This is Working" | out-file "C:\Hi.txt"
}
Invoke-Command -ComputerName $computer -Scriptblock $Scriptblock
You might want to remove the Write-Host "Hi" part because that gives the script an interactive nature. If you want to check for execution on remote computer, you can use out-file cmdlet to create a file on the remote computer as an indication.

How to run processes with Invoke-WMIMethod on remote computer in foreground

I am running this command
Invoke-WmiMethod -ComputerName $machine -Credential $cred -Impersonation 3 -Path Win32_process -Name create -ArgumentList "powershell.exe -ExecutionPolicy Unrestricted -File C:\Windows_Updates.ps1" -Verbose
The only problem is in the remote machine, it getting created as a background process. When I open the task manager, I am able to see powershell.exe, but I have no way to identify what is going on. I have looked nearly everywhere but unable to find a solution.
Basically I need to execute the powershell file remotely. I am open to using other solutions where I can see the script running.
I dont think that is possible. Try psexec instead
http://blogs.technet.com/b/heyscriptingguy/archive/2005/09/06/how-can-i-remotely-start-an-interactive-process.aspx
sysinternals psexec
http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx

Resources