vague memory

うろ覚えを無くしていこうともがき苦しむ人の備忘録

Upstart の自動起動無効化

世の中systemdなので無用の長物になりそうですがメモ。
公式に記載がある通りです。

Ubuntuだと14.10以降は override が利用できるようですが、 CentOS6 や Amazon Linux の場合、 提供されている upstart のバージョンが古く、 override は利用できないようです。

公式

With Upstart 0.6.7, to stop Upstart automatically starting a job, you can either:

  • Rename the job configuration file such that it does not end with ".conf".
  • Edit the job configuration file and comment out the "start on" stanza using a leading '#'.

version 1.3 以上では、override ファイルが利用可能

With Upstart 1.3, you can make use of an "override file" and the manual stanza to achieve the same result in a simpler manner [31]:

# echo "manual" >> /etc/init/myjob.override

Note that you could achieve the same effect by doing this:

# echo "manual" >> /etc/init/myjob.conf

公式の Override の説明リンクが切れてますが、 アーカイブがありました。 upstart.at が既に無いようです。

検証

Amazon Linux の ssm-agent が upstart での起動なので、そちらで検証してみます。

  • 環境
$ grep PRETTY_NAME /etc/os-release
PRETTY_NAME="Amazon Linux AMI 2018.03"
$ initctl --version
initctl (upstart 0.6.5)

a) リネーム

効きました。

$ ls -l /etc/init/amazon-ssm-agent.*
-rw-r--r-- 1 root root 760  8月  3  2018 /etc/init/amazon-ssm-agent.conf_

b) コメントアウト

効きました。

$ diff /etc/init/amazon-ssm-agent.conf.org /etc/init/amazon-ssm-agent.conf
17c17
< start on (runlevel [345] and started network)
---
> #start on (runlevel [345] and started network)
$

c) overrideファイルへ "manual"

効きません。

$ ls -l /etc/init/amazon-ssm-agent.*
-rw-r--r-- 1 root root 760  8月  3  2018 /etc/init/amazon-ssm-agent.conf
-rw-r--r-- 1 root root   7  3月 15 01:10 /etc/init/amazon-ssm-agent.override
$ sudo cat /etc/init/amazon-ssm-agent.override
manual
$
  • reboot 後
$ uptime
 01:11:17 up 0 min,  1 user,  load average: 0.08, 0.02, 0.01
$ ps -ef | grep [s]sm-agent
root      2266     1  0 01:11 ?        00:00:00 /usr/bin/amazon-ssm-agent
$

d) confファイルへ "manual"

効きました。

$ diff /etc/init/amazon-ssm-agent.conf.org /etc/init/amazon-ssm-agent.conf
22a23
> manual
$

Ansible include_tasks で become_user

include_tasks を使用した時に読み込んだタスク全てに become 指定するにはどうするのかを調べたメモ。

バージョンにより挙動は変わりそうですが、 ver 2.9.5 時点では以下の挙動のようです。

include_tasks に become は使用できないので、 読み込まれるタスク側で block を使用して全体に適用することになります。

実行例

id と whoami で実行ユーザを確認します。 sub2.yml を include_tasks で読み込みます。

  • main.yml
---
- hosts: all
  tasks:
   ### tasks
   - name: task1
     command: id
     register: result

   - name: task1 result
     debug: var=result.stdout

   - name: task2
     command: whoami
     register: result

   - name: task2 result
     debug: var=result.stdout

   ### import_tasks
   - name: sub1
     import_tasks: sub1.yml
     tags: ["sub1"]
     become: yes

   - name: sub1
     import_tasks: sub1.yml
     tags: ["sub1"]
     become: yes
     become_user: cwagent

   ### include_tasks (loop)
   - name: sub2
     include_tasks: sub2.yml
     with_items:
       - "root"
       - "cwagent"
     loop_control:
       loop_var: loop_item
     tags: ["sub2"]
  • sub1.yml
- name: sub1_task1
  command: id
  register: result

- name: sub1_task1 result
  debug: var=result.stdout

- name: sub1_task2
  command: whoami
  register: result

- name: sub1_task2 result
  debug: var=result.stdout
  • sub2.yml
