Powershell - Problem with Start-transcript using remoting - powershell

I have a file transcript-test.ps1 with below contents
$log="TestLog{0:yyyyMMdd-HHmm}" -f
(Get-Date) $logfile =
'C:\logs\'+$log+'.txt'
Start-transcript -path $logfile -force
Write-host "To test if this message gets logged"
Stop-transcript
I try to run the script from lets say "box1" and the log file contains the below contents
********** Windows PowerShell Transcript Start Start
time: 20110105114050 Username :
domain\user Machine : BOX1
(Microsoft Windows NT 5.2.3790 Service
Pack 2)
********** Transcript started, output file is
C:\logs\TestLog20110105-1140.txt
To test if this message gets logged
********** Windows PowerShell Transcript End End time:
20110105114050
When I run the same script from another machine using below script I don't see any messages in the log file
Invoke-command {powershell.exe
-ExecutionPolicy Unrestricted -NoProfile -File C:\in ll\transcript-test.ps1} -computername
box1 -credential $credential get-credential
Contents of log file :
********** Windows PowerShell Transcript Start Start
time: 20110105114201 Username :
DOMAIN\user Machine : BOX1
(Microsoft Windows NT 5.2.3790 Service
Pack 2)
********** Windows PowerShell Transcript End End time:
20110105114201
Is there anyway to log the messages from the script to log file when invoked remotely ?
Thanks!
Sanjeev

The following will capture your local and remote verbose messages in the transcript
$VerbosePreference = "continue"
Start-Transcript -path c:\temp\transcript.txt
Write-Verbose "here 1"
$job = Invoke-Command cbwfdev01 -ScriptBlock {
$ErrorActionPreference = "Stop";
$VerbosePreference = "continue";
Write-Verbose "there 1";
Write-Verbose "there 2";
Write-Verbose "there 3";
} -AsJob
Wait-Job $job | Out-Null
$VerboseMessages = $job.ChildJobs[0].verbose.readall()
ForEach ($oneMessage In $VerboseMessages) {Write-Verbose $oneMessage}
Write-Verbose "here 2"
Stop-Transcript

Invoke-command execute your code into a job, which is as far as I understant a thread with no console, so no transcription. For me what you got is absolutly normal.

Related

Check if powerhshell was started using "run as administrator"

