PowerShellコラム:OS標準機能で位置情報を取得してみよう

Microsoft

2022.01.31

始めに

Windowsに標準で組み込まれているPowerShellについて、特にテーマを限定せずいろいろと紹介していきます。
PowerShellを使い始めるきっかけになっていただければ幸いです。

今回は、PowerShellで位置情報を取ってみるサンプルのご紹介。Windows10であれば、OS標準機能でできます。

サンプルを実行する前の準備

位置情報はなかなかセンシティブな情報です。そのため明示的に取得を許可しておく必要があります。まずはこれらを確認、設定していきます。
GUIで行う方法とPowerShellを使用した方法も併記します。

PowerShellを開く

Windowsの検索で PowerShell と入れてEnter。最近のWindows10が入っているなら Win+X を押すとcmdではなくWindows PowerShell がメニューにあります。
そこで I キーで通常の、Aキーで管理者権限のPowerShellコンソールが開きます。

「アプリが位置情報にアクセスできるようにする」を有効にする

「設定」アプリから「位置情報のプライバシー設定」を確認します。「このデバイスの位置情報はオフになっています」となっていたら、変更をクリックしてオンにします。
その後、「アプリが位置情報にアクセスできるようにする」も、オンにしましょう。

この設定はレジストリでも行われており、以下のようになっています。

キー 名前 種類 データ
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\AppPrivacy LetAppsAccessLocation REG_DWORD 0
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\location Value REG_SZ Allow
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Sensor\Overrides\{BFA794E4-F964-4FDB-90F6-51056BFE4B44} SensorPermissionState REG_DWORD 1
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\lfsvc\Service\Configuration Status REG_DWORD 1

これをスクリプトで設定する場合はこちら。Typeの表記がレジストリエディタと違うので要注意です。

# CSVの文字列をオブジェクトに変換する。
# 列名は Set-ItemProperty のパラメータ名とする。
$SettingCSV = @"
Path,Name,Type,Value Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\AppPrivacy,LetAppsAccessLocation,DWord,0
Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\location,Value,String,Allow
Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Sensor\Overrides\{BFA794E4-F964-4FDB-90F6-51056BFE4B44},SensorPermissionState,DWord,1
Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\lfsvc\Service\Configuration,Status,DWord,1
"@ | ConvertFrom-CSV

Foreach ($c in $SettingCSV) {
    # $c には1行分の情報が入る。
    # キーがあればSet、なければNewで新規作成する。
    if ($False -eq (Test-Path -LiteralPath $c.Path)) {
        $null = New-Item -Path $c.Path
    }
    
    # 値を設定する
    Set-ItemProperty `
        -Path $c.Path `
        -Name $c.Name `
        -Type $c.Type `
        -Value $c.Value
}

Geolocation Serviceの起動

「Serviecs.msc」を実行して、「Geolocation Service」のプロパティを確認します。こちらが停止中になっていた場合は起動してください。

その際「指定したファイルが見つかりません」というエラーが出ることがあるので、その場合はレジストリエディタで以下のキーを削除します。

キー
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lfsvc\TriggerInfo\3

スクリプトで実行する場合はこうなります。

# サービス有効化時の「指定したファイルが見つかりません」というエラー対策
Remove-Item -LiteralPath "Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lfsvc\TriggerInfo\3" -EA Silent

# スタートアップタイプを「手動」に変更して結果確認
Set-Service -Name lfsvc -StartupType Manual
Get-Service -Name lfsvc | Select-Object Status,Name,DisplayName,StartType

GPSが搭載されているか確認する

お使いの端末にGPSが搭載されているか、メーカーサイトなどで確認します。
端末のモデル名などは、以下のコマンドで確認出来ます。

# モデル名の確認
Get-CimInstance Win32_ComputerSystem

ちなみに。GPSが搭載されていなくてもWi-Fiが有効になっている場合はある程度の位置を推測することができることがあります。これは各社が携帯電話基地やWi-Fiアクセスポイントの位置を記録したデータベースを構築しているためです。
しかし時にモバイルルーターなどの位置もとってきてしまうようで、全く関係ない場所を示すこともあります。各社でこの位置情報サービスからの除外をする方法が提供されていますが、自分のモバイルルーターが怪しいと感じた場合はSSIDを変えてみると改善するかもしれません。

サンプルコードを直接実行する

サンプルコードを直接実行する場合は、これで準備は完了です。
コードをボードにコピーして、Ctrl+Vで張り付けます。右クリックでも貼り付けできますが、コードの構成によってはおかしな挙動をすることがあるので非推奨です。
また、貼り付ける際はPowerShellのウィンドウの中をクリックしないようにします。

クリックすると以下のように選択状態になってしまいます。この状態で右クリックするとその内容がクリップボードにコピーされてしまうので、その場合はEscキーを押して解除します。