- block:

  - name: sub2_item
    debug: var=loop_item

  - name: sub2_task1
    command: id
    register: result

  - name: sub2_task1 result
    debug: var=result.stdout

  - name: sub2_task2
    command: whoami
    register: result

  - name: sub2_task2 result
    debug: var=result.stdout

  become: yes
  become_user: "{{ loop_item }}"
  tags: ["sub2"]

実行結果

$ ansible-playbook -i hosts main.yml

PLAY [all] ******************************************************************************

TASK [Gathering Facts] ******************************************************************
ok: [test-instance]

TASK [task1] ****************************************************************************
changed: [test-instance]

TASK [task1 result] *********************************************************************
ok: [test-instance] => {
    "result.stdout": "uid=1000(ec2-user) gid=1000(ec2-user) groups=1000(ec2-user),4(adm),10(wheel),190(systemd-journal)"
}

TASK [task2] ****************************************************************************
changed: [test-instance]

TASK [task2 result] *********************************************************************
ok: [test-instance] => {
    "result.stdout": "ec2-user"
}

TASK [sub1_task1] ***********************************************************************
changed: [test-instance]

TASK [sub1_task1 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "uid=0(root) gid=0(root) groups=0(root)"
}

TASK [sub1_task2] ***********************************************************************
changed: [test-instance]

TASK [sub1_task2 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "root"
}

TASK [sub1_task1] ***********************************************************************
[WARNING]: Unable to use /home/cwagent/.ansible/tmp as temporary directory, failing back
to system: [Errno 13] Permission denied: '/home/cwagent'
changed: [test-instance]

TASK [sub1_task1 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "uid=995(cwagent) gid=993(cwagent) groups=993(cwagent)"
}

TASK [sub1_task2] ***********************************************************************
changed: [test-instance]

TASK [sub1_task2 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "cwagent"
}

TASK [sub2] *****************************************************************************
included: /private/tmp/ansible-test/sub2.yml for test-instance
included: /private/tmp/ansible-test/sub2.yml for test-instance

TASK [sub2_item] ************************************************************************
ok: [test-instance] => {
    "loop_item": "root"
}

TASK [sub2_task1] ***********************************************************************
changed: [test-instance]

TASK [sub2_task1 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "uid=0(root) gid=0(root) groups=0(root)"
}

TASK [sub2_task2] ***********************************************************************
changed: [test-instance]

TASK [sub2_task2 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "root"
}

TASK [sub2_item] ************************************************************************
ok: [test-instance] => {
    "loop_item": "cwagent"
}

TASK [sub2_task1] ***********************************************************************
changed: [test-instance]

TASK [sub2_task1 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "uid=995(cwagent) gid=993(cwagent) groups=993(cwagent)"
}

TASK [sub2_task2] ***********************************************************************
changed: [test-instance]

TASK [sub2_task2 result] ****************************************************************
ok: [test-instance] => {
    "result.stdout": "cwagent"
}

PLAY RECAP ******************************************************************************
test-instance              : ok=25   changed=10   unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

import_tasks と include_tasks について

いずれも別ファイルのタスクを読み込む機能ですが、 静的か動的かということで挙動が異なります。 基本的には import 、ループしたい場合は include という感じでしょうか。

list オプションでの確認例

$ ansible-playbook -i hosts main.yml --list-hosts

playbook: main.yml

  play #1 (all): all    TAGS: []
    pattern: ['all']
    hosts (1):
      test-instance
$ ansible-playbook -i hosts main.yml --list-tasks

playbook: main.yml

  play #1 (all): all    TAGS: []
    tasks:
      task1 TAGS: []
      task1 result  TAGS: []
      task2 TAGS: []
      task2 result  TAGS: []
      sub1_task1    TAGS: [sub1]
      sub1_task1 result TAGS: [sub1]
      sub1_task2    TAGS: [sub1]
      sub1_task2 result TAGS: [sub1]
      sub1_task1    TAGS: [sub1]
      sub1_task1 result TAGS: [sub1]
      sub1_task2    TAGS: [sub1]
      sub1_task2 result TAGS: [sub1]
      sub2  TAGS: [sub2]

$ ansible-playbook -i hosts main.yml --list-tags

