Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

File locked after redirection.

May
15,047
271
There are no other TCCs running. The file is written like this.

Code:
echos %_date %_time Offset: %[signum]%waverage  Temperature:^s >> v:\nistcheck.log
call v:\ssdtemp.btm >> v:\nistcheck.log

Code:
v:\> v:\nistcheck.btm

          LOCAL
 HOST    OFFSET STRATUM  RTT
NIST_0    0.002    1      23
NIST_1    0.000    1      28
NIST_2    0.004    1      28
NIST_3    0.000    1      38

Averages at 13:30:00 2026-06-20
 +0.002 Local offset
  0.029 RTT

W32tmSvc running 00:27:06  LastSync: 2026-06-20 13:02:55

v:\> v:\nistcheck.btm

          LOCAL
 HOST    OFFSET STRATUM  RTT
NIST_0    0.002    1      23
NIST_1    0.002    1      36
NIST_2    0.001    1      34
NIST_3   -0.002    1      29

Averages at 13:30:24 2026-06-20
 +0.001 Local offset
  0.031 RTT
TCC: (Sys) V:\nistcheck.btm [58]  The process cannot access the file because it is being used by another process.
 "V:\nistcheck.log"
TCC: (Sys) V:\nistcheck.btm [59]  The process cannot access the file because it is being used by another process.
 "V:\nistcheck.log"

W32tmSvc running 00:27:30  LastSync: 2026-06-20 13:02:55

v:\> filelock V:\nistcheck.log
 8928  D:\tc36\tcc.exe

v:\>
 
It might have something to do with using @PSHELL. Here it is with simple BTMs.
Code:
v:\> type locktest1.btm
setlocal
echos foo^s >> locktest.log
call locktest2.btm  >> locktest.log

v:\> type locktest2.btm
setlocal
set T0=%@pshell[$d=(Get-CimInstance -Namespace root\wmi -ClassName MSStorageDriver_FailurePredictData)[0].VendorSpecific; for($i=2;$i -lt $d.Length-12;$i+=12){if($d[$i]-eq 194){$d[$i+5];break}}]
echo %T0

v:\> locktest1.btm

v:\> locktest1.btm
TCC: (Sys) V:\locktest1.btm [2]  The process cannot access the file because it is being used by another process.
 "V:\locktest.log"
TCC: (Sys) V:\locktest1.btm [3]  The process cannot access the file because it is being used by another process.
 "V:\locktest.log"

v:\> echo %_pid & filelock v:\locktest.log
2884
 2884  D:\tc36\tcc.exe
 
Here's a simpler one.

Code:
v:\> type locktest1.btm
setlocal
echos foo^s >> locktest.log
call locktest2.btm  >> locktest.log

v:\> type locktest2.btm
setlocal
set T0=%@PSHELL[$profile]
echo %T0

v:\> locktest1.btm

v:\> tail /n 1 locktest.log
foo C:\Users\vefatica\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

v:\> locktest1.btm
TCC: (Sys) V:\locktest1.btm [2]  The process cannot access the file because it is being used by another process.
 "V:\locktest.log"
TCC: (Sys) V:\locktest1.btm [3]  The process cannot access the file because it is being used by another process.
 "V:\locktest.log"

v:\> echo %_pid & filelock v:\locktest.log
4456
 4456  D:\tc36\tcc.exe
 
This is the CLR's System.Console managed statics. The CLR's Console.Out / Console.Error are lazy singletons: on first access they call GetStdHandle(STD_OUTPUT_HANDLE) and wrap the result in a StreamWriter that becomes a GC root, living forever in managed memory. Even after closing / destroying the session, that GC root holds the file handle open.

Now, I could override this by using SetStdHandle to swap in NUL before calling the Powershell bridge -- but that means that @PSHELL will not support redirection. I'm not sure you'd be any happier with that result.
 
I can work around it. The CALLed BTM could export a variable (SETLOCAL) and the CALLer could just read it.
 
There's something funny going on. In a TCC that has been running since last night (on the left) the original example with nistcheck.btm and ssdtemp.btm is OK. (can be run multiple times); in a new instance (on the right) it's not OK. I thought I noticed that once before ... that the problem seems to go away on its own ... but I wasn't sure.

