tag:crieit.net,2005:https://crieit.net/tags/PSCustomObject/feed 「PSCustomObject」の記事 - Crieit Crieitでタグ「PSCustomObject」に投稿された最近の記事 2021-01-12T23:48:54+09:00 https://crieit.net/tags/PSCustomObject/feed tag:crieit.net,2005:PublicArticle/16582 2021-01-12T23:48:54+09:00 2021-01-12T23:48:54+09:00 https://crieit.net/posts/powershell-access-key-and-value-in-psobject-20210112 (PowerShell) PSCustomObject をループさせつつキーと値の両方にアクセスする <p>引き続き PowerShell のお話。今度は PSCustomObject をループさせつつキーと値の両方にアクセスする方法が分からず躓きました。</p> <h2 id="現象"><a href="#%E7%8F%BE%E8%B1%A1">現象</a></h2> <pre><code class="json">{ "common": { "config": { "user.name": "testuser", "user.id": 12345, "user.email": "[email protected]" } } } </code></pre> <p>例えばこんな <code>config.json</code> があるとします。</p> <p>この JSONファイル を読み込んでループさせつつ、キーと値の双方にアクセスしたい。</p> <p>そこで <code>foreach($confgi in $configData.GetEnumerator()){}</code> としたり、 <code>foreach($confgi in $configData.Keys){}</code> としたりしましたが一向に中身が取得できず四苦八苦。</p> <h2 id="対処"><a href="#%E5%AF%BE%E5%87%A6">対処</a></h2> <pre><code class="powershell"># JSONファイル 読み込み [String]$configPath = Join-Path ( Convert-Path . ) 'config.json' $configData = Get-Content -Path $configPath -Raw -Encoding UTF8 | ConvertFrom-JSON # ループ foreach( $key in $configData.common.config.psobject.properties.name ) { Write-Host $key ' = ' $configData.common.config.$key } </code></pre> <p>最終的に、 <code>$Object.psobject.properties.name</code> という全然異なるアクセス方法だったことが分かりました。今回の場合はキーが階層で入り組んでいるのでさらに <code>.</code> (ピリオド(ドット)) の個数が増えています。</p> <pre><code class="bash">> PowerShell -ExecutionPolicy RemoteSigned .\test.ps1 user.name = testuser user.id = 12345 user.email = [email protected] </code></pre> <p>やっとキーと値の両方が取得できました……。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://docs.microsoft.com/ja-jp/powershell/scripting/learn/deep-dives/everything-about-pscustomobject?view=powershell-7.1">PSCustomObject について知りたかったことのすべて - PowerShell | Microsoft Docs</a></li> </ul> arm-band tag:crieit.net,2005:PublicArticle/16579 2021-01-11T22:59:05+09:00 2021-01-11T22:59:05+09:00 https://crieit.net/posts/powershell-access-key-with-piriod-in-psobject-20210111 (PowerShell) PSCustomObject のピリオド(ドット)入りのキー名にアクセスする <p>Powershell で JSON から読み込んだオブジェクトにピリオド(ドット)入りのキー名があり、これにどうやってアクセスしようか悩みました。</p> <h2 id="現象"><a href="#%E7%8F%BE%E8%B1%A1">現象</a></h2> <pre><code class="json">{ "user": { "user.name": "testuser", "user.email": "[email protected]" } } </code></pre> <p>例えばこんな <code>config.json</code> があるとします。</p> <p>この JSONファイル を読み込み、ユーザの入力を受け付けて設定を上書きするスクリプトを書きました。</p> <pre><code class="powershell"># JSONファイル 読み込み [String]$configPath = Join-Path ( Convert-Path . ) 'config.json' $configData = Get-Content -Path $configPath -Raw -Encoding UTF8 | ConvertFrom-JSON # 一度出力 Write-Host $configData.user['user.name'] # 入力受付 [String]$username = Read-Host 'ユーザー名 を入力してください (半角英数字と一部記号 (-, _) )。' if (-not ($username -match "^[a-zA-z0-9\-_]+$") ) { Write-Host 'ERROR: ユーザ名 に使用できない文字が含まれています。' -BackgroundColor DarkRed Write-Host `r`n exit } $configData.user['user.name'] = $username # 再度出力 Write-Host $configData.user['user.name'] </code></pre> <p>ここで問題となったのが <code>user.name</code> という <code>.</code> (ピリオド(ドット))入りのキー名。オブジェクトで <code>.</code> でキー名を連結できるのが JavaScript に似ていたので、つい JavaScript のように <code>$configData.user['user.name']</code> と書いてしましました。</p> <p>すると</p> <pre><code class="bash">> PowerShell -ExecutionPolicy RemoteSigned .\test.ps1 ユーザー名 を入力してください (半角英数字と一部記号 (-, _) )。: aaa 型 System.Management.Automation.PSObject のオブジェクトにインデックスを付けることはできません。 発生場所 PATH\TO\PROJECT\test.ps1:16 文字:1 + $configData.user['user.name'] = $username + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) []、RuntimeException + FullyQualifiedErrorId : CannotIndex </code></pre> <p>怒られました。しかも、初出の位置ではなく変数で上書きする部分で。初出の <code>Write-Host</code> による標準出力はブランクを出力してスルーされたようです。</p> <p>以上より、</p> <ul> <li>変数の値を読み込む場合(出力など): 存在しないキーとしてブランク出力してそのままスルー</li> <li>変数の値を書き込む場合: エラー</li> </ul> <p>となるようです。困った。</p> <h2 id="対処"><a href="#%E5%AF%BE%E5%87%A6">対処</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://docs.microsoft.com/ja-jp/powershell/scripting/learn/deep-dives/everything-about-pscustomobject?view=powershell-7.1">PSCustomObject について知りたかったことのすべて - PowerShell | Microsoft Docs</a></li> </ul> <blockquote> <p>プロパティ名に文字列を使用しても、やはり機能します。</p> <p><code>$myObject.'Name'</code></p> </blockquote> <p>なん……だと……。</p> <p>ということで上記スクリプトを書き換えます。</p> <pre><code class="powershell"># JSONファイル 読み込み [String]$configPath = Join-Path ( Convert-Path . ) 'config.json' $configData = Get-Content -Path $configPath -Raw -Encoding UTF8 | ConvertFrom-JSON # 一度出力 Write-Host $configData.user.'user.name' # 入力受付 [String]$username = Read-Host 'ユーザー名 を入力してください (半角英数字と一部記号 (-, _) )。' if (-not ($username -match "^[a-zA-z0-9\-_]+$") ) { Write-Host 'ERROR: ユーザ名 に使用できない文字が含まれています。' -BackgroundColor DarkRed Write-Host `r`n exit } $configData.user.'user.name' = $username # 再度出力 Write-Host $configData.user.'user.name' </code></pre> <p>肝は <code>$configData.user.'user.name'</code> 。 <code>$configData.user['user.name']</code> の角括弧 (<code>[]</code>)を外してキー名の文字列をそのまま <code>.</code> (ピリオド(ドット)) で繋げました。</p> <pre><code class="bash">> PowerShell -ExecutionPolicy RemoteSigned .\test.ps1 testuser ユーザー名 を入力してください (半角英数字と一部記号 (-, _) )。: abc abc </code></pre> <p>上手く行きました。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://docs.microsoft.com/ja-jp/powershell/scripting/learn/deep-dives/everything-about-pscustomobject?view=powershell-7.1">PSCustomObject について知りたかったことのすべて - PowerShell | Microsoft Docs</a></li> </ul> arm-band