none
Запуск скрипта из под другого пользователя на этом же компьютере.

    Вопрос

  • Коллеги,

    Подскажите какими способами можно это организовать?

    Вкратце нужно отправить письмо, а пользователь, от имени которого выполняется скрипт, не имеет почты.

    Invoke-command не может запустить графический интерфейс.

    start-process я не могу заставить работать с переменными... 

    Пробую вот такой скрипт

    $mailTo = Get-Content "C:\tmp\Alert-$SServer`_$SName-Users.txt"
    $ScriptBlock = {
           
           function Test($date,$path,$body,$sig,$to) {
            $Outlook = New-Object -ComObject Outlook.Application
            $Mail = $Outlook.CreateItem(0)
            $to | % {$mail.recipients.add($_) }
            $Mail.Subject = 'Недоступность сетевого ресурса ' + $path + '  '+ $date + ' с 05:00 до 06:00 '
            $Mail.Body = $body+ $sig
            $Mail.Display()
        }
    }
    Start-Process -FilePath Powershell -Credential $cred -LoadUserProfile -ArgumentList "-Command & {$ScriptBlock Test '$MDate' '$StargetP' '$MessageBody' '$emailSig' '$mailTo'}" #,$commands

    Но на $mailto скрип ругается -

    Start-Process : This command cannot be run due to the error: The parameter is incorrect.

    а Mail.CC вообще не смог заставить работать.

    Без Start-Process этот же скрипт отрабатывает нормально.

    Send-MailMessage работает нормально, но нужно просто открыть outlook, a не посылать письмо.


    • Изменено Kupriyanov 6 августа 2018 г. 11:05
    6 августа 2018 г. 11:04

Ответы

  • Самый простой вариант использовать промежуточный скрипт,например send.ps1:

    param(
    	$MDate,
    	$StargetP,
    	$MessageBody,
    	$emailSig,
    	$mailTo
    )
    
    function Test($date,$path,$body,$sig,$to) {
            $Outlook = New-Object -ComObject Outlook.Application
            $Mail = $Outlook.CreateItem(0)
            $to | % {$mail.recipients.add($_) }
            $Mail.Subject = 'Недоступность сетевого ресурса ' + $path + '  '+ $date + ' с 05:00 до 06:00 '
            $Mail.Body = $body+ $sig
            $Mail.Display()
        }
    
    Test $MDate $StargetP $MessageBody $emailSig $mailTo

    Вызов строки:

    Start-Process -FilePath Powershell -Credential $cred -LoadUserProfile -ArgumentList "-File C:\scripts\send.ps1 $MDate $StargetP $MessageBody $emailSig $mailTo"


    • Помечено в качестве ответа Kupriyanov 10 августа 2018 г. 6:24
    7 августа 2018 г. 7:20
    Отвечающий

