Powershell debugging event -Action code block - powershell-ise

I have script watching file creation in a specific directory.
I'm using Register-ObjectEvent after creating a System.IO.FileSystemWatcher,
It works great, but if I set a break point in the -Action code block the IDE generates a:
WARNING: Breakpoint Line breakpoint on 'D:\My Stuff\Desktop\scripts\fileWatcher.ps1:15' will not be hit
this message happens right after I drop a file into the directory I'm watching and I can see my Write-Host printing out my message right after the above 'warning'.
Is this normal?
I need to add more code and could really use the debugger..
What can\should I do, so I can debug this code block?
$fsw = [System.IO.FileSystemWatcher] $path
Register-ObjectEvent -InputObject $fsw –EventName Created -SourceIdentifier DDFileCreated -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore green
Out-File -FilePath $logFile -Append -InputObject "The file '$name' was $changeType at $timeStamp"
}

If you trigger the event from a direct powershell command in the same ISE or console session, it actually works:
$path = (Resolve-Path '~\').Path
if(Test-Path "$path\newfile.txt"){ del "$path\newfile.txt" }
$fsw = [System.IO.FileSystemWatcher] $path
Register-ObjectEvent -InputObject $fsw –EventName Created -SourceIdentifier DDFileCreated -Action {
$name = $Event.SourceEventArgs.Name # put breakpoint here, via ISE or script
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore green
}
'foo' | out-file "$path\newfile.txt" # breakpoint hit
But if you simply hook up the event and wait for some external process to create a file, I see the issue you are hitting.
So if you can add some test code to directly trigger your event, go with that.
If not, read on...
It seems like you cannot enter the debugger while the shell or ISE is waiting for a new command, you can only enter while another command is executing.
Going with that theory, this is the workaround (works for me):
Set your breakpoint
Run your event subscription code
Run the command "Read-Host" in the ISE console window, or from the prompt in the shell
Wait until you know your event should have fired due to external process
Hit "enter" to allow Read-Host to complete
Viola, breakpoint hit!

The real key is to have a loop running so the script never exits. Then debugging and breakpoints work.
E.g.
# At the end of the script.
while ($true) {
Start-Sleep -Seconds 1
}
More detail is here.

Related

Powershell: Issue redirecting output from error stream when using docker

I am working on a set of build scripts which are called from a ubuntu hosted CI environment. The powershell build script calls jest via react-scripts via npm. Unfortunately jest doesn't use stderr correctly and writes non-errors to the stream.
I have redirected the error stream using 3>&1 2>&1 and this works fine from just powershell core ($LASTEXITCODE is 0 after running, no content from stderr is written in red).
However when I introduce docker via docker run, the build script appears to not behave and outputs the line that should be redirected from the error stream in red (and crashes). i.e. something like: docker : PASS src/App.test.js. Error: Process completed with exit code 1..
Can anyone suggest what I am doing wrong? because I'm a bit stumped. I include the sample PowerShell call below:-
function Invoke-ShellExecutable
{
param (
[ScriptBlock]
$Command
)
$Output = Invoke-Command $Command -NoNewScope | Out-String
if($LASTEXITCODE -ne 0) {
$CmdString = $Command.ToString().Trim()
throw "Process [$($CmdString)] returned a failure status code [$($LASTEXITCODE)]. The process may have outputted details about the error."
}
return $Output
}
Invoke-ShellExecutable {
($env:CI = "true") -and (npm run test:ci)
} 3>&1 2>&1

Lua: forward output from Minicom

I have a Lua script and in there I open a minicom session which executes a script (with the -S" parameter).
local myFile = assert(io.popen('minicom -S myScript.sh ' myDevice ' -C myLogFile.log'))
local myFileOutput = myFile:read('*all')
myFile:close()
This works really fine.
But I would like to get the same output as if I execute the minicom command itself:
minicom -S myScript.sh ' myDevice ' -C myLogFile.log
Right now I don't get any output at all (I know that that's somehow obvious).
I would that the output should also occur at (at least nearly) the same time as with the minicom command itself. Not one big chuck of data at the end.
Does anyone know how to achieve that?
If I understand you correctly, you need something like
local myFile = assert(io.popen('minicom ...'))
for line in myFile:lines('l') do
print(line)
end
myFile:close()

How to execute a CMD file in remote computer

I am looking to execute a command in remote machine using invoke but the .cmd file will call for additional .vbs script. So i guess i may have to mention CScript if so how do i mention both cmd/c and cscript in the below command
Invoke-Command -computername blrscrv01 -ScriptBlock { param($path, $command ) cmd /c $path $command } -args '"C:\windows\system32\cscript.exe"','"/?"'
Your example worked for me when I removed the extra level of quoting.
Invoke-Command -computername blrscrv01 -ScriptBlock { param($path, $command ) cmd /c $path $command } -args 'C:\windows\system32\cscript.exe','/?'
Troubleshooting
Enter a remote session and poke around.
Enter-PSSession -computername blrscrv01
Verify that the target script exists and is accessible.
dir \\lcsap027\deploy\c2.cmd
dir \\lcsap027\deploy
type \\lcsap027\deploy\c2.cmd
Attempt to run the script interactively.
\\lcsap027\deploy\c2.cmd
or
cmd /c \\lcsap027\deploy\c2.cmd
Alternative
Another thing you might try is not invoking a cmd script remotely, but issuing the commands remotely. New-PSSession will return a handle you can use to deal interactively with the remote machine. You can repeatedly issue commands with Invoke-Command and get the results (as primitive data types and generic objects, though, not the actual objects themselves).
Altered Script
Here's an altered version of the script you put in your comment. I've removed the nested Invoke-Command (I don't know why it was necessary, you're already running commands on the remote machine). Since the line breaks got lost in the comment, I don't know if there were any statement separator problems (I'll just assume there weren't, though in its "formatted" form as a one-liner, it would have died horribly because PoSH wouldn't have known where one statement ended and the next began).
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("x:", "\\machinename\sharename", $false, $Username, $Password)
cmd.exe /c "x:\c2.cmd"
$net.RemoveNetworkDrive("x:")
} -args $ComputerName, $User, $pass
This at least got the remote script to run and produced the expected output. (I emitted the computer name, user name, and file location.)
Bear in mind that this method doesn't employ any transport-/application-layer encryption, so the password is sent cleartext over the network.

How Can I Return Exit Code To Variable On Local Computer From Script Run On Remote Computer?

I am attempting to execute a Powershell script on a remote computer from a Powershell window on my local computer using Powershell 2.0. My goal is to store an exit code from the script on the remote computer to a variable on my local computer, whether it be in a local script or just a local Powershell window. Currently all I get back is an error message stating the following . . .
Cannot invoke pipeline because run space is not in the Opened state. Current state of run space is Closed. + CategoryInfo: OperationStopped: Microsoft.Power...tHelperRunspace:ExecutionCmdletHelperRunspace) [], InvalidRunspaceStateException + FullyQualifiedErrorID : RemotePipeLineExecutionFailed
My situation is this . . . I am trying to return an exit code to a variable on my local machine from a script on a remote machine. There are actually two scripts involved here and both are on the remote machine and in the same folder. The first script is called "VerifyBatchExistence.ps1". This file takes as input a batch file called "Batch.ps1", an integer that represents an exit code to be output if "Batch.ps1" does not exist, another integer representing the number of parameters needed by "Batch.ps1", and the variable string(s) needed as input for "Batch.ps1". Within "Batch.ps1" I have the following piece of code which I expect to be triggered when one of my passed-in parameters is invalid. . .
exit 931
Within "VerifyBatchExistence.ps1" I have the following piece of code . . .
Powershell - File .\Batch.ps1 BATCHPARAM1 BATCHPARAM2
$Code1 = $LASTEXITCODE
$Host.SetShouldExit($Code1)
exit
On my local machine, I did the following . . .
$Remote=New-PSSession -ComputerName 7.7.7.7 -Credential $cred
Invoke-Command -Session $Remote -ScriptBlock {$Code1=.\VerifyBatchExistence.ps1 7777 2 .\Batch.ps1 NAME1 NAME2}
$Code2=Invoke-Command -Session $Remote -ScriptBlock {$Code1}
$Code2
After this, I receive the error stated above. Any idea what I am doing wrong or how I can return an exit code to a variable on my local machine from a remote machine which has a script consuming and running a second script? Any answer to this would be appreciated. Thanks.
I do it like this:
invoke-command -session $Remote -scriptblock { mycommand }
$remotelastexitcode = invoke-command -session $Remote -ScriptBlock { $lastexitcode }
if ( $remotelastexitcode -ne 0 )
{
"$remotelastexitcode"
exit 1
}

