简体   繁体   English

从 python 脚本中取消阻止 windows 中的文件

[英]Unblock a file in windows from a python script

Could I unblock a file in windows(7), which is automatically blocked by windows (downloaded from Internet) from a python script?我可以在 Windows(7) 中取消阻止 windows(从 Internet 下载)从 python 脚本自动阻止的文件吗? A WindowsError is raised when such a file is encountered.遇到此类文件时会引发 WindowsError。 I thought of catching this exception, and running a powershell script that goes something like:我想捕捉这个异常,并运行一个 powershell 脚本,类似于:

Parameter Set: ByPath
Unblock-File [-Path] <String[]> [-Confirm] [-WhatIf] [ <CommonParameters>]

Parameter Set: ByLiteralPath
Unblock-File -LiteralPath <String[]> [-Confirm] [-WhatIf] [ <CommonParameters>]

I don't know powershell scripting.我不知道 powershell 脚本。 But if I had one I could call it from python.但如果我有一个,我可以从 python 调用它。 Could you folks help?你们能帮忙吗?

是的,您所要做的就是从Python调用以下命令行:

powershell.exe -Command Unblock-File -Path "c:\path\to\blocked file.ps1"

Late to the party .聚会迟到了。 . . . . . . I have found that the Block status is simply an extra 'file' (stream) attached in NTFS and it can actually be accessed and somewhat manipulated by ordinary means.我发现块状态只是附加在 NTFS 中的一个额外的“文件”(流),它实际上可以通过普通方式访问和操作。 These are called Alternative Data Streams.这些称为替代数据流。 The ADS for file blocking (internet zone designation) is called ':Zone.Identifier' and contains, I think, some useful information:用于文件阻塞(互联网区域指定)的 ADS 称为“:Zone.Identifier”,我认为其中包含一些有用的信息:

[ZoneTransfer]
ZoneId=3
ReferrerUrl=https://www.google.com/
HostUrl=https://imgs.somewhere.com/product/1969297/some-pic.jpg

All the other info I have found says to just delete this extra stream.... But, personally, I want to keep this info.... So I tried changing the ZoneId to 0, but it still shows as Blocked in Windows File Properties.我发现的所有其他信息都说只删除这个额外的流......但是,就我个人而言,我想保留这个信息......所以我尝试ZoneId更改为 0,但它仍然在 Windows 文件中显示为已阻止特性。 I settled on moving it to another stream name so I can still find it later.我决定它移到另一个流名称,以便以后仍然可以找到它。

The below script originated from a more generic script called pyADS.下面的脚本源自一个更通用的脚本,称为 pyADS。 I only care about deleting / changing the Zone.Identifier attached stream -- which can all be done with simple Python commands.我只关心删除/更改 Zone.Identifier 附加流——这一切都可以用简单的 Python 命令完成。 So this is a stripped-down version.所以这是一个精简版。 It has several really nice background references listed.它列出了几个非常好的背景参考。 I am currently running the latest Windows 10 and Python 3.8+;我目前正在运行最新的 Windows 10 和 Python 3.8+; I make no guarantees this works on older versions.我不保证这适用于旧版本。

import os

