【问题标题】:Check if Word Document is Read Only from PowerShell从 PowerShell 检查 Word 文档是否为只读
【发布时间】:2020-09-01 00:33:36
【问题描述】:

我正在尝试检测 MSOffice 是否已将“Microsoft Word 文档”配置为“只读”。

我读到的所有内容都与使用Get-ItemProperty "C:\tmp\readonly.docx" | Select-Object IsReadOnly 进行检查有关,但这是从文件系统级别检查文件是否为“只读”。

问题是微软没有在外面标记它,你需要打开/检查我想查询文档是否为只读的微软 COM 对象。

PS C:\Users\Admin> Get-ItemProperty "C:\tmp\readonly.docx" | Select-Object IsReadOnly


IsReadOnly
----------
     False

更新:如果文件配置为RO 没有Password,那么您可以简单地打开为RW 而没有提示(通过powershell),但如果它带有Password,那么您会得到确认提示RO status 这是我想要避免的,因为它挂起了我的脚本。

【问题讨论】:

  • 只读是什么意思?检查的 NTFS 属性或文件是否已在 Word 进程中打开?
  • @vonPryz 两者都不是。只要它是由 MSOffice Word 配置的 RO。
  • @slightly snarky 所有这些都是可能的,有兴趣知道答案,即使它们基于该标准受到限制!
  • ReadOnly 和文件级别设置之间存在差异,与文件是否被锁定相比。检查 RO 与 In Use 的用例是什么?两者都阻止您对文档进行更改,但不能打开它们。如果文件系统属性设置为 OS RO,则必须使用文件系统删除该属性。如果它被锁定,因为正在使用,您可以关闭它,但是这样做会丢失任何未保存的更改。因此,随意这样做是不谨慎的。
  • 我的意思是您不需要 COM 来检查 Word 文档是否为 RO。你只需要检查它的属性。这就是 Get-ItemProperty 所做的一切。现在,如果您的意思是文档创建者在文档保护选项中将文档设置为“始终以只读方式打开”,那么请确保这是不同的。 OP根本没有在帖子中询问文档保护。在 Word 中完成的任何事情,是的,您需要使用 COM/DOM 来完成它。

标签: powershell ms-word


【解决方案1】:

继续我的评论和注释,不使用任何通过 COM 处理 Word DOM 的东西。

$File = 'd:\Temp\HSGCopy.docx'

# File not in use
Set-ItemProperty -Path $File  -Name IsReadOnly -Value $false
(Get-ItemProperty 'd:\Temp\HSGCopy.docx').IsReadOnly
$File | 
ForEach{
    try   
    {
        $TargetFile = (New-Object System.IO.FileInfo $PSitem).Open(
                                            [System.IO.FileMode]::Open, 
                                            [System.IO.FileAccess]::ReadWrite, 
                                            [System.IO.FileShare]::None
                      )
        $TargetFile.Close()  
        Remove-Item -Path $PSItem -WhatIf  
    }
    catch [System.Management.Automation.ItemNotFoundException]{$PSItem.Exception.Message}
    catch {$PSItem.Exception.Message}
}
# Results
<#
False
What if: Performing the operation "Remove File" on target "D:\Temp\HSGCopy.docx".
#>

# File in use
Set-ItemProperty -Path $File  -Name IsReadOnly -Value $false
(Get-ItemProperty 'd:\Temp\HSGCopy.docx').IsReadOnly
$File | 
ForEach{
    try   
    {
        $TargetFile = (New-Object System.IO.FileInfo $PSitem).Open(
                                            [System.IO.FileMode]::Open, 
                                            [System.IO.FileAccess]::ReadWrite, 
                                            [System.IO.FileShare]::None
                      )
        $TargetFile.Close()  
        Remove-Item -Path $PSItem -WhatIf  
    }
    catch [System.Management.Automation.ItemNotFoundException]{$PSItem.Exception.Message}
    catch {$PSItem.Exception.Message}
}
# Results
<#
False
Exception calling "Open" with "3" argument(s): "The process cannot access the file 'd:\Temp\HSGCopy.docx' because it is being used by another process."
#>


# Change the file attribute
# File not in use
Set-ItemProperty -Path $File  -Name IsReadOnly -Value $true
(Get-ItemProperty 'd:\Temp\HSGCopy.docx').IsReadOnly
$File | 
ForEach{
    try   
    {
        $TargetFile = (New-Object System.IO.FileInfo $PSitem).Open(
                                            [System.IO.FileMode]::Open, 
                                            [System.IO.FileAccess]::ReadWrite, 
                                            [System.IO.FileShare]::None
                      )
        $TargetFile.Close()  
        Remove-Item -Path $PSItem -WhatIf  
    }
    catch [System.Management.Automation.ItemNotFoundException]{$PSItem.Exception.Message}
    catch {$PSItem.Exception.Message}
}
# Results
<#
True
Exception calling "Open" with "3" argument(s): "Access to the path 'd:\Temp\HSGCopy.docx' is denied."
#>