playbook: main.yml

  play #1 (all): all    TAGS: []
      TASK TAGS: [sub1, sub2]

AWS CloudWatch Dashboard 複製

簡単にコピーしたかったのです。

同一アカウント

マネジメントコンソール上で別名で保存が簡単かと思います。

f:id:htnosm:20190811141000p:plainf:id:htnosm:20190811141008p:plain

別アカウント

CLI を使います。 jq 使います。

# 複製元のAWSアカウントから DashboardBody を取得

$ aws cloudwatch get-dashboard \
--dashboard-name "sample-dashboard" \
--query 'DashboardBody' > sample-dashboard.json


# 複製先のAWSアカウントに対して、取得した JSON でダッシュボード作成

$ aws cloudwatch put-dashboard \
--dashboard-name "sample-dashboard-copy" \
--dashboard-body "$(jq -r . sample-dashboard.json)"

{
    "DashboardValidationMessages": []
}

jq が無い環境では自力で JSON 書式を調整します。
Text Widget で改行使っている等がある場合はその辺りも考慮必要です。 (下記例は考慮していません) 複製してから修正すれば良い訳ですが。

# sed 例
$ aws cloudwatch put-dashboard \
--dashboard-name "sample-dashboard-copy" \
--dashboard-body "$(sed -e 's/\\"/"/g' -e 's/^"//' -e 's/"$//' sample-dashboard.json)"

おまけでワンライナー

$ aws cloudwatch put-dashboard \
--dashboard-name "sample-dashboard-copy" \
--dashboard-body "$(aws cloudwatch get-dashboard \
  --dashboard-name "sample-dashboard" \
  --query 'DashboardBody' | jq -r . )"

dashboard-name を同一名にしてしまうと上書きされるので注意です。

AWS CloudWatch ECSタスク数

普通に公式に記載がありますが、当たり前過ぎて逆に辿り着くのに時間を要したのでメモ。

データが常時報告される何かしらのメトリクス(CPUUtilization等)の SampleCount で、 RUNNING状態のタスク数のみではありますが、簡単に参照できます。 合計(SUM(METRICS()))すればCluster単位でも出せます。

データポイントの数なので、 Period は 1 Minute です。 (保持期間より過去に遡る場合は、延ばした Period 分で除算すれば算出可能)

ECS (Fargate) のタスク数推移を見たかったわけですが、 サードパーティ製監視サービスの統合機能だと、 Running Task だったり DesiredCount だったり、そのものズバリの名前でメトリクスが用意されているので CloudWatchでも同様のメトリクスがあるものと勝手に思い込んでました。

Ansible で AWS Systems Manager パラメータストア (ついでにシークレットマネージャー) から値を取得

Parameter Store

パラメータストア参照は aws_ssm プラグインで行えます。 version 2.5 から実装されているようです。

Requirements 記載の通り、 botocore,boto3 が必要になります。インストールされていない状態だと下記エラーとなります。

FAILED! => {"msg": "An unhandled exception occurred while running the lookup plugin 'aws_ssm'. Error was a <class 'ansible.errors.AnsibleError'>, original message: botocore and boto3 are required for aws_ssm lookup."}

DescribeParameters

# ap-northeast-1
+---------------+--------------------+----------------+
|     KeyId     |       Name         |     Type       |
+---------------+--------------------+----------------+
|  alias/aws/ssm|  an1-securestring  |  SecureString  |
|  None         |  an1-string        |  String        |
|  None         |  an1-stringlist    |  StringList    |
+---------------+--------------------+----------------+

# us-west-2
+---------------+--------------------+----------------+
|     KeyId     |       Name         |     Type       |
+---------------+--------------------+----------------+
|  alias/aws/ssm|  uw2-securestring  |  SecureString  |
|  None         |  uw2-string        |  String        |
|  None         |  uw2-stringlist    |  StringList    |
+---------------+--------------------+----------------+

tasks例