i found an old question on this topic. However, i am not clear.
I have a script that checks, if PS has been run using "run as administrator" and if yes it does the job, otherweise it prompts that the script must be run as administrator.
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
$CheckforAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
it gives true or false. I have if-else statement that does the rest.
If($CheckforAdmin -eq 'True'){
$MSG = ""
If(($EventLogCheck -ne $EventLog) -or ($EventLogsourceCheck -ne 'True')){
New-EventLog -LogName $EventLog -Source $EventLogSource -ErrorAction Stop
$MSG = "$env:USERNAME has successfully created a new eventlog named $EventLog with the source $EventLogSource."
Write-EventLog -logname $PiEventLog -source $PiEventLogSource -eventID 1021 -entrytype Information -message $MSG
}
else{
$MSG = "$env:USERNAME tried to create an EventLog named $EventLog with the source $EventLogSource. `nSince the EventLog and the source already exist, this step was aborted."
Write-EventLog -logname $EventLog -source $EventLogSource -eventID 1021 -entrytype Information -message $MSG
}
# Wenn der Parameter Silent auf true gesetzt ist, wird das Skript nach der Erstellung des EventLogs unmittelbar beendet.
if($install -eq $true){
Write-Host $MSG
Read-Host 'Press any key to continue...'
}
exit
}
else{
Write-Host "The Script must be executed as admin"
[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
[System.Windows.Forms.MessageBox]::Show('Installation: The script must be run as administrator in order to create the event log', 'Run as admin')
exit
}
It works well, if i am logged in with a normal user. But on my server where i want to run the script, i log in as domain administrator. Even if if run the script just double clicking on it, it runs instead of prompting that the script must be run using "run as administrator".
I red the articles about UAC (User Account control) and as far as i understood: running a script using "run as administor" is actually the same as logging in as domain administrator and double clicking on the script.
Is there any other way to check, if the script was run using "run as administrator" option that shows up if u right click on powershell (doesn't matter, whether you are logged in as admin or not) ?
At the top of your script add the line:
#Requires -RunAsAdministrator
then remove all your code to check for an administrator.
If the user running the script is not an elevated administrator, a message will be displayed and the execution of the scripts stops.
Original comment:
How did you implement the prompt? Because obviously, this part only returns $true or $false. I suppose a way to work around this would be something like
PowerShell -NoProfile -ExecutionPolicy Unrestricted -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Unrestricted -File ""PS_Script_Path&Name.ps1""' -Verb RunAs}"
To call the script as admin again, if it wasnt before.
Newly added:
Additionally, you have an error in your if-statement. To compare to boolean, you want to have your if-statement like following:
If($CheckforAdmin -eq $true){
Comparing against strings can lead to problems. Otherwise I cannot locate any other errors.

New-PSSession to Linux host is frozen when run under SYSTEM Account

I tried to run a Powershell Script under the System Account via Jenkins.
$DebugPreference = 'Continue'
$dt=get-date -Format "MM-dd-yyyy-HH-mm-ss-fff"
Start-Transcript -Path "C:\install\transcript-$dt.txt"
dir env:
$cmdline = $((Get-CimInstance win32_process -Filter "ProcessID=$PID" | ? { $_.processname -eq "pwsh.exe" }).commandline)
if($cmdline -like "*pwsh.exe*")
{
write-host "Powershel 7 continue"
Write-Host "Before Start-session"
$s = New-PSSession -HostName ip -UserName user -verbose -KeyFilePath C:\.ssh\id_rsa
Write-Host "After Start-session"
}else{
Start-Process pwsh.exe -Wait -PassThru -ArgumentList "-NonInteractive -ExecutionPolicy Bypass -File $($MyInvocation.MyCommand.Definition)"
}
stop-transcript
My Problem is that Write-Host "After Start-session" is never reached.
The first Start-Transcript shows, that the Script is started again with pwsh.exe
The second Start-Transcript shows the Output till Before Start-session.
After that there is nothing added to the Transcript and the Process keeps running.
The Script is working fine, when it is running under the Administrator Account.
How can I debug this ?
The Problem was that the SSH fingerprint was not trusted.
When I runned the Script via a command Line instead of via Jenkins direct, i got this output:
The authenticity of host 'ip (ip)' can't be established.
ECDSA key fingerprint is SHA256:gQv8WE8G04RhfNNX7pRQjVX0lPj3jNZ4JTPIDNEIGHk.
Are you sure you want to continue connecting (yes/no)?
After i answered it with yes everything worked.
The Jenkings Job is now working two.

How do you log the results of remotely invoked commands on the system running the PowerShell session?

I have a script that loops through a list of my servers, and runs various commands on them.
I am attempting to log the commands and their results for both the computer running the PowerShell script, and the remote computer running the commands.
Right now, I am trying to use the PSLogging module with the Start-Log cmdlet. I am able to log the commands run on the system running the Powershell script, but things run on the remote computer are not showing up.
My code looks like this.
Import-Module -Name "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\PSLogging\2.5.2\PSLogging.psm1"
$Date = Get-Date -Format "MM-dd-yyyy hh-mm tt"
$LogFileOutput = "Output Log"+" $Date"+".log"
$LogFilePlusPath = "\\files\Logs\"+"$LogFileOutput"
Start-Log -LogPath "\\files\Logs\" -LogName "LogFileOutput" -ScriptVersion "1.0"
Servers = #("Server1","Server2")
ForEach ($Server in $Servers)
{
Write-Host "Running script on $Server"
param([string]$Server)
Invoke-Command -Computer $Server -ScriptBlock {
Write-Host "Stopping IIS App Pool on $Server."
c:\windows\system32\inetsrv\appcmd.exe stop apppool "IISAppPool"
Write-Host "Switching Service to manual on $Server and stopping it."
Stop-Service Service -Force
Set-Service Service-StartupType Manual
} -args $Server
}
Write-Host "Script complete at $(Get-Date -Format "hh:mm tt MM/dd/yyyy") Logs available at \\files\Logs"
Stop-Log
The script works, and the services and App pools perform their operation as desired. The results just aren't being logged.
The only thing in the log would be:
Running script on Server1
Running script on Server2
Script complete at 12:20 PM 09/19/2020 Logs available at \files\Logs
Any suggestions on the best way to capture everything?
Thank you!

Invoke-AzVMRunCommand and Start-Process under specific user on remote VM using Azure Runbook

I need to run Start-Process on a remote VM with specific user account using Azure Powershell Runbook
function Install-Postgres {
$username = "aact-import-vm1\aact-importer"
$password = "ChangeMe!"
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList `
#($username,(ConvertTo-SecureString -String $password -AsPlainText -Force))
write-output $cred
# run pg installer
Start-Process "C:\Program Files\WindowsPowerShell\Modules\Install-Postgres\postgresql.exe" -ArgumentList `
"--mode unattended", "--unattendedmodeui none",`
"--prefix `"C:\Program Files\PostgreSQL\10`"", "--datadir `"C:\Program Files\PostgreSQL\10\data`"",
"--superpassword `"ChangeMe!`"",`
"--servicename `"postgres`"", "--serviceaccount `"postgres`"", "--servicepassword `"ChangeMe!`""`
-Wait -Credential $cred;
}
$script = Get-Content Function:\Install-Postgres
Out-File -FilePath Install.ps1 -InputObject $script
#Note that the -ScriptPath should not point to the remote path(in remote vm), it should point to the local path where you execute the command Invoke-AzureRmVMRunCommand
$output = Invoke-AzVMRunCommand -ResourceGroupName $resourceGroupName -Name $vmName -CommandId 'RunPowerShellScript' -ScriptPath Install.ps1
write-output $output.Value
#after execution, you can remove the file
Remove-Item -Path Install.ps1
The script above produces the following error:
Start-Process : This command cannot be run due to the error: Access is denied.
If I run the script above without specific credentials the postgres installer produces this error in the log:
Executing icacls "C:\Windows\Temp/postgresql_installer_1ef9b3f2c6" /T /Q /grant "WORKGROUP\aact-import-vm1$:(OI)(CI)F"
Script exit code: 1332
Script output:
Successfully processed 0 files; Failed processing 1 files
Script stderr:
WORKGROUP\aact-import-vm1**$**: No mapping between account names and security IDs was done.
Please notice that there is symbol $ instead of user name.
However, if I run it on the VM it works fine and produces this line in the log:
Executing icacls "C:\Users\aact-importer\AppData\Local\Temp\2/postgresql_installer_2662c862ff" /T /Q /grant "aact-import-vm1\aact-importer:(OI)(CI)F"
Script exit code: 0
As far as I can see, If I run runbook script remotely without credentials it runs under NTAUTHORITY\SYSTEM that's why there is symbol $ instead of user name in the postgres installer log. If I run it locally it uses proper user and everything works fine.
The question is: how can I specify a user account to run Start-Process on the remote VM?
Same question on msdn https://social.msdn.microsoft.com/Forums/en-US/a7fa0ca8-5cba-42bb-8076-9a8d4a654beb/invokeazvmruncommand-and-startprocess-under-specific-user-on-remote-vm-using-azure-runbook?forum=azureautomation#a7fa0ca8-5cba-42bb-8076-9a8d4a654beb
For those who are interested:
After investigation with MS support they confirmed that runbook (not hybrid) always runs under NTAUTHORITY\SYSTEM

Code in Job's Script Block after Start-Process Does not Execute

When I create a automation script with PowerShell 5.1, I got an issue – in a script block of a job, the code after Start-Process will not get chance to execute. Here’s a simple repro:
Step 1 >> Prepare a .cmd file for Start-Process, the code in callee.cmd is:
#echo off
echo "Callee is executing ..."
exit /B 0
Step 2 >> Prepare the PowerShell code,
$scriptBlock = {
$res = Start-Process -FilePath "cmd.exe" -Wait -PassThru -NoNewWindow -ArgumentList "/c .\callee.cmd"
throw "ERROR!"
}
$job = Start-Job -ScriptBlock $scriptBlock
Wait-Job $job
Receive-Job $job
Write-Host($job.State)
Step 3 >> Run the PowerShell script, the output on screen is:
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
1 Job1 BackgroundJob Completed True localhost ...
Completed
The expected value should be “Failed”.
Does my code have problem or I’m using jobs in a wrong way?
Start-Job run job in separate PowerShell process in so-called server mode. In this mode PowerShell job process use standard input and output streams to exchange messages with the parent process.
-NoNewWindow parameter of Start-Process cmdlet instruct it to connect spawned console child process to the standard streams of its parent.
Thus, using Start-Process -NoNewWindow inside of PowerShell job, you connect spawned cmd.exe process to the same streams, which PowerShell job process use to exchange messages with its own parent process.
Now, when spawned cmd.exe write something into its standard output stream, it disturb normal message exchange between PowerShell job process and its parent, which leads to some unexpected behavior.
PetSerAl gave a great explanation of why it happens but it took me while to find a proper solution.
First thing - as some people mentioned don't use -NoNewWindow, use -WindowStyle Hidden instead.
Second, output results to file and handle them in your script block. There are two parameters, one for output and another for errors -RedirectStandardOutput and -RedirectStandardError.
For some reasons I was sure that first one will handle all output and my code worked well if there were no errors, but was failing with no output in case of exceptions in script block.
I created a function that also handles process status result:
function RunProcesSafe($pathToExe, $ArgumentList)
{
Write-Host "starting $pathToExe $ArgumentList"
$logFile = Join-Path $env:TEMP ([guid]::NewGuid())
$errorLogFile = Join-Path $env:TEMP ([guid]::NewGuid())
try
{
Write-Host "starting $pathToExe $ArgumentList"
$proc = Start-Process "$pathToExe" -Wait -PassThru -RedirectStandardError $errorLogFile -RedirectStandardOutput $logFile -WindowStyle Hidden -ArgumentList $ArgumentList
$handle = $proc.Handle
$proc.WaitForExit();
if ($proc.ExitCode -ne 0) {
Write-Host "FAILED with code:"+$proc.ExitCode
Throw "$_ exited with status code $($proc.ExitCode)"
}
}
Finally
{
Write-Host (Get-Content -Path $logFile)
Write-Host (Get-Content -Path $errorLogFile)
Remove-Item -Path $logFile -Force
Remove-Item -Path $errorLogFile -Force
}
}