Long Running Powershell Script Freezes

We are using a long running PowerShell script to perform a lot of small operations that can take an extremely long amount of time. After about 30 minutes the scripts froze. We were able to get the scripts to start running again by pressing Ctrl-C which caused the scripts to resume execution instead of killing the process.
Is there some sort of script timeout or mechanism that prevents long running scripts within PowerShell?
I had this problem due to a bad habit I have. If you select a little bit of text inside a console powershell, scripts logs freeze. Make sure nothing is selected after launching a big script :)
Like mentioned, when clicking/selecting text in powershell console, the script stops. You can disable this behaviour like this:
Right-click the title bar
Select Properties
Select Options
Under Edit Options, disable QuickEdit Mode
Note: You won't be able to select text from powershell window anymore.
Try my kill timer script. Just change the $ScriptLocation variable to the script you want to run. That script will then run as a background job while the current windows keeps track of the timer. After the time expires the current window will kill the background job and write it all to logs.
Start-Transcript C:\Transcriptlog-Cleanup.txt #write log to this location
$p = Get-Process -Id $pid | select -Expand id # -Expand selects the string from the object id out of the current process.
Write-Host $p
$BJName = "Clean-up-script" #Define Background job name
$startTime = (Get-Date) # set start time
$startTime
$expiration = (Get-Date).AddMinutes(2)#program expires at this time
# you could change the expiration time by changing (Get-Date).AddSeconds(20) to (Get-Date).AddMinutes(10)or to hours or whatever you like
#-----------------
#Timer update function setup
function UpdateTime
{
$LeftMinutes = ($expiration) - (Get-Date) | Select -Expand minutes # sets minutes left to left time
$LeftSeconds = ($expiration) - (Get-Date) | Select -Expand seconds # sets seconds left to left time
#Write time to console
Write-Host "------------------------------------------------------------------"
Write-Host "Timer started at : " $startTime
Write-Host "Current time : " (Get-Date)
Write-Host "Timer ends at : " $expiration
Write-Host "Time on expire timer : " $LeftMinutes "Minutes" $LeftSeconds "Seconds"
Write-Host "------------------------------------------------------------------"
}
#get background job info and remove the it afterwards + print info
function BJManager
{
Receive-Job -Name $BJName #recive background job results
Remove-Job -Name $BJName -Force #remove job
Write-Host "Retrieving Background-Job info and Removing Job..."
}
#-----------------
$ScriptLocation = "C:\\Local-scripts\Windows-Server-CleanUp-Script-V2.4(Beta).ps1" #change this Var for different kind of script locations
Start-Job -Name $BJName -FilePath $ScriptLocation #start this script as background job
# dont start job in the loop.
do{ #start loop
Write-Host "Working"#start doing other script stuff
Start-Sleep -Milliseconds 5000 #add delay to reduce spam and processing power
UpdateTime #call upadate function to print time
Get-Job -Name $BJName | select Id, State ,Location , Name
if((Get-Job).State -eq "Failed")
{
BJManager
}
elseif((Get-Job).State -eq "Completed")
{
BJManager
}
}
until ($p.HasExited -or (Get-Date) -gt $expiration) #check exit time
Write-Host "Timer Script Finished"
Get-Job -Name $BJName | select Id, State ,Location , Name
UpdateTime
BJManager
Start-Sleep -Milliseconds 5000 #give it some time to write to log
Stop-Transcript
Start-Sleep -Milliseconds 5000 #give it some time to stop the logging before killing process
if (-not $p.HasExited) { Stop-Process -ID $p -PassThru } # kill process after time expires
try to add percentage calculation in your script.. so you can identity that how much time it would take to complete...

Resources