Note: Below I did nistcheck.btm (in order by pane) left, left, right, right. It won't work again in the left pane because the TCC in the right pane has the file open. If I close the right TCC, it'll be OK again in the left one.

1782050188242.webp
 
In regards to the FILELOCK command...

I had an issue with that command a while back.

I switched to the @FILELOCK function,
which worked better for me.

Code:
set thePID=%@filelock[E:\DOSBox\DATA\DBASE\WealthSimple\TRNSCTNS.DBF]
iff defined thePID then
  echo Locked   : E:\DOSBox\DATA\DBASE\WealthSimple\TRNSCTNS.DBF
  echo Locked by: %thePID
  echo            %@pidcommand[%thePID]
  quit
endiff

If I cannot close the program that has the file locked,
I use the TASKEND /F command.

YMMV

Joe
 
It's locked by the current TCC ... something to do with the use of @PSHELL.
 
More likely the .NET runtime has it locked.

I work around that by reading the .NET Assembly from a .dll into a byte array,
and then loading the assembly into memory from the byte array.

That way, the .dll is not locked.

Code:
:: Load the assembly without locking it during the duration of the PowerShell session
pshell /s "$bytes = [System.IO.File]::ReadAllBytes('%theDLLDir\%theDLL')"
pshell /s "[System.Reflection.Assembly]::Load($bytes)" > nul

Rex summed it up in post #4.

Rex also had to apply a fix for .NET plugins,
so that the .dll was not locked after doing a plugin /u
Ref: Done - Load .NET plugin as raw binary data

Joe
 
I can work around it. The CALLed BTM could export a variable (SETLOCAL) and the CALLer could just read it.
Nice Idea (works too) but regardless of how I get that value, I still want to write it to the file (which may be locked).
 
This is the CLR's System.Console managed statics. The CLR's Console.Out / Console.Error are lazy singletons: on first access they call GetStdHandle(STD_OUTPUT_HANDLE) and wrap the result in a StreamWriter that becomes a GC root, living forever in managed memory. Even after closing / destroying the session, that GC root holds the file handle open.

Now, I could override this by using SetStdHandle to swap in NUL before calling the Powershell bridge -- but that means that @PSHELL will not support redirection. I'm not sure you'd be any happier with that result.
Rex, is there anything iffy about that initialization? I have an instance of TCC right now in which both tests (nistcheck.btm and locktest1.btm) work over and over. And I have another instance in which neither will work a second time.
 
Not sure if this is a solution,
but what if you ran your PowerShell code in a new shell,
then exit that new shell,
back to the parent?

Code:
R:\>setlocal

R:\>echos foo^s >> locktest.log

R:\>setlocal

R:\>"%comspec%" /i

TCC  36.50.63 x64   Windows 10 [Version 10.0.19045.7417]
Copyright 2026 JP Software Inc.  All Rights Reserved
Registered to DESKTOP-LFBF7P3

R:\>set T0=%@PSHELL[$profile]

R:\>echo %T0
C:\Users\jlcav\OneDrive\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

R:\>echo %T0 >> locktest.log

R:\>exit

R:\>tail /n 1 locktest.log
foo C:\Users\jlcav\OneDrive\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

R:\>setlocal

R:\>echos foo^s >> locktest.log

R:\>setlocal

R:\>
R:\>"%comspec%" /i

TCC  36.50.63 x64   Windows 10 [Version 10.0.19045.7417]
Copyright 2026 JP Software Inc.  All Rights Reserved
Registered to DESKTOP-LFBF7P3

R:\>set T0=%@PSHELL[$profile]

R:\>echo %T0 >> locktest.log

R:\>exit

R:\>tail /n 1 locktest.log
foo C:\Users\jlcav\OneDrive\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

R:\>tail locktest.log
foo C:\Users\jlcav\OneDrive\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
foo C:\Users\jlcav\OneDrive\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

R:\>

Joe
 
Locktest is just a simple example. In the real life scenario, the CALLed btm is used for other purposes; I don't want it writing to a log file. Specifically, I want nistcheck.btm to CALL ssdtemp.btm and nistcheck.btm to do the logging. While the exported environment variable works, I have a better solution, ssdtemp.exe, which I can wrap in @EXECSTR. That will avoid @PSHELL leaving the file locked. I'm still curious why @PSHELL sometimes doesn't cause a problem.
 
Back
Top