貼り付けるコード:

# 位置情報取得するための準備
Add-Type -AssemblyName System.Device
$GeoWatcher = New-Object System.Device.Location.GeoCoordinateWatcher

# 計測開始
$GeoWatcher.Start()

# 計測待ち。問題なく計測完了なら Ready になる。Denied だったら事前設定不足。
while("Ready" -ne $GeoWatcher.Status) {
    Start-Sleep 1
    Write-Host "計測中… $($GeoWatcher.Status)"
}

# 結果確認
$Location = $GeoWatcher.Position.Location | Select-Object Latitude,Longitude
Write-Host $Location

# 位置が判ったらEdgeでGoogleMapのアドレスを表示
$URL = "https://www.google.co.jp/maps/place/$($Location.Latitude),$($Location.Longitude)"
Write-Host $URL
start Microsoft-Edge:$URL

# 満足したら終了
$GeoWatcher.Dispose()

Edgeが起動して、周辺の地図が出たでしょうか?うまくいけばコンソールにはこんな結果が返ってくると思います。

サンプルファイルをダウンロードして実行する

スクリプトファイルを実行する場合は、もう少し準備が必要です。まずはサンプルを適当な場所にダウンロードします。

サンプルデータ

PowerShellでダウンロードもやりたい方はこちら。Downloads フォルダにダウンロードするサンプルです。

# サンプルスクリプトのダウンロード法
$url = "https://www.intellilink.co.jp/-/media/ndil/ndil-jp/column/ms/2022/013100/gpsfunctions.zip"
$DestFolder = "$Home\Downloads"
$OutFile = "$DestFolder\$(split-path $url -leaf)"

# ダウンロード
Invoke-WebRequest $URL -OutFile $OutFile

Zipファイルを展開する

ダウンロードしたファイル(GpsFunctions.zip)から、GpsFunctions.ps1 を展開します。

# 展開
$DestFolder = "$Home\Downloads\"
$ZipPath = "$Home\Downloads\GpsFunctions.zip"

Expand-Archive -LiteralPath $ZipPath -DestinationPath $DestFolder

ファイルのブロックを解除する

スクリプトファイルをダウンロードした場合、スクリプトがブロックされていないことを確認します。
ファイルのプロパティの全般タブを確認します。ブロックされていたら「許可する」にチェックを入れて適用してください。

これもスクリプトにするなら、こちら。Downloadsフォルダに置いてある場合のサンプルです。

# スクリプトのブロック解除
Get-Item "$home\Downloads\GpsFunctions.ps1" | Unblock-File

実行ポリシーの設定

PowerShellはとってもPowerfull なので、セキュリティが厳しくなっています。このコマンドを実行すると「今開いているPowerShellコンソールから、ローカルにあるスクリプトファイルは実行してもいいよ」という設定をします。

# 実行ポリシーの設定(このセッションのみ)
Set-ExecutionPolicy RemoteSigned -Scope Process -force

なお何度も聞いてほしくないという人は

# 実行ポリシーの設定(永続)
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -force

とすれば設定は永続化します。

スクリプトファイルを実行する

ダウンロードしたGpsFunctions.ps1を実行します。パスにスペースが入っている場合は、クオートやダブルクオートでくくって、先頭に「&」を付けます。
例えば、ダウンロードフォルダに置いているならこうなります。$homeには自動的にユーザのホームディレクトリが入ります。

# サンプルの実行
& "$home\Downloads\GpsFunctions.ps1"

終わりに

PowerShellを用いて位置情報を取得する方法を紹介しました。またその前準備もすべてコンソールから実行できることもお判りいただけたと思います。
位置情報取得に限らず、くの操作をコマンドで実行できるので、いろいろと応用が利きます。

定期的なタスク以外にも、構築手順書や試験手順書の一部をスクリプトファイル化、あるいは手順書からコピー&ペースト手順にしたらどうでしょうか。
作業者は、作業ミスを防ぐことができるかもしれません。作成者は、WordやExcelと格闘しながらキャプチャの貼り付けとマーク付け、位置調整、などなどの手間を省くこともできます。一言「PowerShellウィンドウに以下を張り付けて実行する」と書くだけです。

一方で、前準備が面倒と感じる方がいるかもしれません。
あるいは、「バッチやVBSならダブルクリックで済むのに、わざわざPowerShellのコンソールを開いて実行するなんて面倒!」という人もいると思います。
今後はこういった導入の際に躓くポイントや、これらを回避するテクニックも紹介していけたらと思います。

※文中の商品名、会社名、団体名は、一般に各社の商標または登録商標です。

PowerShellコラム:OS標準機能で位置情報を取得してみよう