存在しないパラメータはエラーにならず空文字で返却されるため、値チェックを入れた方が良さそうです。

  pre_tasks:
    - name: 'set ssm parameter store values'
      set_fact:
        an1:
          string: "{{ lookup('aws_ssm', 'an1-string') }}"
          securestring: "{{ lookup('aws_ssm', 'an1-securestring') }}"
          stringlist: "{{ lookup('aws_ssm', 'an1-stringlist') }}"
          not_exist: "{{ lookup('aws_ssm', 'dummy') }}"
        uw2:
          string: "{{ lookup('aws_ssm', 'uw2-string', region='us-west-2') }}"
          securestring: "{{ lookup('aws_ssm', 'uw2-securestring', region='us-west-2') }}"
          stringlist: "{{ lookup('aws_ssm', 'uw2-stringlist', region='us-west-2') }}"
          not_exist: "{{ lookup('aws_ssm', 'dummy') }}"

    - name: 'check ssm parameter store values'
      debug: msg="check variable {{ item }}"
      failed_when: '{{ item }} == ""'
      ignore_errors: yes
      with_items:
        - "an1.string"
        - "an1.securestring"
        - "an1.stringlist"
        - "an1.not_exist"
        - "uw2.string"
        - "uw2.securestring"
        - "uw2.stringlist"
        - "uw2.not_exist"

  tasks:
    - name: 'output ssm parameter store values'
      debug: var="{{ item }}"
      with_items:
        - "an1.string"
        - "an1.securestring"
        - "an1.stringlist"
        - "an1.not_exist"
        - "uw2.string"
        - "uw2.securestring"
        - "uw2.stringlist"
        - "uw2.not_exist"

実行結果

TASK [set ssm parameter store values] ***************************************************
ok: [test-instance]

TASK [check ssm parameter store values] *************************************************
 [WARNING]: when statements should not include jinja2 templating delimiters such as {{
}} or {% %}. Found: {{ item }} == ""

ok: [test-instance] => (item=an1.string) => {
    "msg": "check variable an1.string"
}
ok: [test-instance] => (item=an1.securestring) => {
    "msg": "check variable an1.securestring"
}
ok: [test-instance] => (item=an1.stringlist) => {
    "msg": "check variable an1.stringlist"
}
failed: [test-instance] (item=an1.not_exist) => {
    "msg": "check variable an1.not_exist"
}
ok: [test-instance] => (item=uw2.string) => {
    "msg": "check variable uw2.string"
}
ok: [test-instance] => (item=uw2.securestring) => {
    "msg": "check variable uw2.securestring"
}
ok: [test-instance] => (item=uw2.stringlist) => {
    "msg": "check variable uw2.stringlist"
}
failed: [test-instance] (item=uw2.not_exist) => {
    "msg": "check variable uw2.not_exist"
}
fatal: [test-instance]: FAILED! => {"msg": "All items completed"}
...ignoring

TASK [output ssm parameter store values] ************************************************
ok: [test-instance] => (item=an1.string) => {
    "an1.string": "Tokyo文字列",
    "item": "an1.string"
}
ok: [test-instance] => (item=an1.securestring) => {
    "an1.securestring": "Tokyo secure文字列",
    "item": "an1.securestring"
}
ok: [test-instance] => (item=an1.stringlist) => {
    "an1.stringlist": "Tokyo リスト1,Tokyo リスト2,Tokyo リスト3",
    "item": "an1.stringlist"
}
ok: [test-instance] => (item=an1.not_exist) => {
    "an1.not_exist": "",
    "item": "an1.not_exist"
}
ok: [test-instance] => (item=uw2.string) => {
    "item": "uw2.string",
    "uw2.string": "Oregon 文字列"
}
ok: [test-instance] => (item=uw2.securestring) => {
    "item": "uw2.securestring",
    "uw2.securestring": "Oregon secure文字列"
}
ok: [test-instance] => (item=uw2.stringlist) => {
    "item": "uw2.stringlist",
    "uw2.stringlist": "Oregon リスト1,Oregon リスト2,Oregon リスト3"
}
ok: [test-instance] => (item=uw2.not_exist) => {
    "item": "uw2.not_exist",
    "uw2.not_exist": ""
}

Secrets Manager

aws_secret プラグインを使う方法と、aws_ssm 経由で取得する方法の2パターンが利用できそうです。

aws_secret

