はじめに

こんにちは!そしてこんばんは!
クラウドインテグレーション事業部の大嵩です。

みなさんは、Windows Serverでエクスプローラーではなく、CLI上でディスク使用率を表示する方法はご存知ですか?
今回は、業務の中で実装が必要となった、SSM Run CommandからWindowsの全てのディスク使用率を表示する方法を紹介します!

検証したこと

今回は下記を検証してみました!
実装が必要なものとして、まっさらな別のインスタンスからディスク使用率を確認する必要があるため、2パターン検証してみます!

  • インスタンス自体のディスク使用率を確認
  • 別のインスタンスからAWS CLIを使ってディスク使用率を確認

下準備

まずは準備をしていきます。
合計でインスタンスは2台必要です!
片方はわかりやすくルートボリュームとは別に、2つEBSをアタッチします。
今回追加分のドライブは10GBで作成します。
EBS作成部分は割愛します。

Windows内の手順

最初にパーティションテーブルの選択を求められます。
今回は10GBですので、MBRを選択します!

「New Simple Volume(新しいシンプルボリューム)」を選択します

すると、ボリュームサイズを聞かれるので、シンプルにMAXの値を入れます!

次にドライブレターを選択し、ドライブ名をつけてFinishを押したら完了です!


これを、追加するディスク分繰り返します!

準備完了!

画像の通り、インスタンスAでは、DドライブとGドライブの準備ができました!
インスタンスBは、まっさらな状態なので、割愛します。

まずは、ドライブを増やしたインスタンスでの表示確認

では、ドライブの準備も整ったところで、実際にコマンドを実行して全てのディスク使用率を出してみましょう。
PowerShellを使って表示します!

PS C:\Users\Administrator> Get-Volume |
>>   Select-Object DriveLetter,
>>     FileSystem,
>>     @{Name="Size(GB)";Expression={[math]::Round($_.Size / 1GB, 2)}},
>>     @{Name="FreeSpace(GB)";Expression={[math]::Round($_.SizeRemaining / 1GB, 2)}},
>>     @{Name="FreeSpace(%)";Expression={[math]::Round(($_.SizeRemaining / $_.Size) * 100, 2)}} |
>>   Format-Table -AutoSize

DriveLetter FileSystem Size(GB) FreeSpace(GB) FreeSpace(%)
----------- ---------- -------- ------------- ------------
          C NTFS             30         10.78        35.94
          G NTFS             10          9.96        99.66
          D NTFS             10          9.96        99.66

意外とすんなりきれいにテーブルの状態で表示することができました!
このコマンドは、コンピュータに接続されているすべてのボリュームの情報を取得し、見やすく整形して表示するものです!

具体的には、以下の処理をパイプライン(|)でつなげて順番に実行しています。

1. Get-Volume

まず、Get-Volume コマンドレットが実行されます。
これは、システム上のすべてのボリューム(ハードディスク、SSD、USBドライブなど)とその情報を取得するものです。

2. Select-Object

次に、Get-Volume から渡された情報を Select-Object で加工します。
表示したい項目を選択し、一部のデータは計算して新しい項目を作成しています。

  • DriveLetter: ドライブ文字(例: C, D)を表示します。
  • FileSystem: ファイルシステム(例: NTFS, ReFS)を表示します。
  • @{Name="Size(GB)";Expression={[math]::Round($_.Size / 1GB, 2)}}:
    • @{...}: 計算プロパティと呼ばれ、新しいプロパティ(列)を作成します。
    • Name="Size(GB)": 新しい列の名前を「Size(GB)」に設定します。
    • Expression={...}: 表示する内容を計算します。ここでは、各ボリュームの合計サイズ ($_.Size) を1GBで割り、小数点以下2桁に丸めてギガバイト単位で表示します。
  • @{Name="FreeSpace(GB)";Expression={[math]::Round($_.SizeRemaining / 1GB, 2)}}:
    • ボリュームの空き容量 ($_.SizeRemaining) をギガバイト単位で計算し、「FreeSpace(GB)」という名前の列に表示します。
  • @{Name="FreeSpace(%)";Expression={[math]::Round(($_.SizeRemaining / $_.Size) * 100, 2)}}:
    • 空き容量の割合を (空き容量 ÷ 合計サイズ) * 100 で計算し、「FreeSpace(%)」という名前の列に表示します。

3. Format-Table -AutoSize

