none
PowerShellの実行の挙動の違いについて教えてください RRS feed

  • 質問

  • 前提・実現したいこと

    PowerShellはド素人です。
    あるフォルダを監視して、更新されたら通知を出すコードをWebからコピーして改変しました。
    それをVSCode上で実行すると、思惑通りの動きをするのですが、ps1ファイルを右クリックして「PowerShellで実行」すると、PowerShellの画面が起動され、以下の状態になり、エラーは出ないのですが、通知も来ません。

    以下コードのトースト通知を表示する関数を呼び出す部分をコメントアウトしたところ、ログは吐き出されていたので、関数部分がいけないっぽいのですが、VSCode上で実行するとトースト通知が来るので原因が分かりません。

    ご教授お願いします。

    右クリックで実行した際の画面

    <button class="btnClipboardCopy js-clipboardCopy" data-clipboard-target="#clipboardCopy0" style="outline:none;right:8px;display:inline;border-width:initial;border-style:none;border-color:initial;width:12px;height:12px;background-color:#f8f8f8;background-image:url("/img/common/icnCopy.png?d41d8cd98f00b204e9800998ecf8427e");background-size:12px 12px;background-repeat:no-repeat;cursor:pointer;opacity:0.5;" title="このコードをクリップボードにコピー"></button>

    Id Name PSJobTypeName State HasMoreData Location Command -- ---- ------------- ----- ----------- -------- ------- 1 27f52340-c05... NotStarted False ...

    該当のソースコード

    <button class="btnClipboardCopy js-clipboardCopy" data-clipboard-target="#clipboardCopy1" style="outline:none;right:8px;display:inline;border-width:initial;border-style:none;border-color:initial;width:12px;height:12px;background-color:#f8f8f8;background-image:url("/img/common/icnCopy.png?d41d8cd98f00b204e9800998ecf8427e");background-size:12px 12px;background-repeat:no-repeat;cursor:pointer;opacity:0.5;" title="このコードをクリップボードにコピー"></button>### SHOW TOAST
    function ShowToast {
        [CmdletBinding()]
        PARAM (
            [Parameter(Mandatory=$true)][String] $title,
            [Parameter(Mandatory=$true)][String] $message,
            [Parameter(Mandatory=$true)][String] $detail
        )
    
        [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
        [Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
        [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null
    
        $app_id = '{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\WindowsPowerShell\v1.0\powershell.exe'
        $content = @"
    <?xml version="1.0" encoding="utf-8"?>
    <toast scenario="reminder">
        <visual>
            <binding template="ToastGeneric">
                <text>$($title)</text>
                <text>$($message)</text>
                <text>$($detail)</text>
                <image placement="appLogoOverride" hint-crop="circle" hint-align="center" src="画像ファイルのパス" />
            </binding>
        </visual>
        <actions>
            <input id="snoozeTime" type="selection" defaultInput="15">
                <selection id="1" content="1 minute"/>
                <selection id="15" content="15 minutes"/>
                <selection id="60" content="1 hour"/>
                <selection id="240" content="4 hours"/>
                <selection id="1440" content="1 day"/>
            </input>
            <action activationType="system" arguments="snooze" hint-inputId="snoozeTime" content="" />
            <action activationType="system" arguments="dismiss" content=""/>
        </actions>
    </toast>
    "@
        $xml = New-Object Windows.Data.Xml.Dom.XmlDocument
        $xml.LoadXml($content)
        $toast = New-Object Windows.UI.Notifications.ToastNotification $xml
        [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($app_id).Show($toast)
    }
    
    ### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
        $watcher = New-Object System.IO.FileSystemWatcher
        $watcher.Path = "監視するフォルダパス"
        $watcher.Filter = "*.*"
        $watcher.IncludeSubdirectories = $true
        $watcher.EnableRaisingEvents = $true  
    
    ### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
        $action = { 
            $path = $Event.SourceEventArgs.FullPath
            $FileName = $Event.SourceEventArgs.Name
            $changeType = $Event.SourceEventArgs.ChangeType
    
            $msg = "メッセージ"
    
            ShowToast -title "フォルダ監視" -message $msg -detail $changeType
    
            $logline = "$(Get-Date), $changeType, $path"
            Add-content "ログファイルのパス" -value $logline
        }
    
    ### DECIDE WHICH EVENTS SHOULD BE WATCHED 
        Register-ObjectEvent $watcher "Created" -Action $action
        while ($true) {sleep 900}
    2021年1月29日 2:47

すべての返信

  • こんにちは。フォーラムオペレーターのFarenaです。

    TechNetフォーラムにご投稿くださいましてありがとうございます。

     

    VSCode関連の問題について、より適切なチャネルである MSDNフォーラムにお問い合わせいただくことをお勧めします。

    https://social.msdn.microsoft.com/forums/ja-jp/home

     

    適切な回答が得られやすくなること、後から検索で回答を探しやすくなる、といったメリットがあるためです。

    宜しくお願い致します。


    Please remember to mark the replies as answers if they help.
    If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com.

    2021年2月2日 7:56
    モデレータ
  • ご提示のスクリプトには2点問題があるように思います。

    1つ目は、スクリプトファイル直下にShowToast関数が定義されていますが、Register-ObjectEventコマンドレットの-Actionパラメータに渡す$actionスクリプトブロックはバックグラウンドジョブとして実行、すなわち別プロセスで実行されるため、ShowToast関数は呼び出せません。

    (VSCodeで実行できるのは、ShowToast関数の定義を含むコード全体をコンソールで実行すると、関数定義がグローバルスコープで読み込まれる為と思われます)

    回避方法としては、以下のように$action内でShowToast関数を定義してしまうのが一番簡単かと思います。

    $action = { function ShowToast { ここに関数定義を記述 } $path = $Event.SourceEventArgs.FullPath $FileName = $Event.SourceEventArgs.Name …中略… ShowToast -title "フォルダ監視" -message $msg -detail $changeType …後略… }

    もう1点は、「sleep 900」の部分ですが、これはStart-Sleep -Seconds 900を意味し、900秒(15分)間待機するということになるのですが、この待機中にCreatedイベントが発生しても、即座に$actionスクリプトブロックは実行されず、トースト通知もされないことになります。15分経過後か、スクリプトを強制終了する直前にまとめて通知が出るという挙動になるかと思います。

    この問題を手っ取り早く解決するには、例えばStart-Sleep -Seconds 1のようにスリープ間隔を十分短く(この場合は1秒)することが考えられます。

    2021年2月26日 2:47
    モデレータ