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