我正在收集有关网络驱动器权限的数据,我已经能够获取我想要的数据,但我希望能够更好地处理错误,尤其是对于“访问被拒绝”,我没有权限查看文件夹权限。
$PathtoScan = "\\folderxxx\folderyyy"
$GetFileInfo=Get-ChildItem "$PathtoScan" -Recurse -ErrorAction Stop |
Where {$_.Mode -match "d"} |
Get-NTFSAccess | Select-Object Name,FullName,InheritanceEnabled,IsInherited,
InheritedFrom, AccessRights, Account |
Export-Csv C:\Scripts\dump.csv -NoTypeInformation
try {
$GetFileInfo
}
catch [System.UnauthorizedAccessException] {Write-Host "Message:
[$($_.Exception.Message)" | Out-File C:\Scripts\test.txt ]
}
我试图捕获的错误消息:
Get-NTFSAccess : (5) Access is denied: [\\folderxxx\folderyyy]
At C:\Scripts\ACL.ps1:4 char:1
+ Get-NTFSAccess | Select-Object Name,FullName,InheritanceEnabled,IsInh ...
+ CategoryInfo : WriteError: (\\folderxxx\folderyyy) [Get-NTFSAccess], UnauthorizedAccessException
+ FullyQualifiedErrorId : ReadSecurityError,NTFSSecurity.GetAccess
理想情况下,我想将路径导出到我无权访问的位置,以查看修复权限。
我使用:$Error[0].exception | Get-Member
来更好地了解我想要捕获的错误:System.UnauthorizedAccessException
有什么想法吗?
谢谢!
答案 0 :(得分:4)
这里有很多错误。
首先,你这样做:
$GetFileInfo = Get-ChildItem [...] |
[...] |
Export-Csv C:\Scripts\dump.csv -NoTypeInformation
Export-Csv
根本不会将任何对象返回到标准输出。您可以使用-PassThru
参数覆盖执行此操作的某些cmdlet,但Export-Csv
不支持该参数。 $GetFileInfo
总是将成为$null
。您的脚本结构让我觉得您不了解管道和输出的工作原理。当你写下这样的东西时:
$x = Get-Item -Path C:\
当您致电$x
时,您不会编写要执行的命令。命令立即执行 ,将这些命令的标准输出分配给变量$x
。
你似乎在后面的catch块中犯了同样的错误:
Write-Host "Message: [$($_.Exception.Message)" | Out-File C:\Scripts\test.txt ]
我不知道这是怎么做的,但我保证它不会做你认为它做的事情。同样,Write-Host
和Out-File
都不会将输出发送到标准输出,并且cmdlet都不支持-PassThru
。看:
PS C:\> Write-Host Hello World | Out-File C:\test.txt
Hello World
PS C:\> Get-Content C:\test.txt
PS C:\>
我所做的只是打印“Hello World”并在C:\test.txt
创建一个空文件。 Write-Host
非常具有欺骗性,因为它看起来像是在写标准输出,但事实并非如此。它直接写入控制台。这就是您经常看到人们说“您可能想要Write-Output
而不是Write-Host
”的原因,因为Write-Output
会写入标准输出。但是,这不是必要的。您通常根本不能使用cmdlet进行输出。
我猜你想要这个:
"Message: [$($_.Exception.Message)]" | Out-File C:\Scripts\test.txt -Append
接下来,您还要这样做来过滤目录:
$GetFileInfo = Get-ChildItem "$PathtoScan" -Recurse -ErrorAction Stop |
Where {$_.Mode -match "d"} |
您永远不想使用Mode
属性。它非常慢。事实上,Mode
是Get-ChildItem
因默认输出而变慢的原因。如果只需要目录,请执行以下操作:
$GetFileInfo = Get-ChildItem "$PathtoScan" -Recurse -Directory -ErrorAction Stop |
Get-NTFSAccess | [...]
或者,在PowerShell v2及更早版本中:
$GetFileInfo = Get-ChildItem "$PathtoScan" -Recurse -ErrorAction Stop |
Where-Object { $_.PSIsContainer } |
Get-NTFSAccess | [...]
所以,上面让我们更接近:
$PathtoScan = "\\folderxxx\folderyyy"
try {
Get-ChildItem "$PathtoScan" -Recurse -Directory -ErrorAction Stop |
Get-NTFSAccess | Select-Object Name,FullName,InheritanceEnabled,IsInherited,
InheritedFrom, AccessRights, Account |
Export-Csv C:\Scripts\dump.csv -NoTypeInformation
}
catch {
"Message: [$($_.Exception.Message)" | Out-File C:\Scripts\test.txt ]
}
但是,在Get-ChildItem
引发的第一个错误中,这仍然会完全停止执行。再说一次,这可能不是你想要的。我猜你想要更接近这个:
$PathtoScan = "\\folderxxx\folderyyy"
# Clear the automatic error variable
$Error.Clear()
# Run the commands, but don't stop for any errors encountered and export the results to file
Get-ChildItem "$PathtoScan" -Recurse -Directory -ErrorAction SilentlyContinue |
Get-NTFSAccess | Select-Object Name,FullName,InheritanceEnabled,IsInherited,
InheritedFrom, AccessRights, Account |
Export-Csv C:\Scripts\dump.csv -NoTypeInformation
# If there were errors
if ($Error) {
# Reverse the $Error ArrayList variable to put the oldest events first
$Error.Reverse()
# Write all the errors from the automatic error variable to file
$Error | ForEach-Object {
"Message: [$($_.Exception.Message)]"
} | Out-File C:\Scripts\test.txt # You might want an -Append here
}
答案 1 :(得分:1)
您尝试在已经发生错误后尝试捕获错误。在$GetFileInfo
块中包含Try{}
的初始分配。在您的示例中,我甚至不确定您为什么首先将该命令流分配给变量。如果您尝试取消输出,则应执行$Null=
要确切知道要使用Catch [Errortype]
抛出哪个错误,请输入
Catch { Write-Output "[$($_.Exception.GetType().FullName)] $($_.Exception.Message)" }
在您的区块中。我还建议在开头使用$ErrorActionPreference='Stop'
。