最後に、Select-Object で整形されたデータを受け取り、Format-Table でテーブル形式に変換して表示します。

  • -AutoSize: 各列の幅を、その列に含まれるデータの中で最も長いものに合わせて自動で調整し、表示が崩れないようにします。

他のインスタンスから表示してみる

ディスクを増やしたインスタンス本体ではすんなり表示できましたね!
では、他のインスタンスから表示する方法を試してみます。
RDP接続してそのインスタンスに入るのが簡単ですが、今回はRDPが使用できない場合を想定して、AWS CLIからの確認を試みてみます。
SSMドキュメントはAWS-RunPowerShellScript を使用し、SSM Run Commandから実行してみます。

マネジメントコンソールから試してみる

まずはコマンドがRun Commandでも動くのか、マネジメントコンソールから試してみます!

AWS-RunPowerShellScriptを選択して、コマンドのパラメータにコマンドを入力します

Get-Volume |
   Select-Object DriveLetter,
     FileSystem,
     @{Name="Size(GB)";Expression={[math]::Round($_.Size / 1GB, 2)}},
     @{Name="FreeSpace(GB)";Expression={[math]::Round($_.SizeRemaining / 1GB, 2)}},
     @{Name="FreeSpace(%)";Expression={[math]::Round(($_.SizeRemaining / $_.Size) * 100, 2)}} |
   Format-Table -AutoSize


次に、実行するインスタンスを選択して、今回は出力先をCloudWatch Logsにします。

実行すると。。。?

実行したら、まずは実行完了を示す画面が出てきます!
ここでは、出力を確認できません。

次に、指定したCloudWatch Logsを見てみると。。。

しっかり出力されていました!
これで、SSM経由でも実行できることが確認できました!!
それでは、肝心のAWS CLIから試してみましょう

AWS CLIから試してみる

それでは、インスタンスBから、本題のAWS CLIで実行してみましょう。
構築後はすぐに使えなかったため、下記のページからインストールしましょう!

インストールしたら、動くか確認してみます!

C:\Users\Administrator>aws --version
aws-cli/2.27.25 Python/3.13.3 Windows/2022Server exec-env/EC2 exe/AMD64

C:\Users\Administrator>

無事に行けましたね!
ですが、なんとコマンドプロンプトでしか使えないようです。。
PowerShellでは不明なコマンドとしてエラーが出てしまいます。
下記のようなコマンドで実行可能になるようですが、今回はPowerShellのカスタムを想定しないため実施しません。

Install-Module -Name AWSPowerShell

Windows AWS Tools for PowerShell での のインストール - AWS Tools for PowerShell
Windows ベースのコンピュータは、次のいずれかの AWS Tools for PowerShell パッケージオプションを実行できます。

それでは、コマンドを書いていきます。
例として、AWS CLIでは下記のような形で実行する感じになります。
今回でいうと、--instance-ids にはインスタンスAのIDを指定します。

aws ssm send-command \
    --document-name "AWS-RunPowerShellScript" \
    --instance-ids "i-xxxxxxxxxxxxxxxxx" \
    --parameters '{"commands":["echo hello world"]}' \
    --comment "実行テスト" \
    --region ap-northeast-1

では、これを置き換えてみましょう!

aws ssm send-command \
    --document-name "AWS-RunPowerShellScript" \
    --targets "Key=instanceids,Values=i-xxxxxxxxxxxxxxxxx" \
    --parameters '{"commands":["Get-Volume | Select-Object DriveLetter, FileSystem, @{Name=\\\"Size(GB)\\\";Expression={[math]::Round($_.Size / 1GB, 2)}}, @{Name=\\\"FreeSpace(GB)\\\";Expression={[math]::Round($_.SizeRemaining / 1GB, 2)}}, @{Name=\\\"FreeSpace(%)\\\";Expression={[math]::Round(($_.SizeRemaining / $_.Size) * 100, 2)}} | Format-Table -AutoSize"]}' \
    --comment "Get Volume Information" \
    --region ap-northeast-1 # リージョンは適宜変更してください

こうなるはずですね!
では、そのまま実行してみます!

エラーが。。

予想はつきますが、commandsの指定部分でエラーが出ます。
原因としては、配列内にコマンドを記載している点で、途中のダブルクオーテーションのエスケープ部分が問題のようです。。。

単純なコマンドで試してみる

次は、echoコマンドだけのもので試してみますが、それでもダメです。
やはり、--parameters 部分でエラーが出てしまいます。。