シークレットマネージャー参照は aws_secret プラグインで行えます。 version 2.8 (2019-05-16) から追加されました。

Requirements 記載の通り、 botocore,boto3 が必要になります。インストールされていない状態だと下記エラーとなります。

FAILED! => {"msg": "The lookup aws_secret requires boto3 and botocore."}

近い内に修正されると思いますが、region指定部分で不具合があります。

FAILED! => {"msg": "An unhandled exception occurred while running the lookup plugin 'aws_secret'. Error was a <type 'exceptions.KeyError'>, original message: 'Requested entry (plugin_type: lookup plugin: aws_secret setting: region ) was not defined in configuration.'"}

PRされている修正を反映すると、取得できました。

  • ansible/plugins/lookup/aws_secret.py
@@ -14,6 +14,7 @@
   - botocore>=1.10.0
 extends_documentation_fragment:
   - aws_credentials
+  - aws_region
 short_description: Look up secrets stored in AWS Secrets Manager.
 description:
   - Look up secrets stored in AWS Secrets Manager provided the caller

GetSecretValue

+------------------+----------------------------------+
|    Name          |        SecretString              |
+------------------+----------------------------------+
|  dev/test_secret |  {"dev/test_secret":"testtest"}  |
+------------------+----------------------------------+

tasks例

存在しないシークレットの指定はエラーとなります。

FAILED! => {"msg": "An unhandled exception occurred while running the lookup plugin 'aws_secret'. Error was a <class 'ansible.errors.AnsibleError'>, original message: Failed to retrieve secret: ResourceNotFoundException(u'An error occurred (ResourceNotFoundException) when calling the GetSecretValue operation: Secrets Manager can\\u2019t find the specified secret.',)"}
  pre_tasks:
    - name: 'set secrets'
      set_fact:
        an1:
          secret1: "{{ lookup('aws_secret', 'dev/test_secret') }}"
  tasks:
    - name: 'output secrets'
      debug: var="{{ item }}"
      with_items:
        - "an1.secret1"
        - "an1.not_exist"

実行結果

TASK [set secrets] **********************************************************************
ok: [test-instance]

TASK [output secrets] *******************************************************************
ok: [test-instance] => (item=an1.secret1) => {
    "an1.secret1": {
        "dev/test_secret": "testtest"
    },
    "ansible_loop_var": "item",
    "item": "an1.secret1"
}

aws_ssm

制限事項がいくつかありますが、SSM 経由でシークレットマネージャの参照が可能ですので、同様に取得できます。

tasks例

予約パス /aws/reference/secretsmanager/ を含めて指定します。

  pre_tasks:
    - name: 'set secrets using ssm parameter store'
      set_fact:
        an1:
          secret: "{{ lookup('aws_ssm', '/aws/reference/secretsmanager/dev/test_secret') }}"
          not_exist: "{{ lookup('aws_ssm', '/aws/reference/secretsmanager/dummy') }}"
  tasks:
    - name: 'output secrets'
      debug: var="{{ item }}"
      with_items:
        - "an1.secret"
        - "an1.not_exist"

実行結果

TASK [set secrets using ssm parameter store] ********************************************
ok: [test-instance]

TASK [output secrets] *******************************************************************
ok: [test-instance] => (item=an1.secret) => {
    "an1.secret": {
        "dev/test_secret": "testtest"
    },
    "ansible_loop_var": "item",
    "item": "an1.secret"
}
ok: [test-instance] => (item=an1.not_exist) => {
    "an1.not_exist": "",
    "ansible_loop_var": "item",
    "item": "an1.not_exist"
}

__NSPlaceholderDate initialize エラー

Mac OS Mojave (10.14.x) で playbook を実行した際に以下のようなエラーが発生しました。