# File in use
Set-ItemProperty -Path $File  -Name IsReadOnly -Value $true
(Get-ItemProperty 'd:\Temp\HSGCopy.docx').IsReadOnly
$File | 
ForEach{
    try   
    {
        $TargetFile = (New-Object System.IO.FileInfo $PSitem).Open(
                                            [System.IO.FileMode]::Open, 
                                            [System.IO.FileAccess]::ReadWrite, 
                                            [System.IO.FileShare]::None
                      )
        $TargetFile.Close()  
        Remove-Item -Path $PSItem -WhatIf  
    }
    catch [System.Management.Automation.ItemNotFoundException]{$PSItem.Exception.Message}
    catch {$PSItem.Exception.Message}
}
# Results
<#
True
Exception calling "Open" with "3" argument(s): "Access to the path 'd:\Temp\HSGCopy.docx' is denied."
#>

使用 Word 文档保护时

# with Word doc protection off
#>
$Word = New-Object –comobject Word.Application
Try
{
    ($Word.documents.open($File,$false,$false)).ReadOnly
    Write-Warning -Message "$File is protected ReadOnly"
}
Catch {Write-Verbose -Message "$File is not protected" -Verbose}

# then don't forget to close
$Word.Quit()
# Results 
<#
VERBOSE: d:\Temp\HSGCopy.docx is not protected
#>




# With Word doc protection on
$Word = New-Object –comobject Word.Application
Try
{
    ($Word.documents.open($File,$false,$false)).ReadOnly
    Write-Warning -Message "$File is protected ReadOnly"
}
Catch {Write-Verbose -Message "$File is not protected ReadOnly" -Verbose}

# then don't forget to close
$Word.Quit()
# Results 
<#
True
WARNING: d:\Temp\HSGCopy.docx is protected ReadOnly
#>

偶然或故意,您可以将两者都设置在一个环境中。我在自动分类场景中遇到过这种情况。这意味着 FSRM/RMS/AIP 何时已部署/实施和实施。

更新

根据我们的交流,这是我在工作流程中捕获此类内容的示例。

Clear-Host
$Files | 
ForEach{
    $File = $PSItem
    "Processing $PSItem"
    try   
    {
        Write-Verbose -Message 'Word properties:
        DocID, FullName, HasPassword, 
        Permission, ReadOnly, Saved, 
        Creator, CurrentRsid, CompatibilityMode' -Verbose

        'DocID', 'FullName', 'HasPassword', 
        'Permission', 'ReadOnly', 'Saved', 
        'Creator', 'CurrentRsid', 'CompatibilityMode' | 
        ForEach {($Word.documents.open($File,$false,$false)).$PSitem}

        Write-Verbose -Message 'File system ReadOnly attribute:' -Verbose
        (Get-ItemProperty $File).IsReadOnly

        Write-Verbose -Message 'Document state' -Verbose
        $TargetFile = (New-Object System.IO.FileInfo $PSitem).Open(
                                            [System.IO.FileMode]::Open, 
                                            [System.IO.FileAccess]::ReadWrite, 
                                            [System.IO.FileShare]::None
                        )
        $TargetFile.Close()  
        Remove-Item -Path $PSItem -WhatIf  
    }
    catch [System.Management.Automation.ItemNotFoundException]{$PSItem.Exception.Message}
    catch {$PSItem.Exception.Message}
}
# Results
<#
Processing d:\Temp\HSGCopy.docx
VERBOSE: Word properties:
        DocID, FullName, HasPassword, 
        Permission, ReadOnly, Saved, 
        Creator, CurrentRsid, CompatibilityMode
938207550
D:\Temp\HSGCopy.docx
False
True
True
1297307460
12414886
15
VERBOSE: File system ReadOnly attribute:
False
VERBOSE: Document state
What if: Performing the operation "Remove File" on target "D:\Temp\HSGCopy.docx".
#>

【讨论】:

  • Epic +1 接受挑战,我忘记了原因,但我之前已经检查过 docx XML,知道没有 COM/opening doc 也有办法判断
  • 不用担心。文档用户、所有者和政策执行在背后咬了我太多次了。我工作过和仍在工作的所有环境,我都会确保观察者就位以进行属性更改等。数据保管人通常不知道数据处于什么状态,然后我接到一个电话,说为什么 X 或 Y 是这样的。这是高科技保姆。我的代码只是通过文件系统和 DOM/COM 两个级别的属性循环,只是因为。查看我的更新,了解我在警报中执行的操作,或来自此类人的问题。