Все ответы

  • Более простые конструкции по типу Send-Mailmessage вам не подходят?

    The opinion expressed by me is not an official position of Microsoft

    6 августа 2018 г. 16:14
    Модератор
  • Да, как я и писал, Send-Mailmessage работает.

    Но человеку свойственно ошибаться, поэтому хочется посмотреть, что ты отсылаешь.

    Можно не через start-process. Просто через него мне удалось добиться хоть какого-то положительного результата с подстановкой переменных.

    С $Mail.TO я вроде понял в чем ошибка - функция не пропускает через переменную знаки равно.

    то есть если в явном виде задать переменную $mailto внутри функции, то поле кому заполняется. А если через переменную, то сама функция ругается на переменную.

    Просто поле кому имеет вид =user1;=user2;.... Без знака равно Outlook не всегда правильно резольвит пользователей. Например, user1 будет соответствовать и user1 и user1a.

    А вот поле $Mail.CC при любом раскладе выдает ошибку. Даже если его просто явно задать.

    без start-process и, наверное, самое главное, без функции все норм. но в Start-Process без функции не передать переменную. 

    7 августа 2018 г. 6:42
  • Самый простой вариант использовать промежуточный скрипт,например send.ps1:

    param(
    	$MDate,
    	$StargetP,
    	$MessageBody,
    	$emailSig,
    	$mailTo
    )
    
    function Test($date,$path,$body,$sig,$to) {
            $Outlook = New-Object -ComObject Outlook.Application
            $Mail = $Outlook.CreateItem(0)
            $to | % {$mail.recipients.add($_) }
            $Mail.Subject = 'Недоступность сетевого ресурса ' + $path + '  '+ $date + ' с 05:00 до 06:00 '
            $Mail.Body = $body+ $sig
            $Mail.Display()
        }
    
    Test $MDate $StargetP $MessageBody $emailSig $mailTo

    Вызов строки:

    Start-Process -FilePath Powershell -Credential $cred -LoadUserProfile -ArgumentList "-File C:\scripts\send.ps1 $MDate $StargetP $MessageBody $emailSig $mailTo"


    • Помечено в качестве ответа Kupriyanov 10 августа 2018 г. 6:24
    7 августа 2018 г. 7:20
    Отвечающий
  • С отдельным скриптом тоже не хочет

    Cannot process argument because the value of argument "name" is not valid. Change the v
    alue of the "name" argument and run the operation again.
        + CategoryInfo          : InvalidArgument: (:) [SMB_SendAlertForAll.ps1], PSArgumentException
        + FullyQualifiedErrorId : Argument,SMB_SendAlertForAll.ps1

    8 августа 2018 г. 10:55
  • С отдельным скриптом тоже не хочет

    Cannot process argument because the value of argument "name" is not valid. Change the v
    alue of the "name" argument and run the operation again.
        + CategoryInfo          : InvalidArgument: (:) [SMB_SendAlertForAll.ps1], PSArgumentException
        + FullyQualifiedErrorId : Argument,SMB_SendAlertForAll.ps1

    Приводите тестовые данные и полный скрипт, т.к. параметра $name в скрипте нет.
    8 августа 2018 г. 12:31
    Отвечающий
  • Ваш скрипт один в один. То есть первую часть в скрипт. Вторую (start-process) запускаю из под основного пользователя в powershell_ise.

    Ничего не менял. Согласен, что $name отсутствует. Как я понял это общая ошибка.

    8 августа 2018 г. 13:33
  • Ваш скрипт один в один. То есть первую часть в скрипт. Вторую (start-process) запускаю из под основного пользователя в powershell_ise.

    Ничего не менял. Согласен, что $name отсутствует. Как я понял это общая ошибка.

    Тогда скрин выполнения строки:

    Start-Process -FilePath Powershell -Credential $cred -LoadUserProfile -ArgumentList "-File C:\scripts\send.ps1 123 'C:\test.txt' Тест Тест 't@ya.ru'"

    8 августа 2018 г. 13:44
    Отвечающий
  • Да, так работает, видимо ему какие-то переменные не нравятся. Я попробую по очереди их подставлять.

    Скрин не могу прислать - окно сразу закрывается, поэтому только ошибку перенаправил в файл.

    8 августа 2018 г. 14:20
  • Да, теперь не работает $MessageBody или из-за  переменных внутри, или из-за многострочности.

    а $mail.to и $mail.cc заработали :) даже со спецсимволами.

    А не подскажите, почему start-process -command в моем примере не хочет работать? Просто удобнее, когда все в одном месте, а не по скриптам разбросано.

    8 августа 2018 г. 15:11
  • Ему пробелы не нравятся. Если в значении переменной есть пробелы (переносы строк), скрипт разбивает предложение на отдельные переменные, и каждое новое слово подставляет как новую переменную.
    8 августа 2018 г. 15:18
  • Да, все решилось экранированием кавычек вокруг переменной либо сдвоенными двойными кавычками, либо бэктиком.

    Start-Process-FilePathPowershell-Credential $cred-LoadUserProfile-ArgumentList"-File D:\PS\SMB_SendAlertForAll.ps1 $mDate\\path\\ `"$MessageBody`" `"$emailSig`" $mailTo$mailCC"-RedirectStandardErrorC:\tmp\err.txt

    Остается вопрос, почему не работает start-process -command в моем примере. То есть это в принципе невозможно, или нужно приложить большие усилия?

    8 августа 2018 г. 15:28
  • Ему пробелы не нравятся. Если в значении переменной есть пробелы (переносы строк), скрипт разбивает предложение на отдельные переменные, и каждое новое слово подставляет как новую переменную.

    Использовать удвоенные кавычки для параметров:

    ""$Mdate""


    А не подскажите, почему start-process -command в моем примере не хочет работать? Просто удобнее, когда все в одном месте, а не по скриптам разбросано. - Неправильно передаете строку для выполнения. Так же есть ограничение на количество символов при использовании параметра -Credential около 900, без него ~8100. 

    Для примера:

    $sb = {
    	function Test($date,$path,$body,$sig,$to) {
            $Outlook = New-Object -ComObject Outlook.Application
            $Mail = $Outlook.CreateItem(0)
            $to | % {$mail.recipients.add($_) }
            $Mail.Subject = 'Недоступность сетевого ресурса ' + $path + '  '+ $date + ' с 05:00 до 06:00 '
            $Mail.Body = $body+ $sig
            $Mail.Display()
        }
    
    }
    
    Start-Process -FilePath Powershell -Credential $cred -LoadUserProfile -ArgumentList "-Command &{$sb; test `"`"`"$(Get-Date)`"`"`" C:\file.txt Hello World t@yandex.ru}"
    




    • Изменено KazunEditor 8 августа 2018 г. 16:22
    8 августа 2018 г. 15:47
    Отвечающий
  • Черт, это гениально.

    А  тройные кавычкы - это чтобы первая заэкранировала вторую пару и эта пара внутри скрипта тоже была бы заэкранирована?

    И $messagebody при таком количестве пользователей получается около 200 символов. А это ограничение на 900 символов можно обойти? Или можно ли каким-нибудь другим способом запустить код от другого польователя в PS?

    9 августа 2018 г. 12:36
  • Черт, это гениально.

    А  тройные кавычкы - это чтобы первая заэкранировала вторую пару и эта пара внутри скрипта тоже была бы заэкранирована?

    И $messagebody при таком количестве пользователей получается около 200 символов. А это ограничение на 900 символов можно обойти? Или можно ли каким-нибудь другим способом запустить код от другого польователя в PS?

    А это ограничение на 900 символов можно обойти? - Использовать промежуточный скрипт и/или файлы с параметрами, которые будут передаваться.

    Если у пользователя, административные права, то можно использовать перменные среды на время выполнения скрипта:

    # Создать
    [Environment]::SetEnvironmentVariable("Body","Text","Machine")
    
    # Запуск
    Start-Process ....
    
    # Удалить
    [Environment]::SetEnvironmentVariable("Body",$null,"Machine")

    • Изменено KazunEditor 9 августа 2018 г. 13:32
    9 августа 2018 г. 13:12
    Отвечающий
  • А эта переменная среды появляется только после рестарта PS?

    Хотя даже после перезапуска ругается. Не знаю на что, но видимо на длинную переменную.

    9 августа 2018 г. 15:00
  • А эта переменная среды появляется только после рестарта PS?

    Хотя даже после перезапуска ругается. Не знаю на что, но видимо на длинную переменную.

    Да, т.к. создается новый процесс с другим профилем, то переменная уже есть, но не в текущем. Ограничение у нее 32767, но требуются права администратора.

    $a = "a" * 32000
    [Environment]::SetEnvironmentVariable("Body",$a,"Machine")
    Start-Process -LoadUserProfile -Credential $cred -FilePath powershell -ArgumentList "-nologo -noexit -command &{`$env:body.length}"
    [Environment]::SetEnvironmentVariable("Body",$null,"Machine")

    9 августа 2018 г. 17:02
    Отвечающий
  • Не, с перезагрузкой ещё менее удобно, чем с отдельным файлом. Тем более start-process все равно не принимает даже переменную среды, если они длинная.

    10 августа 2018 г. 6:23
  • Не, с перезагрузкой ещё менее удобно, чем с отдельным файлом. Тем более start-process все равно не принимает даже переменную среды, если они длинная.

    Перезагружать не надо, т.к. создается новый процесс через Start-Process  в нем уже есть новые  переменные среды. В Start-Process она участвует в виде имени,а не ввиде содержимого. Скрин я выше привел.
    10 августа 2018 г. 7:12
    Отвечающий
  • Попробую, но он у меня без перезагрузки использует старое значение переменной, а даже если перезагрузить, то все равно ругается на длинную переменную. Может это из-за тройных кавычек...

    10 августа 2018 г. 7:55
  • Попробую, но он у меня без перезагрузки использует старое значение переменной, а даже если перезагрузить, то все равно ругается на длинную переменную. Может это из-за тройных кавычек...

    Как видим ниже, все работает без перезагрузки, значения обновляются, строка передается 32000 символов, длинной переменной нет и не может быть, если быть внимательным.


    10 августа 2018 г. 8:10
    Отвечающий
  • А вот сейчас проверил -File и там тоже у меня сработало ограничение на количество символов.

    Видимо в первый раз неправильно проверял.

    То есть в не зависимости от аргумента и -command и -file выдают, что

    Start-Process : This command cannot be run due to the error: The parameter is incorrect.

    И это если сделать текст письма большим. Может ещё что-то надо включить, чтобы при параметре -credential, start-process пропускал больше 900 символов?


    Может от версии зависит, или от того, что я в ISE запускаю?
    • Изменено Kupriyanov 8 ч. 45 мин. назад
    8 ч. 46 мин. назад
  • А вот сейчас проверил -File и там тоже у меня сработало ограничение на количество символов.

    Видимо в первый раз неправильно проверял.

    То есть в не зависимости от аргумента и -command и -file выдают, что

    Start-Process : This command cannot be run due to the error: The parameter is incorrect.

    И это если сделать текст письма большим. Может ещё что-то надо включить, чтобы при параметре -credential, start-process пропускал больше 900 символов?


    Может от версии зависит, или от того, что я в ISE запускаю?

    Не у -File,а у параметра -ArgumentList. И powershell тут не причем. Т.к. Start-Process использует .Net класс System.Diagnostics.Process внутри, где и есть это ограничение.

    cmd:

    Cmd:
    PS > Start-Process cmd -Credential "" -ArgumentList "/c echo $(""a""*1000)"
    Start-Process : This command cannot be run due to the error: The parameter is incorrect.

    $startInfo = New-Object System.Diagnostics.ProcessStartInfo  -Property @{
    	UseShellExecute = $false
    	LoadUserProfile = $true
    	FileName = "C:\WINDOWS\system32\cmd.exe"
        UserName = "MyUser"
        Domain = "$env:ComputerName"
        Password = $(ConvertTo-SecureString 'P@$$word' -Force -AsPlainText)
        Arguments = "/k echo $(`"a`"*1000)"
    }
    
    [System.Diagnostics.Process]::Start($startInfo)

    Как вариант можно поробовать добавить переменную среды, через ProcessStartInfo:

    $startInfo = New-Object System.Diagnostics.ProcessStartInfo -Property @{
    	UseShellExecute = $false
    	LoadUserProfile = $true
    	FileName = "powershell"
        UserName = "MYuser"
        Domain = "MyDomain"
        Password = $(ConvertTo-SecureString 'MyPassword' -Force -AsPlainText)
        Arguments = "-noexit -command `"&{`$env:BodyMessage}`""
    }
    
    $startInfo.Environment.Add("BodyMessage",("a"*10000))
    
    [System.Diagnostics.Process]::Start($startInfo)

    7 ч. 40 мин. назад
    Отвечающий
  • Да, еще раз переписал с самого начала. Получилось вот так:

     

    [Environment]::SetEnvironmentVariable("eBody",$MessageBody,"Machine") [Environment]::SetEnvironmentVariable("eTo",$mailTo,"Machine") Start-Process -FilePath Powershell -Credential $cred -ArgumentList "-nologo -noexit -command &{ $sb; test1 $mDate path `$env:eBody ""Sig"" `$env:eTo ""`'$mailCC`'""}"

    [Environment]::SetEnvironmentVariable("Body",$null,"Machine") [Environment]::SetEnvironmentVariable("eTo",$null,"Machine")


    Действительно всё работает, но двойные, тройные ковычки да ещё и с бэктиками - это как-то совсем запутано.


    То есть переменную с точками и односложный текст, пропускает просто так; длинные через `$env: ; со спецсимволами в тройных кавычках ""`'$xxx`'""
    • Изменено Kupriyanov 3 ч. 7 мин. назад Уточнил
    3 ч. 12 мин. назад