C:\Users\Administrator>aws ssm send-command --document-name "AWS-RunPowerShellScript" --instance-ids "i-0472903427489b845" --parameters '{"commands":["echo hello world"]}' --comment "実行テスト" --region ap-northeast-1

Error parsing parameter '--parameters': Expected: '=', received: ''' for input:
 '{commands:[echo hello world]}'
^

指定方法を変えてみる

それでは、コマンドは変わりますが指定方法を変えてみます。
下記のように、JSON形式での指定にこだわっていましたが、commands= の形にして実行してみます。

なんと、CommandId が発行され、無事に実行できました!!
このCommandIdをメモしておきます。

C:\Users\Administrator>aws ssm send-command --document-name "AWS-RunPowerShellScript" --instance-ids "i-0472903427489b845" --parameters "commands=['hostname']"
{
    "Command": {
        "CommandId": "72f7671b-754a-4cce-b62d-09942e4eae03",
        "DocumentName": "AWS-RunPowerShellScript",
        "DocumentVersion": "$DEFAULT",
        "Comment": "",
        "ExpiresAfter": "2025-05-30T09:40:58.934000+00:00",
        "Parameters": {
            "commands": [
                "hostname"
            ]
        },
        "InstanceIds": [
            "i-0472903427489b845"
        ],
        "Targets": [],
        "RequestedDateTime": "2025-05-30T07:40:58.934000+00:00",
        "Status": "Pending",
        "StatusDetails": "Pending",
        "OutputS3Region": "ap-northeast-1",
        "OutputS3BucketName": "",
        "OutputS3KeyPrefix": "",
        "MaxConcurrency": "50",
        "MaxErrors": "0",
        "TargetCount": 1,
        "CompletedCount": 0,
        "ErrorCount": 0,
        "DeliveryTimedOutCount": 0,
        "ServiceRole": "",
        "NotificationConfig": {
            "NotificationArn": "",
            "NotificationEvents": [],
            "NotificationType": ""
        },
        "CloudWatchOutputConfig": {
            "CloudWatchLogGroupName": "",
            "CloudWatchOutputEnabled": false
        },
        "TimeoutSeconds": 3600,
        "AlarmConfiguration": {
            "IgnorePollAlarmFailure": false,
            "Alarms": []
        },
        "TriggeredAlarms": []
    }
}

実行確認

それでは、気になる実行結果を確認してみましょう!
情報量が多いですが、「StandardOutputContent」が実行結果になります。

C:\Users\Administrator>aws ssm get-command-invocation --instance-id "i-0472903427489b845" --command-id "72f7671b-754a-4cce-b62d-09942e4eae03"
{
    "CommandId": "72f7671b-754a-4cce-b62d-09942e4eae03",
    "InstanceId": "i-0472903427489b845",
    "Comment": "",
    "DocumentName": "AWS-RunPowerShellScript",
    "DocumentVersion": "$DEFAULT",
    "PluginName": "aws:runPowerShellScript",
    "ResponseCode": 0,
    "ExecutionStartDateTime": "2025-05-30T07:40:59.858Z",
    "ExecutionElapsedTime": "PT0.496S",
    "ExecutionEndDateTime": "2025-05-30T07:40:59.858Z",
    "Status": "Success",
    "StatusDetails": "Success",
    "StandardOutputContent": "EC2AMAZ-0OEUQ6A\r\n",
    "StandardOutputUrl": "",
    "StandardErrorContent": "",
    "StandardErrorUrl": "",
    "CloudWatchOutputConfig": {
        "CloudWatchLogGroupName": "",
        "CloudWatchOutputEnabled": false
    }
}

しっかりコマンド通りにホスト名が出力されています!

"StandardOutputContent": "EC2AMAZ-0OEUQ6A\r\n",

いざ実行してみる

では、同じ指定方法で、かつエスケープに気をつけて実行してみましょう!

C:\Users\Administrator>aws ssm send-command --document-name "AWS-RunPowerShellScript" --instance-ids "i-0472903427489b845" --parameters "commands=['Get-Volume | Select-Object DriveLetter, FileSystem, @{Name=\"Size(GB)\";Expression={[math]::Round($_.Size / 1GB, 2)}}, @{Name=\"FreeSpace(GB)\";Expression={[math]::Round($_.SizeRemaining / 1GB, 2)}}, @{Name=\"FreeSpace(%)\";Expression={[math]::Round(($_.SizeRemaining / $_.Size) * 100, 2)}} | Format-Table -AutoSize']" --comment "Get Volume Information" --region ap-northeast-1
{
    "Command": {
        "CommandId": "e6e37ca5-9ba8-4f3c-8bd0-5534d0911d3b",
        "DocumentName": "AWS-RunPowerShellScript",
        "DocumentVersion": "$DEFAULT",
        "Comment": "Get Volume Information",
        "ExpiresAfter": "2025-05-30T09:49:36.419000+00:00",
        "Parameters": {
            "commands": [
                "Get-Volume | Select-Object DriveLetter, FileSystem, @{Name=\"Size(GB)\";Expression={[math]::Round($_.Size / 1GB, 2)}}, @{Name=\"FreeSpace(GB)\";Expression={[math]::Round($_.SizeRemaining / 1GB, 2)}}, @{Name=\"FreeSpace(%)\";Expression={[math]::Round(($_.SizeRemaining / $_.Size) * 100, 2)}} | Format-Table -AutoSize"
            ]
        },
        "InstanceIds": [
            "i-0472903427489b845"
        ],
        "Targets": [],
        "RequestedDateTime": "2025-05-30T07:49:36.419000+00:00",
        "Status": "Pending",
        "StatusDetails": "Pending",
        "OutputS3Region": "ap-northeast-1",
        "OutputS3BucketName": "",
        "OutputS3KeyPrefix": "",
        "MaxConcurrency": "50",
        "MaxErrors": "0",
        "TargetCount": 1,
        "CompletedCount": 0,
        "ErrorCount": 0,
        "DeliveryTimedOutCount": 0,
        "ServiceRole": "",
        "NotificationConfig": {
            "NotificationArn": "",
            "NotificationEvents": [],
            "NotificationType": ""
        },
        "CloudWatchOutputConfig": {
            "CloudWatchLogGroupName": "",
            "CloudWatchOutputEnabled": false
        },
        "TimeoutSeconds": 3600,
        "AlarmConfiguration": {
            "IgnorePollAlarmFailure": false,
            "Alarms": []
        },
        "TriggeredAlarms": []
    }
}

なんと、実行できましたね!!!
前の方法では、エスケープが多かったのも原因の一つかもしれません。。
それでは、実行結果を確認してみます。
今回はクエリを追加して、「StandardOutputContent」部分だけ出力します。

C:\Users\Administrator>aws ssm get-command-invocation --command-id "e6e37ca5-9ba8-4f3c-8bd0-5534d0911d3b" --instance-id "i-0472903427489b845" --query "StandardOutputContent" --output text

DriveLetter FileSystem Size(GB) FreeSpace(GB) FreeSpace(%)
----------- ---------- -------- ------------- ------------
          C NTFS             30          9.86        32.86
          E NTFS             10          9.96        99.66
          D NTFS             10          9.96        99.66

ちゃんと出てます!!
インスタンスAとマネジメントコンソールでの実行結果と同じで、きれいなテーブル形式で出力できていますね!
大成功です!

まとめ

今回の検証から、下記がわかりました!
AWS CLIからRun Commandを使用することで、CLI上でディスク使用率の確認を行うことができますね!

  • Windows Serverのディスク使用率をコマンドラインで確認するには、PowerShellの Get-Volume コマンドレットが便利です。Select-Object で表示項目を整形し、Format-Table を使うことで、各ドライブのサイズ、空き容量、使用率をわかりやすいテーブル形式で出力できます。
  • このPowerShellコマンドは、AWS Systems Manager (SSM) のRun Command機能(AWS-RunPowerShellScriptドキュメント)を利用して、リモートのWindowsインスタンスに対しても実行可能です。これにより、RDP接続せずに別のインスタンスからディスク情報を取得できます。
  • AWS CLIを用いてSSM Run Commandを実行する際、コマンドを渡す --parameters の指定方法で注意が必要です。記事では、JSON形式での指定でエラーが発生したものの、--parameters "commands=['...']" という形式に変更し、コマンド内のダブルクォーテーションを \" のようにエスケープすることで成功しました。
  • aws ssm send-command でコマンドを送信後、発行されたCommandIdを使って aws ssm get-command-invocation を実行することで、コマンドの実行結果を確認できます。

この記事がどなたかの参考になりますと幸いです!
みなさんも良いSSMライフを!