Вывод списка открытых файлов
Администратор файлового сервера Windows может вывести список открытых файлов в общей сетевой папке и принудительно закрыть заблокированные файлы, открытые пользователями в монопольном режиме. Если пользователь открыл файл в общей сетевой SMB папке на сервере на чтение и запись и забыл его закрыть (ушел домой, в отпуск), другие пользователи не смогут внести изменения в файл.
Получение списка открытых файлов на сервере Windows
Список открытых по сети файлов в Windows можно получить с помощью графической консоли Computer Management (Управление компьютером).
Откройте консоль
compmgmt.mscи перейдите в раздел System Tools -> Shared Folders -> Open files (Служебные программы -> Общие папки -> Открытые файлы);В правой части окна отображается список открытых файлов. Здесь указаны локальный путь к файлу, имя учетной записи пользователя, количество блокировок и режим, в котором открыт файл (Read или Write+Read).
Также вы можете вывести список открытых на сервере файлов из командной строки:
Openfiles /Query /fo csvКоманда возвращает номер сессии, имя пользователя, количество блокировок и полный путь к файлу.
Работа со списком открытых файлов
Cо списком открытых файлов на сервере удобнее работать с помощью PowerShell командлета Get-SmbOpenFile. В выводе команды содержится имя пользователя, имя (IP адрес) удаленного компьютера, с которого открыт файл, имя файла и ID файловой сессии.
Определение открытого файла на сервере
Чтобы удаленно определить пользователя, который открыл (заблокировал) файл cons.adm в сетевой папке на сервере mskfs01, выполните команду:
Openfiles /query /s mskfs01 /fo table /v | find /i cons.admМожно указать только часть имени файла. Например, чтобы узнать, кто открыл xlsx файл, в имени которого есть строка farm, воспользуйтесь таким конвейером:
Openfiles /query /s server_name /fo table /v | find /i farmПринудительное закрытие открытого файла
Можно закрыть открытый файл через консоль Computer Management. Найдите файл в списке секции Open Files, выберите в контекстном меню пункт “Close Open File”.
Как закрыть открытые файлы в сетевой папке
Если на сервере по сети открыты сотни файлов, то найти нужный файл в графической консоли довольно сложно. Лучше использовать инструменты командной строки.
Закрытие файла через SMB сессию
Чтобы закрыть файл, можно использовать ID его SMB сессии. Получить ID сессии файла можно выполнить команду:
Openfiles /local on | findstr REPORT2023.XLSXТеперь можно принудительно отключить пользователя по полученному идентификатору SMB сессии:
Openfiles /Disconnect /ID 3489847304Вы успешно разблокировали открытый файл и теперь его могут открыть другие пользователи.
Закрытие всех файлов пользователя
Можно принудительно сбросить все сессии и освободить все файлы, открытые определённым пользователем:
openfiles /disconnect /S mskfs01 /U corp\aivanova /ID *Закрытие файла через PowerShell
Можно закрыть открытый файл по ID сессии с помощью PowerShell командлета Close-SmbOpenFile:
Close-SmbOpenFile -SessionId 3489847304Для подтверждения сброса сессии и освобождения открытого файла нажмите Y -> Enter.
Чтобы закрыть файл без предупреждения, добавьте параметр -Force в последнюю команду.
Графический интерфейс для закрытия файлов
С помощью Out-GridView можно сделать простую графическую форму для поиска и закрытия файлов. Следующий скрипт выведет список открытых файлов, которые можно закрыть выборочно.
Осторожно использовать команды
Принудительное закрытие открытого файла на файловом сервере вызывает потерю несохраненных пользователем данных. Поэтому команды openfiles /disconnect и Close-SMBOpenFile нужно использовать с осторожностью.
Удаленное закрытие файлов с помощью PowerShell
Командлеты Get-SMBOpenFile и Close-SmbOpenFile можно использовать чтобы удаленно найти и закрыть открытые файлы. Сначала нужно подключиться к удаленному SMB серверу Windows через CIM сессию:
$sessn = New-CIMSession –Computername mskfs01Также вы можете подключаться к удаленным серверам для запуска команд через командлеты PSRemoting: Enter-PSSession или Invoke-Command.
Следующая команда найдет сессию для открытого файла pubs.docx и завершит ее.
Заключение
В данной статье мы рассмотрели возможности PowerShell для управления открытыми файлами, запланированными задачами в Windows, и взаимодействия с почтовым клиентом Outlook. PowerShell предлагает удобные средства автоматизации, которые могут значительно упростить рутинные задачи системного администратора.
Если у вас есть открытые файлы, которые нужно закрыть или задачи, которые надо автоматизировать, PowerShell может стать незаменимым инструментом для эффективного управления системными ресурсами.
Советуем ознакомиться с документацией PowerShell и провести собственные эксперименты для более полного понимания возможностей этого мощного инструмента.
Ссылка на оригинал статьи: winitpro.ru