【解决方案2】:

好的,所以为了测试这个,我有 3 个文件如下:

  • A) 一个普通的test.docx,没有任何限制
  • B) 一个带有密码的readonly.docx。这是让我挂断的文件
  • C) 一个 nopass.docx 具有只读设置,但未配置 PWD。​​li>

无论ReadOnly 设置如何,A 和 C 都会打开,但即使 DisplayAlerts 设置为 0,B 也会挂起。您也无法检查 ReadOnly 属性,除非超出提示,或者如果您将其设置为 TRUE,则它始终为 true。

如果不先打开文档,我无法检查ReadOnlyHasPassword 属性。您可能可以检查 HEX 的 XML 文件,但我会说这不太可靠。我的方式只是采取了一些测试/技巧来开始工作。重要的部分是我必须传递密码并在失败时捕获。即使您传递密码参数,Doc 的 A/C 也会正常打开,因此不会造成任何伤害。在捕获中,我设置了ReadOnly = TRUEVisible = TRUE。您可能不需要将可见部分设置为 true,但如果 ReadOnly = TRUE 则无法通过 VB(如 ORIENTATION)进行某些调整,我将使用 SENDKEYS 所以我需要 UI如果ReadOnly = TRUE。同样,隐藏 UI 只是一个“奖励”,但不是必需的。如果我继续浪费时间为OPENUI 语句编码IF/THEN,我可能会将其设置为始终可见。

无论如何...这是一个最终代码 sn-p 用于测试三个文件,这应该会导致每个文件打开时都没有提示。

 #Constants
 Clear-Variable ReadOnly
 $missing = [System.Type]::Missing
 $str = ''
 $PASSWD = 'IsPWDProtected?'
 $wdAlertsNone = 0
 $FILENAME = "C:\tmp\readonly.docx"
 $OPENUI = "TRUE"

 #Start Word
 $ObjWord = New-Object -comobject Word.Application
 IF ($OPENUI -eq "FALSE"){$ObjWord.Visible  = $FALSE}ELSE{$ObjWord.Visible  = $TRUE}
 $ObjWord.Application.DisplayAlerts = $wdAlertsNone

 #.Open
 IF (!$ConfirmConversions){$ConfirmConversions = $missing}
 IF (!$ReadOnly){$ReadOnly = $FALSE}
 IF (!$AddToRecentFiles){$AddToRecentFiles = $missing}
 IF (!$PasswordDocument){$PasswordDocument = $PASSWD}
 IF (!$PasswordTemplate){$PasswordTemplate = $PASSWD}
 IF (!$Revert){$Revert = $False} 
 IF (!$WritePasswordDocument){$WritePasswordDocument =  $PASSWD}
 IF (!$WritePasswordTemplate){$WritePasswordTemplate =  $PASSWD} 
 IF (!$Format){$Format = 'wdOpenFormatAuto'} 
 IF (!$Encoding){$Encoding = $missing}
 IF (!$Visible){$Visible = $False} 
 try{$ObjDoc=$ObjWord.documents.open($FILENAME,$ConfirmConversions,$ReadOnly,$AddToRecentFiles,$PasswordDocument,$PasswordTemplate,$Revert,$WritePasswordDocument,$WritePasswordTemplate,$Format,$Encoding,$Visible)}
  catch {
     Write-Error  $_
     Write-Host "Opening Read_Only"
     $ReadOnly = $TRUE
     $Visible = $TRUE
     $ObjDoc=$ObjWord.documents.open($FILENAME,$ConfirmConversions,$ReadOnly,$AddToRecentFiles,$PasswordDocument,$PasswordTemplate,$Revert,$WritePasswordDocument,$WritePasswordTemplate,$Format,$Encoding,$Visible)
 }

#AllDone?
PAUSE
$ObjWord.ActiveDocument.Close(0)
$ObjWord.Quit()
[gc]::collect()
[gc]::WaitForPendingFinalizers()
[gc]::collect()
[gc]::WaitForPendingFinalizers()
sleep 2

结果:

PS C:\Users\Admin> C:\tmp\test.ps1
C:\tmp\test.ps1 : The password is incorrect. Word cannot open the document. (C:\tmp\readonly.doc)
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,test.ps1
 
Opening Read_Only
Press Enter to continue...: 

注意:我在测试期间对 OPENUI = TRUE 进行了硬编码,因为如果它在关闭 UI 的提示上挂起,我必须使用 tskill winword.exe 并重新开始。

【讨论】:

  • 很高兴你拥有它。
  • 进一步测试表明这在某种程度上也与VISIBLE 设置有关。如果为假,则通过 PS 无提示打开。我有点朦胧,但无论如何,如果它失败了,这将“抓住它”并将所有麻烦/可见变量设置为 true。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多