+[__NSPlaceholderDate initialize] may have been in progress in another thread when fork() was called.
+[__NSPlaceholderDate initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.

以下の環境変数を設定することで回避可能です。

export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES

High Sierra (10.13.x) からの仕様変更により発生するようです。

Redash REDASH_GOOGLE_APPS_DOMAIN はもう無い

(最新の)公式読みましょう。

To enable automatic user creation who belong to a specific domain name, you can add this domain (or more) in the setting page:

Redash では Google OAuth 認証が利用できますが、 特定のドメインのみ許可する設定は管理画面上で行います。

[Settings] -> [Settings] -> "Allowed Google Apps Domains" f:id:htnosm:20190502031819p:plain


導入に当たり、参考にした情報が古かったようで、 REDASH_GOOGLE_APPS_DOMAIN を使用(紹介)しているパターンが結構多かったです。 反映されないと小一時間悩みました。
既に廃止されています。

Windows版Squid導入あれやこれや

Windows Server 2016 へ Squid を導入します。 (※ プロキシ設定は触れません。)



Squid について

f:id:htnosm:20190119174746p:plain

コンパイルすることでSOCKSの対応もできそうな感じです。(未確認)

4.10 Does Squid support Socks?
We would like to use Squid, but we need it to use socks to connect to the world outside our firewall.

No changes are necessary to use Squid with socks5. Simply add the usual -Dbind=SOCKSbind etc., to the compile line and -lsocks to the link line.

インストールなど

インストール

ダウンロードした squid.msi でインストール。迷う所はありません。各種設定ファイルは C:\Squid\etc\squid\ に置かれます。

インストールが完了すると、デスクトップ上にアイコンが作成されます。

f:id:htnosm:20190119174847p:plain

  • Squid Server Tray
    • サービスの起動停止、設定ファイルへのリンクを選択できる簡易ツール

f:id:htnosm:20190119174908p:plain

サービスではなく、コマンドでの実行も可能です。

C:\Squid\bin>squid.exe -h
Usage: squid [-cdhvzCFNRVYX] [-n name] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]
       -a port   Specify HTTP port number (default: 3128).
       -d level  Write debugging to stderr also.
       -f file   Use given config-file instead of
                 /etc/squid/squid.conf
       -h        Print help message.
       -k reconfigure|rotate|shutdown|restart|interrupt|kill|debug|check|parse
                 Parse configuration file, then send signal to
                 running copy (except -k parse) and exit.
       -n name   Specify service name to use for service operations
                 default is: squid.
       -s | -l facility
                 Enable logging to syslog.
       -u port   Specify ICP port number (default: 3130), disable with 0.
       -v        Print version.
       -z        Create missing swap directories and then exit.
       -C        Do not catch fatal signals.
       -D        OBSOLETE. Scheduled for removal.
       -F        Don't serve any requests until store is rebuilt.
       -N        No daemon mode.
       -R        Do not set REUSEADDR on port.
       -S        Double-check swap during rebuild.
       -X        Force full debugging.
       -Y        Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.

サービスは Squid for Windows という名前で作成されます。自動起動も有効化された状態です。

f:id:htnosm:20190119173903p:plain

ファイアウォール設定

squid 自体での接続元制限設定が行なえますが、それとは別にファイアウォール設定の必要があります。 Squid Cache Server ルールが作成されているので、適宜設定します。

f:id:htnosm:20190119173859p:plain

ログローテーション

ログファイルが C:\Squid\var\log\squid に作成されます。 ログローテーションはコマンド実行で行います。

C:\squid\bin> squid -k rotate

デフォルト10世代(ファイル)です。保存数を変更したい場合は設定ファイルに追記します。

logfile_rotate 10

タスクスケジューラ

Squid 固有というわけではないですが、ログローテーションの定期実行のため、スケジュール実行設定を行います。

C:\>schtasks /create /tn logrotate_squid /tr "C:\Squid\bin\squid.exe -k rotate" /sc weekly /ST 00:00 /rl highest /F /NP
SUCCESS: The scheduled task "logrotate_squid" has successfully been created.

f:id:htnosm:20190119174115p:plain

タスクスケジューラの履歴(ログ)

最近のWindowsはタスクスケジューラの履歴取得がデフォルトで無効のようでした。必要に応じて有効化します。

C:\>wevtutil set-log Microsoft-Windows-TaskScheduler/Operational /enabled:true

履歴の実体はイベントビューアーなので、詳細設定(ログ保持量等)はそちらで行います。

  • [Applications and Services Logs] -> [Microsoft] -> [Windows] -> [TaskScheduler] -> [Operational]

f:id:htnosm:20190119175251p:plain