PowerShell для управления открытыми файлами
Подтвердите закрытие файла, нажав Y. В результате вы разблокировали открытый файл. Теперь его могут открыть другие пользователи.
Управление запланированными задачами в Windows
Все запланированные задачи в Windows можно посмотреть в Планировщике задач. Автоматизировать Windows возможно как с его помощью, так и чисто на PowerShell. Чтобы вывести все текущие задачи необходимо выполнить:
Get-ScheduledJobЧтобы вывести задачи, запланированные только с помощью PowerShell, используется команда:
Get-ChildItem $HOME\AppData\Local\Microsoft\Windows\PowerShell\ScheduledJobsДля создания задания необходимо выполнить следующую команду:
$Условие = New-JobTrigger -Daily -At 12AM
Register-ScheduledJob -Name NewAD_User -ScriptBlock {######} -Trigger $УсловиеВзаимодействие с Outlook через PowerShell
Для взаимодействия с Outlook через PowerShell необходимо при выполнении действий с почтой закрыть открытое приложение. Пример кода:
## Завершение Outlook
Get-Process | Where-Object {$_.ProcessName -eq OUTLOOK} | Stop-Process
Start-Sleep -Seconds 10
## Создание объекта Outlook
$outlook = New-Object -ComObject Outlook.Application
## Получение коллекции папок
$folders = $outlook.Session.Folders.Item(###Ваш адрес почты####).Folders
## Выбор папки Входящие
$Входящие = $folders.Item(Входящие)
$Исполнено = $folders.Item(Исполнено)
## Получение последнего письма
$Письма = $Входящие.Items | Sort-Object ReceivedTime -DescendingДанная команда позволяет получить список писем из папки Входящие и адрес папки Исполнено для перемещения писем.
foreach ($Письмо in $Письма) { $lines = $Письмо.Body -split `n #Условие чтения письма if ($lines[0].Substring(0, 29) -ne Заявка в IT - Новый сотрудник) {continue} $Дата_заявки = $lines[0].Substring(32).Trim() $Фамилия = $lines[2].Substring(18).Trim() $Имя = $lines[4].Substring(4).Trim() $Отчество = $lines[6].Substring(9).Trim()
}## Создание учетной записи и контакта в PowerShell
## Переменные
- $Отдел = $lines[8].Substring(6).Trim()
- $Должность = $lines[10].Substring(10).Trim()
- $Организация = $lines[12].Substring(12).Trim()
- $Подразделение = $lines[14].Substring(14).Trim()
- $Номер_телефона = $lines[16].Substring(15).Trim()
- $Мобильный_телефон = $lines[18].Substring(18).Trim()
- $Имя_пользователя_для_копирования_групп = $lines[20].Substring(29).Trim()
## Цикл обработки писем
```powershell
## Цикл обработки писем
foreach ($письмо in $почта) { # Преобразование письма в список строк и получение значений # Добавление проверки на случай случайного попадания письма # Создание учетки на удаленном сервере $Сессия = New-PSSession -ComputerName ###Сетевое имя или IP-адресс компа### $Переменные = Invoke-Command -Session $Сессия -ScriptBlock { param(####Все ваши переменные через запятую###) # Команды на удаленном компьютере return Переменные которые вернуться в массив объектов $Переменные } -ArgumentList ###Переменные через запятую которые вы передали в параметры###
}Транслитерация имени
## Транслитерация имени
function global:Translit {} - Функция принимает кириллицу и возвращает латиницу
$count = 0
## Получение списка пользователей AD
$adUsers = Get-ADUser -Filter * -Properties UserPrincipalName
## Создание логина
$Имя_пользователя = Translit($Имя[0] + . + $Фамилия)
$Отображаемое_имя = $Фамилия $Имя
## Проверка на однофамильцев
while ($adUsers.SamAccountName -like *$Имя_пользователя*) { $count = $count + 1 $Имя_пользователя = Translit($Имя[0] + $count + . + $Фамилия) $Отображаемое_имя = $Фамилия $Имя $count # Создание почты на основе логина $Эл_почта = $Имя_пользователя + @mail
}Создание учетной записи и контакта
## Создание учетной записи пользователя
$Пароль = ConvertTo-SecureString -String ###Пароль### -AsPlainText -Force
New-ADUser -SamAccountName $Имя_пользователя -UserPrincipalName $Имя_пользователя -Name $Отображаемое_имя -DisplayName $Отображаемое_имя -GivenName $Имя -Surname $Фамилия -Title $Должность -Mobile $Мобильный_телефон -OfficePhone $Номер_телефона -EmailAddress $Эл_почта -Department $Отдел -Company $Организация -AccountPassword $Пароль -Enabled $true -Path OU=ТЕСТ,DC=domen,DC=local
## Создание контактаNew-ADObject -Name "$Отображаемое_имя" -Type Contact -Path "OU=ТЕСТ_КОНТАКТЫ,OU=ТЕСТ,DC=domen,DC=local" -OtherAttributes @{DisplayName = $Отображаемое_имя; GivenName = "$Имя"; Sn = "$Фамилия"; Mobile = "$Мобильный_телефон"; Mail = "$Эл_почта";telephoneNumber = "444"; Title = "$Должность"; Department = "$Отдел"; Company = "$Организация"}$Исходные_группы = Get-ADUser $Имя_пользователя_для_копирования_групп -Properties MemberOf | Select-Object -ExpandProperty MemberOf
foreach ($группы in $Исходные_группы) { Add-ADGroupMember -Identity $группы -Members $Имя_пользователя
}На этом действия на сервере заканчиваются, закрываем скобки, и переходим в локальную сессию, в качестве отчета я отправлю письмо-ответ на адрес отправителя, для этого получаем переменные из объекта сессии и составляем письмо, после чего перемещаем письмо в папку "Исполнено".
#Получение значений из сессии
$Имя_учетки = $Переменные.GetValue(0)
$Почта = $Переменные.GetValue(1)
#Ответное письмо
$Ответ = $Письмо.ReplyAll()
$Ответ.Body = @"
$Фамилия $Имя $Отчество
$Отдел
$Должность
$Организация
$Имя_учетки
$Почта
$Мобильный_телефон
$Номер_телефона
"@
$Ответ.Send( )
$Письмо.Move($Исполнено)После завершения цикла, закрываем сессию с сервером и закрываем Outlook, через 10 секунд чтобы письма успели отправиться.
#Завершение сессии
Remove-PSSession -Session $Сессия
#Завершение Outlook
Start-Sleep -Seconds 10
Get-Process | Where-Object {$_.ProcessName -eq "OUTLOOK"} | Stop-ProcessОбразец моей заявки:
Заявка в IT - Новый сотрудник от 12.04.2024 10:34:49
Описание: Фамилия: Жданов
Имя: Дмитрий
Отчество: Юрьевич
Отдел: Служба Качества
Должность: Контролер пищевой продукции
Организация: АО "Агрофирма "Бунятино"
Подразделение: -
Номер телефона:
Мобильный телефон: -
Пользователь для копирования:Полный листинг кода:
#----------------Создание сессии------------------------
$Сессия = New-PSSession -ComputerName ServerAD
#-------------------------Чтение почты-----------------------------
#Завершение Outlook
Get-Process | Where-Object {$_.ProcessName -eq "OUTLOOK"} | Stop-Process
Start-Sleep -Seconds 10
# Создание объекта Outlook
$outlook = New-Object -ComObject Outlook.Application
# Получение коллекции папок
$folders = $outlook.Session.Folders.Item("auto-user@agro-holding.ru").Folders
# Выбор папки "Входящие"
$Входящие = $folders.Item("Входящие")
$Исполнено = $folders.Item("Исполнено")
# Получение последнего письма
$Письма = $Входящие.Items | Sort-Object ReceivedTime -Descending
#-------------------------Рабочий алгоритм-----------------------------
#Получение значений переменных из письма
foreach ($Письмо in $Письма) {
$lines = $Письмо.Body -split "`n"
#Условие чтения письма
if ($lines[0].Substring(0, 29) -ne "Заявка в IT - Новый сотрудник") {continue}
$Дата_заявки = $lines[0].Substring(32).Trim()
$Фамилия = $lines[2].Substring(18).Trim()
$Имя = $lines[4].Substring(4).Trim()
$Отчество = $lines[6].Substring(9).Trim()
$Отдел = $lines[8].Substring(6).Trim()
$Должность = $lines[10].Substring(10).Trim()
$Организация = $lines[12].Substring(12).Trim()
$Подразделение = $lines[14].Substring(14).Trim()
$Номер_телефона = $lines[16].Substring(15).Trim()
$Мобильный_телефон = $lines[18].Substring(18).Trim()
$Имя_пользователя_для_копирования_групп = $lines[20].Substring(29).Trim()
#---------------Основная команда создания пользователя на удаленном сервере-----------------
$Переменные = Invoke-Command -Session $Сессия -ScriptBlock { param($Фамилия, $Имя, $Отчество, $Отдел, $Должность, $Организация, $Подразделение, $Номер_телефона, $Мобильный_телефон, $Имя_пользователя_для_копирования_групп)
#---------------Функция транслита-----------------
#Транслит имени
function global:Translit {
param([string]$inString)
$Translit = @{
[char]'а' = "a"
[char]'А' = "a"
[char]'б' = "b"
[char]'Б' = "b"
[char]'в' = "v"
[char]'В' = "v"
[char]'г' = "g"
[char]'Г' = "g"
[char]'д' = "d"
[char]'Д' = "d"
[char]'е' = "e"
[char]'Е' = "e"
[char]'ё' = "yo"
[char]'Ё' = "yo"
[char]'ж' = "zh"
[char]'Ж' = "zh"
[char]'з' = "z"
[char]'З' = "z"
[char]'и' = "i"
[char]'И' = "i"
[char]'й' = "j"
[char]'Й' = "j"
[char]'к' = "k"
[char]'К' = "k"
[char]'л' = "l"
[char]'Л' = "l"
[char]'м' = "m"
[char]'М' = "m"
[char]'н' = "n"
[char]'Н' = "n"
[char]'о' = "o"
[char]'О' = "o"
[char]'п' = "p"
[char]'П' = "p"
[char]'р' = "r"
[char]'Р' = "r"
[char]'с' = "s"
[char]'С' = "s"
[char]'т' = "t"
[char]'Т' = "t"
[char]'у' = "u"
[char]'У' = "u"
[char]'ф' = "f"
[char]'Ф' = "f"
[char]'х' = "h"
[char]'Х' = "h"
[char]'ц' = "c"
[char]'Ц' = "c"
[char]'ч' = "ch"
[char]'Ч' = "ch"
[char]'ш' = "sh"
[char]'Ш' = "sh"
[char]'щ' = "sch"
[char]'Щ' = "sch"
[char]'ъ' = ""
[char]'Ъ' = ""
[char]'ы' = "y"
[char]'Ы' = "y"
[char]'ь' = ""
[char]'Ь' = ""
[char]'э' = "e"
[char]'Э' = "e"
[char]'ю' = "yu"
[char]'Ю' = "yu"
[char]'я' = "ya"
[char]'Я' = "ya"
}
$outCHR=""
foreach ($CHR in $inCHR = $inString.ToCharArray())
{
if ($Translit[$CHR] -cne $Null )
{$outCHR += $Translit[$CHR]}
else
{$outCHR += $CHR}
}
Write-Output $outCHR
}
$count = 0
#---------------Получаем список пользователей AD-----------------
$adUsers = Get-ADUser -Filter * -Properties UserPrincipalName
#---------------------Получение логина---------------------------
#чтобы транслейтить имя надо написать: $Транслит = Translit($имя)
$Имя_пользователя = Translit($Имя[0] + "." + $Фамилия)
$Отображаемое_имя = "$Фамилия $Имя"
#---------------Проверка на однофамильцев-----------------
while ($adUsers.SamAccountName -like "*$Имя_пользователя*") { $count = $count + 1 $Имя_пользователя = Translit($Имя[0] + $count + "." + $Фамилия) $Отображаемое_имя = "$Фамилия $Имя $count"
}
#---------------Создание почты на основе логина-----------------
$Эл_почта = $Имя_пользователя + "@почта"
#---------------------Добавиление в AD-----------------------------
#Пользователь
$Пароль = ConvertTo-SecureString -String "пароль" -AsPlainText -Force
New-ADUser -SamAccountName "$Имя_пользователя" -UserPrincipalName "$Имя_пользователя" -Name $Отображаемое_имя -DisplayName $Отображаемое_имя -GivenName "$Имя" -Surname "$Фамилия" -Title "$Должность" -Mobile "$Мобильный_телефон" -OfficePhone "$Номер_телефона" -EmailAddress "$Эл_почта" -Department "$Отдел" -Company "$Организация" -AccountPassword $Пароль -Enabled $true -Path "OU=ТЕСТ,DC=bun,DC=local"
#Контакт
New-ADObject -Name "$Отображаемое_имя" -Type Contact -Path "OU=ТЕСТ_КОНТАКТЫ,OU=ТЕСТ,DC=bun,DC=local" -OtherAttributes @{DisplayName = $Отображаемое_имя; GivenName = "$Имя"; Sn = "$Фамилия"; Mobile = "$Мобильный_телефон"; Mail = "$Эл_почта";telephoneNumber = "444"; Title = "$Должность"; Department = "$Отдел"; Company = "$Организация"}
#-----------Копируем группы пользователя из контейнера-------------
$Исходные_группы = Get-ADUser $Имя_пользователя_для_копирования_групп -Properties MemberOf | Select-Object -ExpandProperty MemberOf
foreach ($группы in $Исходные_группы) { Add-ADGroupMember -Identity $группы -Members $Имя_пользователя
}
#-----------Возвращение переменных из сессии для ответного письма-------------
return $Имя_пользователя, $Эл_почта, $Фамилия, $Имя, $Отчество, $Отдел, $Должность, $Организация, $Подразделение, $Номер_телефона, $Мобильный_телефон, $Имя_пользователя_для_копирования_групп
} -ArgumentList $Фамилия, $Имя, $Отчество, $Отдел, $Должность, $Организация, $Подразделение, $Номер_телефона, $Мобильный_телефон, $Имя_пользователя_для_копирования_групп
#Получение значений из сессии
$Имя_учетки = $Переменные.GetValue(0)
$Почта = $Переменные.GetValue(1)
#Ответное письмо
$Ответ = $Письмо.ReplyAll()
$Ответ.Body = @"
$Фамилия $Имя $Отчество
$Отдел
$Должность
$Организация
$Имя_учетки
$Почта
$Мобильный_телефон
$Номер_телефона
"@
$Ответ.Send( )
$Письмо.Move($Исполнено)
}
#Завершение Outlook
Start-Sleep -Seconds 10
Get-Process | Where-Object {$_.ProcessName -eq "OUTLOOK"} | Stop-Process
#Завершение сессии
Remove-PSSession -Session $СессияНадеюсь вам помогла моя статья, я постарался максимально понятно разделить код на составные части чтобы его части можно было поменять на собственные.

Here’s how to implement graceful termination mechanisms in PowerShell scripts, both in text-based and GUI-based scenarios.
PowerShell scripts typically run until they finish, but it can be useful to build in a mechanism for the script to terminate gracefully after completing its intended tasks.
Exiting a Text-Based Script
Exiting a GUI-Based Script
Escape Key Termination
Exiting a Text-Based Script
If your script is text-based, adding a termination mechanism is super simple. Just using the command Exit in PowerShell will prompt the script to terminate.
For example, suppose that you had a script containing these commands:
Write-Host ‘Line 1’
Write-Host ‘Line 2’
Exit
Write-Host ‘Line 3’
The script would display the phrases “Line 1” and “Line 2”, but it would never display “Line 3” because the exit command causes the script to terminate before it ever reaches the “Line 3” command.
Figure 1. The last line of code does not execute because the script terminates before reaching that point.
Here is what the code used to create such a prompt might look like:
$Prompt = Read-Host ‘Do you want to continue? Press Y for Yes or N to exit’
Switch ($Prompt)
{
Y {Write-Host 'The script is continuing'} N {Exit}}
Write-Host ‘The script executes yet another instruction’
Exiting a GUI-Based Script
As you can see, terminating a text-based script is simple – just insert the Exit command at the desired termination point. However, let’s look at how you can terminate a GUI-based script.
Here is the source code for a simple GUI-based script:
Add-Type -AssemblyName System.Windows.Forms
Create the form
$form = New-Object Windows.Forms.Form
$form.Text = “Hello World Popup”
$form.Size = New-Object Drawing.Size(500, 500)
$form.FormBorderStyle = [Windows.Forms.FormBorderStyle]::FixedDialog
$form.StartPosition = [Windows.Forms.FormStartPosition]::CenterScreen
$Form.KeyPreview = $True
$Form.Add_KeyDown({if ($_.KeyCode -eq “Escape”)
{$Form.Close()}})Create the label to display “Hello World”
$label = New-Object Windows.Forms.Label
$label.Text = “Hello World”
$label.Font = New-Object Drawing.Font(“Arial”, 14, [Drawing.FontStyle]::Bold)
$label.AutoSize = $true
$label.Location = New-Object Drawing.Point(100, 40)
$label.ForeColor = [System.Drawing.Color]::Black
$Button1 = New-Object System.Windows.Forms.Button
$Button1.Location = New-Object System.Drawing.Size (200,250)
$Button1.Size = New-Object System.Drawing.Size(80,30)
$Button1.Font=New-Object System.Drawing.Font(“Lucida Console”,14,[System.Drawing.FontStyle]::Regular)
$Button1.BackColor = “LightGray”
$Button1.Text = “Exit”
$Button1.Add_Click({
$Form.Close() })Add the label to the form
$form.Controls.Add($label)
$Form.Controls.Add($Button1)
Display the form
$form.ShowDialog()
This script displays the words Hello World within a GUI interface. The only thing that makes it different from any other Hello World script that you might have seen before is that the GUI also contains an exit button, as shown in Figure 3.
Figure 3. This simple Hello World script contains an exit button.
At a functional level, this script is straightforward and works just like any other PowerShell GUI-based script. I began by loading the necessary assemblies. From there, I created a form object, a label object (the Hello World text), and a button object. Then, I told PowerShell to add the label object and the button object to the form and to display the form.
So, now that I have outlined how the script works, let’s examine the exit button. Whenever you create a button object in PowerShell, you have the option of associating a click action with the button. Here are the commands associated with the click action:
$Button1.Add_Click({
$Form.Close() })$Button1.Add_Click({
$Form.Close() Exit })Escape Key Termination
$Form.KeyPreview = $True
$Form.Add_KeyDown({if ($_.KeyCode -eq "Escape")
{$Form.Close()}})The third line tells PowerShell what to do if the escape key is pressed. Once again, we are going to close the form.
As you can see, there are any number of different ways that you can gracefully terminate a PowerShell script. The technique that you use largely depends on whether the script is text-based or GUI-based.
About the author
Brien Posey is a bestselling technology author, speaker, and 21x Microsoft MVP. In addition to his ongoing work in IT, Posey has trained as a commercial astronaut candidate in preparation to fly on a mission to study polar mesospheric clouds from space.em>
Доброго времени суток!
В Windows Server 2019 перед резервным копированием через планировщик срабатывает PowerShell скрипт, который принудительно разрывает файловые сессии у пользователей:
Get-SMBOpenFile | where {$_.Path -like "*.*"} | Close-SMBOpenFile -ForceПо факту файловые сессии не закрываются (Управление компьютером – Общие папки – Открытые файлы)
Запустил скрипт вне планировщика от имени админа, посыпались ошибки вида:
Close-SMBOpenFile : Нет открытого файла с данным идентификационным номером.
C:\ps\useroff.ps1:1 знак:49
+ ... -SMBOpenFile | where {$_.Path -like "*.*"} | Close-SMBOpenFile -Force
+ ~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (MSFT_SmbOpenFile (FileId = 527744999433):ROOT/Microsoft/...SFT_SMBOpenFile) [Close-SmbOpenFile], CimExc eption + FullyQualifiedErrorId : Windows System Error 2314,Close-SmbOpenFile
Close-SMBOpenFile : Буфер возврата API слишком мал.
C:\ps\useroff.ps1:1 знак:49
+ ... -SMBOpenFile | where {$_.Path -like "*.*"} | Close-SMBOpenFile -Force
+ ~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (MSFT_SmbOpenFile (FileId = 521839493137):ROOT/Microsoft/...SFT_SMBOpenFile) [Close-SmbOpenFile], CimExc eption + FullyQualifiedErrorId : Windows System Error 2123,Close-SmbOpenFileМожет скрипт неправильно написан?




