У меня возникла задача отключения компьютеров по расписанию с помощью скрипта CMD. Я написал следующий код: <pre><code class="dos">Setlocal EnableDelayedExpansion @ECHO OFF SET file=hosts.txt SET username=megoodminЪ SET pass=megoodminЪ_password FOR /F %%i IN (%file%) DO ( SET tmpip=%%i NET USE \\!!tmpip! %pass% /USER:%username% IF errorlevel 1 GOTO fail REM SHUTDOWN /R /T 30 /F /M \\!!tmpip! IF errorlevel 1 GOTO fail ECHO Shutdown !!tmpip! success REM GOTO next :fail ECHO Shutdown !!tmpip! failed :next NET USE \\!!tmpip! /DELETE )</code></pre> На данный момент я закомментировал строку с командой shutdown и заменил параметр /s на /r для тестирования. Однако, после успешного выполнения основного блока циклу следующая инструкция после метки fail все равно выполняется — логирует сообщение об ошибке. Если убрать REM перед GOTO, как показано ниже: <pre><code class="dos">Setlocal EnableDelayedExpansion @ECHO OFF SET file=hosts.txt SET username=megoodminЪ SET pass=megoodminЪ_password FOR /F %%i IN (%file%) DO ( SET tmpip=%%i NET USE \\!!tmpip! %pass% /USER:%username% IF errorlevel 1 GOTO fail REM SHUTDOWN /R /T 30 /F /M \\!!tmpip! IF errorlevel 1 GOTO fail ECHO Shutdown !!tmpip! success GOTO next :fail ECHO Shutdown !!tmpip! failed :next NET USE \\!!tmpip! /DELETE )</code></pre> то после успешного выполнения основного блока код переходит к метке next, и, соответственно, цикл завершается. Я не понимаю, в чем может быть ошибка. Возможно, я чего-то не знаю о порядке выполнения команд в CMD или мне нужно сменить профессию...
Ваша проблема заключается в области видимости меток и контроля потока в командном интерпретаторе Windows (CMD). Ваша логика подразумевает использование меток для управления выполнением кодовых блоков, но в командных циклах `FOR` поведение отличается от обычных условных операторов.
Предлагаю рассмотреть ваш код и внести некоторые изменения, чтобы добиться нужного результата.
### Основные моменты:
1. **Область видимости меток:** Каждая метка, которую вы определяете (например, `:fail` и `:next`), имеет локальную область видимости в теле цикла `FOR`. Если вы используете `GOTO`, он может выйти из цикла, но не перейдет к следующей итерации. Это приведет к тому, что код после метки `:next` не будет выполняться, и выполнение вернется в начало цикла.
2. **Логика управления потоком:** Вместо использования `GOTO` между метками, можно использовать переменные для управления потоком выполнения.
### Пример исправленного кода:
```cmd
@ECHO OFF
Setlocal EnableDelayedExpansion
SET file=hosts.txt
SET username=megoodminЪ
SET pass=megoodminЪ_password
FOR /F %%i IN (%file%) DO (
SET tmpip=%%i
NET USE \\!!tmpip! %pass% /USER:%username%
IF errorlevel 1 (
ECHO Shutdown !!tmpip! failed
NET USE \\!!tmpip! /DELETE
GOTO next
)
REM SHUTDOWN /R /T 30 /F /M \\!!tmpip!
IF errorlevel 1 (
ECHO Shutdown !!tmpip! failed
) ELSE (
ECHO Shutdown !!tmpip! success
)
NET USE \\!!tmpip! /DELETE
:next
)
```
### Основные изменения:
- Вложенные блоки if используют скобки `()` для явного определения, что следует делать в случае ошибки.
- Убраны метки `:fail` и `:next` для упрощения логики. Вместо этого осуществляется только прерывание текущей итерации с помощью `GOTO next`.
- Пользуйтесь `NET USE \\!!tmpip! /DELETE` только один раз после обработки IP и возможного отключения.
Теперь после неудачной попытки подключения к компьютеру через `NET USE`, выполнение переходит к следующему IP из файла, а не к меткам, что обеспечивает корректное поведение цикла.
<blockquote>Решил не усложнять, написать на CMD</blockquote> да и на Powershell не сложнее... <br/> <pre><code>$Comps = Get-Content -Path hosts.txt $Cred = Get-Credential -Credential YourDomain\megoodminЪ Stop-Computer -ComputerName $Comps -Force -Credential $Cred</code></pre>