Join GitHub today
GitHub is home to over 36 million developers working together to host and review code, manage projects, and build software together.
Sign upWhen using `Start-Transcript` and file exists, empty file rather than deleting #8131
Conversation
paalbra
requested review from
anmenaga and
daxian-dbw
as
code owners
Oct 26, 2018
This comment has been minimized.
This comment has been minimized.
|
My understanding is that currently we write an error and remove the file. Your suggestion is don'nt remove the file but wipe. Right? /cc @mklement0 What do you think about the special case? |
This comment has been minimized.
This comment has been minimized.
Well, kind of. The file is deleted and when Start-Transcript tries to recreate the file you get an access denied error (if the access is set in a way mentioned in #4065 ). But it is a bit OS/filesystem dependent. This can be avoided by not deleting the file, but rather wiping it. The fix should not alter the behavior of successful usage of Start-Transcript, but it will fix this special access case. |
This comment has been minimized.
This comment has been minimized.
|
@paalbra Thanks for clarification! I don't like the change because there can be very many permission combinations and we can not address all cases. Ex.: user could allow file removing and disable creation or create as read-only. Also on user system there could be a protection application which can overlap system assigned permissions. |
This comment has been minimized.
This comment has been minimized.
|
I too agree that we shouldn't special-case this:
In other words: loss of any preexisting file with the same name is always to be expected and no relationship between the old and the new file can and should be assumed. That creation of a new file then fails, is a separate issue, and requires that the permissions be set accordingly on the enclosing directory to allow file creation by the current user - which strikes me as reasonable. @paalbra: Your scenario sounds exotic and the steps to reproduce it (as shown in #4065) are quite involved. Is this a real-life scenario you've run into, and why would you expect to run into this repeatedly? |
This comment has been minimized.
This comment has been minimized.
|
@mklement0 Thanks! @SteveL-MSFT Please confirm that current behavior is "by-design" and we can not accept the PR. |
This comment has been minimized.
This comment has been minimized.
|
According to the documentation, one must use the existing |
This comment has been minimized.
This comment has been minimized.
|
Yes, I've run into this issue in my real-life environment. I don't view this issue as a special or exotic case myself. You could even compare this to Out-File which also has an Append parameter. Out-File has no issues with the same access permissions set because Out-File doesn't delete the file. I would expect both commands to work in this setup and this is what I try to fix with this PR. |
This comment has been minimized.
This comment has been minimized.
|
@paalbra I appreciate you bringing up this inconsistent experience and taking the time to submit a PR, however, we need to balance changes with impact to backwards compatibility. In this specific case, it seems the current behavior is documented so it's not a strong enough justification to change the current behavior. (I'm always open to reconsidering if there's sufficient community feedback) |
This comment has been minimized.
This comment has been minimized.
|
With the current behavior you also have other bad side effects. E.g. you can't point Start-Transcript to a symlink. If you do Start-Transcript will just delete the symlink and create a file. There is simply no reason for Start-Transcript to delete the file. I should just overwrite the file. This is also what it says that it does in the documentation. Overwriting a file is not the same as recreating a file. So I think the current documentation and behavior don't match. |
This comment has been minimized.
This comment has been minimized.
|
I really can't agree that the behavior is the same as the documentation. Again you could compare Start-Transcript and Out-File. They both have similar documentation when it comes to Append and NoClobber, but they do not behave the same way. |
This comment has been minimized.
This comment has been minimized.
|
I see your point now: In light of this, I think your PR has merit. Unless I'm missing something, I think this PR would be an easy consistency improvement that shouldn't impact existing scripts. |
This comment has been minimized.
This comment has been minimized.
|
@paalbra I misunderstood the intent, but thanks to @mklement0 I get it. Based on the explanation, I would agree that this PR makes sense particularly in the symlink case. |
SteveL-MSFT
changed the title
Avoid file deletion in Start-Transcript when not appending
When using `Start-Transcript` and file exists, empty file rather than deleting
Oct 28, 2018
This comment has been minimized.
This comment has been minimized.
|
@paalbra it would be great if you can add a test for this specific behavior. You can probably just check the file creation date hasn't changed. |
iSazonov
self-assigned this
Oct 29, 2018
This comment has been minimized.
This comment has been minimized.
|
@SteveL-MSFT I'm not very familiar with the project yet, since this is my first PR, but I'll certainly look into adding more tests. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@paalbra Just give it a try and we'll make suggestions :) |
This comment has been minimized.
This comment has been minimized.
|
Ok, so I've tried to add a test that checks creation time, as suggested by @SteveL-MSFT , but I've encountered some problems. I've tried to add something like It "Should not change the creation time of existing file" {
$oldDate = (Get-Date).AddDays(-1)
"" | Out-File -FilePath $transcriptFilePath
(Get-Item $transcriptFilePath).CreationTime = $oldDate
Start-Transcript -Path $transcriptFilePath
Stop-Transcript
(Get-Item $transcriptFilePath).CreationTime | Should -Be $oldDate
}The thing is that the CreationTime property on Windows apparently does not change when the file is recreated within a few seconds. This makes the whole test kind of useless since it won't fail.
Also: I found out that on Ubuntu a modification of the CreationTime actually alters the LastAccessTime. So I can't really do the above test on Linux.
The issue on Linux I could work around, but on Windows I'm not sure if I really can tell if a file has been deleted and recreated or not. I'm not really sure what to do here as I quickly run into these kind of filesystem/OS dependent issues. Any suggestions? |
This comment has been minimized.
This comment has been minimized.
|
A bit more of searching the web led me to the FileSystemWatcher class. I guess I could use one of those and make a test that makes sure no file deletion events are emitted when running Start-Transcript. This seems a bit excessive to me though. Any thoughts? |
This comment has been minimized.
This comment has been minimized.
|
@paalbra Thanks for making the effort. I agree that using FileSystemWatcher is overkill for this. I suspect you can't reply on the |
This comment has been minimized.
This comment has been minimized.
msftclas
commented
Oct 30, 2018
•
paalbra
force-pushed the
paalbra:bugfix-4065
branch
2 times, most recently
Oct 30, 2018
This comment has been minimized.
This comment has been minimized.
|
I decided to try the FileSystemWatcher path since I got it working on Windows and Ubuntu (the test is failing in master and passing in my branch). But for some reason it's failing on MacOS. I'm really not sure why and I currently have no Mac available for debugging. I'll try to get my hands on a Mac some day soon though... |
paalbra
force-pushed the
paalbra:bugfix-4065
branch
Oct 30, 2018
This comment has been minimized.
This comment has been minimized.
|
@paalbra there may be an issue in CoreFx where the file on macOS is deleted or that the event is being incorrectly raised |
This comment has been minimized.
This comment has been minimized.
|
@paalbra looks like the file gets deleted on MacOS when you're not expecting it to, at least from the build logs:
|
This comment has been minimized.
This comment has been minimized.
|
I have no explanation, but here's a data point: I just ran the test locally against this PR's code on my macOS 10.14 machine, and it succeeded in 100 successive invocations. |
This comment has been minimized.
This comment has been minimized.
|
How we open the file? If "Read shared" we could open the file twice and check its content by second handle. |
This comment has been minimized.
This comment has been minimized.
|
So, I've gotten my hands on a Mac (10.13.6) and done some debugging. I also get failing results. Sometimes I actually see two file deletion events when running the test. These failures seems to be related to the testdrive. I do not get failures if I modify the test to use some other path elsewhere. I'm not familiar with the testdrive and I honestly have no idea why the file somehow gets deleted multiple times from the testdrive when running the test. Apperently @mklement0 does not experience the same thing, which only makes it harder to understand. |
This comment has been minimized.
This comment has been minimized.
|
Interesting, @paalbra, but there's some consistency: I hadn't used the |
This comment has been minimized.
This comment has been minimized.
|
Perhaps to help isolate if this is a
|
paalbra
force-pushed the
paalbra:bugfix-4065
branch
to
64e2b82
Nov 3, 2018
This comment has been minimized.
This comment has been minimized.
|
Ok, so I've done some more testing. On MacOS the TestDrive doesn't seem to be "clean" between tests. Somehow the state/file deletion events "bleed through" from other tests. I've tried to resolve this by creating a new, unique path within my test and this seems to work. Any thoughts or feedback on this method? |
This comment has been minimized.
This comment has been minimized.
|
I guess this is something you might want for all tests. So a better solution might be to create a new unique path in the |
This comment has been minimized.
This comment has been minimized.
|
I think creating a unique path for this PR is definitely the way to go. My sense is that we needn't worry about the other tests, as they don't use file-system watchers. It is curious that only macOS is affected, though. There are several open issues for the Another thing to try - though more out of curiosity, given that the use |
This comment has been minimized.
This comment has been minimized.
|
@paalbra thanks for taking the time to investigate this. My suggestion is for this PR to have the macOS specific code path (with appropriate comments). Agree with @mklement0 that the other tests are probably ok although not ideal. It may be worthwhile to see if |
This comment has been minimized.
This comment has been minimized.
|
Adding It "Should not delete the file if it already exist" {
# Create an existing file
#$transcriptFilePath = Join-Path $TestDrive ([System.IO.Path]::GetRandomFileName())
Out-File $transcriptFilePath
Start-Sleep -Seconds 20
$FileSystemWatcher = [System.IO.FileSystemWatcher]::new((Split-Path -Parent $transcriptFilePath), (Split-Path -Leaf $transcriptFilePath))
$Job = Register-ObjectEvent -InputObject $FileSystemWatcher -EventName "Deleted" -SourceIdentifier "FileDeleted" -Action {
return "FileDeleted"
}
Start-Transcript -Path $transcriptFilePath
Stop-Transcript
Unregister-Event -SourceIdentifier "FileDeleted"
# Nothing should have been returned by the FileSystemWatcher
Receive-Job $job | Should -Be $null
}The above actually makes the test pass on MacOS. My guess is that the I think the current solution, with unique file path, is the best for all OSes. |
iSazonov
requested a review
from
SteveL-MSFT
Nov 6, 2018
iSazonov
approved these changes
Nov 6, 2018
SteveL-MSFT
requested changes
Nov 6, 2018
|
Only need to address @iSazonov's comment on try..finally |
SteveL-MSFT
approved these changes
Nov 7, 2018
|
LGTM . Thanks! |
iSazonov
merged commit 2e89efa
into
PowerShell:master
Nov 7, 2018
7 checks passed
This comment has been minimized.
This comment has been minimized.
|
@paalbra Thanks for your contribution! |
paalbra commentedOct 26, 2018
PR Summary
Currently Start-Transcript will delete the file it refers to if it's not set to append. This might lead to issues if the user running the command only has access to the file and not the parent folder. This PR makes sure the file is emptied rather than deleted. There are more details in the issue. Fix #4065.
PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:to the beginning of the title and remove the prefix when the PR is ready.[feature]if the change is significant or affects feature testsP.S.
This is my first PR in this project. I'm hopefully doing things right...