'''
References:
    Accessing alternative data-streams of files on an NTFS volume   https://www.codeproject.com/Articles/2670/Accessing-alternative-data-streams-of-files-on-an
    Original ADS class (pyADS)                                      https://github.com/RobinDavid/pyADS
    SysInternal streams applet                                      https://docs.microsoft.com/en-us/sysinternals/downloads/streams
    Windows: killing the Zone.Identifier NTFS alternate data stream https://wiert.me/2011/11/25/windows-killing-the-zone-identifier-ntfs-alternate-data-stream-from-a-file-to-prevent-security-warning-popup/
    Zone.Information                                                https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/6e3f7352-d11c-4d76-8c39-2516a9df36e8
    About URL Security Zones                                        https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/ms537183(v=vs.85)?redirectedfrom=MSDN
    GREAT info: How Windows Determines That the File....            http://woshub.com/how-windows-determines-that-the-file-has-been-downloaded-from-the-internet/
    Dixin's Blog: Understanding File Blocking and Unblocking        https://weblogs.asp.net/dixin/understanding-the-internet-file-blocking-and-unblocking

'''
class ADS2():
    def __init__(self, filename):
        self.filename = filename

    def full_filename(self, stream):
        return "%s:%s" % (self.filename, stream)

    def add_stream_from_file(self, filename):
        if os.path.exists(filename):
            with open(filename, "rb") as f: content = f.read()
            return self.add_stream_from_string(filename, content)
        else:
            print("Could not find file: {0}".format(filename))
            return False

    def add_stream_from_string(self, stream_name, bytes):
        fullname = self.full_filename(os.path.basename(stream_name))
        if os.path.exists(fullname):
            print("Stream name already exists")
            return False
        else:
            fd = open(fullname, "wb")
            fd.write(bytes)
            fd.close()
            return True

    def delete_stream(self, stream):
        try:
            os.remove(self.full_filename(stream))
            return True
        except:
            return False

    def get_stream_content(self, stream):
        fd = open(self.full_filename(stream), "rb")
        content = fd.read()
        fd.close()
        return content
def UnBlockFile(file, retainInfo=True):
    ads = ADS2(file)
    if zi := ads.get_stream_content("Zone.Identifier"):
        ads.delete_stream("Zone.Identifier")
        if retainInfo: ads.add_stream_from_string("Download.Info", zi)
### Usage:
from unblock_files import UnBlockFile
UnBlockFile(r"D:\Downloads\some-pic.jpg")

Before:前:

D:\downloads>dir /r
 Volume in drive D is foo
 Directory of D:\downloads

11/09/2021  10:05 AM                 8 some-pic.jpg
                                   126 some-pic.jpg:Zone.Identifier:$DATA
               1 File(s)              8 bytes

D:\downloads>more <some-pic.jpg:Zone.Identifier:$DATA
[ZoneTransfer]
ZoneId=3
ReferrerUrl=https://www.google.com/
HostUrl=https://imgs.somewhere.com/product/1969297/some-pic.jpg

After:后:

D:\downloads>dir /r
 Volume in drive D is foo
 Directory of D:\downloads

11/09/2021  10:08 AM                 8 some-pic.jpg
                                   126 some-pic.jpg:Download.Info:$DATA
               1 File(s)              8 bytes

From this page about the Unblock-File command: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/unblock-file?view=powershell-7.2从此页面了解Unblock-File命令: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/unblock-file?view=powershell-7.2

Internally, the Unblock-File cmdlet removes the Zone.Identifier alternate data stream, which has a value of 3 to indicate that it was downloaded from the internet.在内部, Unblock-File cmdlet 删除Zone.Identifier备用数据 stream,其值为3表示它是从 Internet 下载的。

To remove an alternate data stream ads_name from a file path\to\file.ext , simply delete path\to\file.ext:ads_name :要从文件path\to\file.ext中删除备用数据 stream ads_name ,只需删除path\to\file.ext:ads_name

try:
    os.remove(your_file_path + ':Zone.Identifier')
except FileNotFoundError:
    # The ADS did not exist, it was already unblocked or
    # was never blocked in the first place
    pass
# No need to open up a PowerShell subprocess!

(And similarly, to check if a file is blocked you can use os.path.isfile(your_file_path + ':Zone.Identifier') ) (同样,要检查文件是否被阻止,您可以使用os.path.isfile(your_file_path + ':Zone.Identifier')

In a PowerShell script, you can use Unblock-File for this, or simply Remove-Item -Path $your_file_path':Zone.Identifier' .在 PowerShell 脚本中,您可以为此使用Unblock-File ,或者简单地使用Remove-Item -Path $your_file_path':Zone.Identifier'
Remove-Item also has a specific flag for alternate data streams: Remove-Item -Stream Zone.Identifier (which you can pipe in multiple files to, or a single -Path ) Remove-Item还具有用于备用数据流的特定标志: Remove-Item -Stream Zone.Identifier (您可以在多个文件中使用 pipe 或单个-Path

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM