Задача:
На компьютере есть общие сетевые ресурсы. В определенное время с файлами, к которым дан общий доступ, производятся какие-либо запланированные задания, требующие монопольного доступа. Поэтому, перед началом выполнения задания необходимо закрывать все открытые пользователями по сети файлы.
Примечание: из графического интерфейса открытые файлы можно посмотреть из оснастки «Управление компьютером» -> Общие папки -> Открытые файлы.
Решение:
Существует рекомендация от Microsoft: «Как закрыть с помощью командной строки все файлы, открытые сетевыми клиентами»
Собственно, на ее базе можно отбирать любые варианты файлов. Например, по расширению, по части пути и пр.
Следующий пример из командной строки закрывает все открытые файлы с расширением «.CDX»:
Код: Выделить всё
for /f "skip=4 tokens=1,2" %a in ('net files') do if %~xb==.CDX net files %a /close
Конечно, использование PowerShell, будет гораздо удобнее. Если в ранних версиях (до 2 включительно) для получения списка открытых файлов мы могли использовать тот же «net files», то в более старших версиях появился командлет «Get-SmbOpenFile».
Для свежих версий PowerShell все просто. Приведу пример, закрывающий открытые по сети файлы с расширением «.xls»
Код: Выделить всё
Get-SmbOpenFile | foreach-object {if ($_.path -like "*.xls") {Close-SmbOpenFile -Force -FileId $_.FileID}}
Для ранних версий PowerShell скрипт не намного сложнее. Сначала получаем список открытых файлов «net files», потом выбираем из них те которые нужно закрыть, и потом уже закрываем их «net files /close».
В приведенном примере закрываются все файлы из папки «c:\Soft»:
Код: Выделить всё
(net files | select-string -pattern 'c:\\Soft\\' -allmatches) -split "\s",2 | select-string -Pattern "c:\\Soft\\" -NotMatch | foreach-object {net files $_ /close}
Кроме «net files», для старых версий, для удобства можно использовать следующую функцию, позволяющую как выводить список открытых файлов, так и закрывать их:
Вывод имен открытых общих файлов
Код: Выделить всё
Function Get-OpenFiles
{
<#
Аналог утилиты net file.Запуск скрипта без параметров,выведет список открытых общих файлов,
так же поддерживается функция закрытия файлов,как на локальном,там и на удаленном ПК.
Требуются права администратора или соответсвующие. Сервис Server должен быть запущен.
Пример:
PS > Get-OpenFiles
PS > Get-OpenFiles -Id 510
PS > "Server1","Server2" | Get-OpenFiles
#>
[CmdletBinding()]
param (
[parameter(Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[alias("CN")]
[String[]]$ComputerName = ".",
[parameter(ParameterSetName="Close")]
[int[]]$Id
)
begin {
#Объявляем функцию NetFileClose
$signature = @"
[DllImport("netapi32.dll", SetLastError=true, CharSet = CharSet.Unicode)]
public static extern int NetFileClose(
string servername,
int id);
"@
$type = Add-Type -MemberDefinition $signature -Name NetFile -Namespace Win32.Function -PassThru
}
process {
#Получаем список открытых файлов
foreach ($server in $ComputerName)
{
$netfile = [ADSI]"WinNT://$server/LanmanServer"
#Получаем свойства интерфейса IADsResource
$netfile.Invoke("Resources") | foreach {$collection = @()} {
$collection += New-Object PsObject -Property @{
Id = $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
Path = $_.GetType().InvokeMember("Path", 'GetProperty', $null, $_, $null)
UserName = $_.GetType().InvokeMember("User", 'GetProperty', $null, $_, $null)
LockCount = $_.GetType().InvokeMember("LockCount", 'GetProperty', $null, $_, $null)
Server = $server
}
}
}
}
end {
#Если задан параметр -Id ,пытаемся закрыть доступ к файлу
if ($pscmdlet.ParameterSetName -eq "Close"){
foreach ($i in $Id)
{
$collection | Where-Object {$_.Id -eq $i} | Foreach {
$type::NetFileClose($_.Server,$_.Id)
}
}
}
#Если параметр -Id не задан,выводим список открытых файлов.
else {$collection}
}
}