トップ回答者
PowerShellを用いたプリンタセキュリティへのアクセス権追加について

質問
-
PowerShellでプリンタのセキュリティ設定を変更したいのですが、
「Add-AccessControlEntry」が動作しません。
どのように記述すれば動作するのかご教示ください。
<やりたい事詳細>
プリンタプロパティの「セキュリティ」タブで「Everyone」が「印刷:許可」のみ設定
された状態になっています。
この状態から、「このプリンターの管理」と「ドキュメントの管理」の権限を追加したいのです。
※他のアクセス権はそのまま残したい。
<記述内容>
#対象プリンタの指定
$S = "RICOH RPCS Basic Color"
$SFilter = "name='" + $S + "'"
$SPrinter = gwmi win32_printer -filter $SFilter#セキュリティ情報を取得
$ace = $SPrinter.GetSecurityDescriptor#'Everyone'のセキュリティ設定を追加
$ace | Add-AccessControlEntry -Principal Everyone -PrinterRights ManagePrinters # 983052
$ace | Add-AccessControlEntry -Principal Everyone -PrinterRights ManageDocuments # 983088
$ace | Set-SecurityDescriptor<実行結果>
Add-AccessControlEntry : 用語 'Add-AccessControlEntry' は、コマンドレット、関数、スクリプト ファイル、または操作可能な
プログラムの名前として認識されません。名前が正しく記述されていることを確認し、パスが含まれている場合はそのパスが正しい
ことを確認してから、再試行してください。
発生場所 C:\Users\******\Desktop\printer_ace_add.ps1:10 文字:8
+ $ace | Add-AccessControlEntry -Principal Everyone -PrinterRights Mana ...
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Add-AccessControlEntry:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundExceptionAdd-AccessControlEntry : 用語 'Add-AccessControlEntry' は、コマンドレット、関数、スクリプト ファイル、または操作可能な
プログラムの名前として認識されません。名前が正しく記述されていることを確認し、パスが含まれている場合はそのパスが正しい
ことを確認してから、再試行してください。
発生場所 C:\Users\******\Desktop\printer_ace_add.ps1:11 文字:8
+ $ace | Add-AccessControlEntry -Principal Everyone -PrinterRights Mana ...
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Add-AccessControlEntry:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundExceptionSet-SecurityDescriptor : 用語 'Set-SecurityDescriptor' は、コマンドレット、関数、スクリプト ファイル、または操作可能な
プログラムの名前として認識されません。名前が正しく記述されていることを確認し、パスが含まれている場合はそのパスが正しい
ことを確認してから、再試行してください。
発生場所 C:\Users\******\Desktop\printer_ace_add.ps1:12 文字:8
+ $ace | Set-SecurityDescriptor
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Set-SecurityDescriptor:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException<実行環境のバージョン>
Windows7
PowerShell2.0
<参考にしたサイト>
https://gallery.technet.microsoft.com/scriptcenter/PowerShellAccessControl-d3be7b83#content
https://docs.microsoft.com/ja-jp/windows/desktop/CIMWin32Prov/setsecuritydescriptor-method-in-class-win32-printer
回答
-
Examplesのコードだと既存のDACLを完全に上書きしてしまうので、そのような結果になります。
Everyoneのアクセス権だけを変更するには、DACLに含まれるEveryone以外のACEを保持しておき、新たに生成したEveryoneのACEと結合させてDACLに反映させる必要がありそうです。
そのようなスクリプトを標準コマンドレットのみで作ってみました。
$user = "everyone" # 対象ユーザー名 $printerName = "RICOH RPCS Basic Color" # 対象プリンタ名 $printer = Get-WmiObject -Class win32_printer | Where-Object {$_.Name -eq $printerName} # プリンタのSecurity Descriptorを取得する $sd = $printer.GetSecurityDescriptor().Descriptor # DACLから$user以外のACEを取得する $aces = @($sd.DACL | Where-Object {$_.Trustee.Name -ne $user}) # ACEオブジェクトを生成する関数 # see: https://docs.microsoft.com/ja-jp/windows/desktop/CIMWin32Prov/setsecuritydescriptor-method-in-class-win32-printer function createAce { param([string]$user, [int]$accessMask, [int]$type, [int]$flags) $ace = ([WMIClass] "Win32_Ace").CreateInstance() $Trustee = ([WMIClass] "Win32_Trustee").CreateInstance() $SID = (new-object security.principal.ntaccount $user).translate([security.principal.securityidentifier]) [byte[]] $SIDArray = ,0 * $SID.BinaryLength $SID.GetBinaryForm($SIDArray,0) $Trustee.Name = $user $Trustee.SID = $SIDArray $ace.AccessMask = $accessMask $ace.AceType = $type $ace.AceFlags = $flags $ace.Trustee = $Trustee return $ace } # $user以外のACEと新しく作った$userのACEを結合 $aces += @(createAce -user $user -accessMask 983052 -type 0 -flags 0) + # ManagePrinters @(createAce -user $user -accessMask 983088 -type 0 -flags 9) # ManageDocuments $sd.DACL = [System.Management.ManagementBaseObject[]]$aces # DACLを更新 $printer.psbase.Scope.Options.EnablePrivileges = $true # 上書き許可 $ret = $printer.SetSecurityDescriptor($sd).ReturnValue # Security Descriptorを更新 if($ret -eq 0) { Write-Host "${user}の${printerName}に対するアクセス権を更新しました。" } else { Write-Host "アクセス権更新に失敗しました。" }
- 編集済み 牟田口大介Moderator 2018年7月28日 17:01
- 回答としてマーク ps_printer 2018年7月29日 11:46
すべての返信
-
Add-AccessControlEntry等のコマンドは、標準のものではないので、ご自分でインストールする必要があります。
まずはScript PowerShellAccessControl Module 3.0/4.0 からzipファイルをダウンロードし、Installation節の内容に従ってモジュールをインストールしてみてください。
-
ご自分で示されているサイトの2つ目(SetSecurityDescriptor method of the Win32\_Printer class | Microsoft Docs)のExamplesがまさに、標準のコマンドレットだけで実現する方法なのではないかと思いますが、いかがでしょうか。
-
牟田口様
ご返信ありがとうございます。
Examplesのコードを使わせて頂き、処理を行うと
既存のユーザやグループなどのアクセス権が失われてしまい、
希望通りの処理になりませんでした。
また、フルコントロールを指定しても何故かドキュメントの管理はチェックが入らず、これも謎です。
Everyoneだけいれば別に良いのでは?とも思ったのですが、もしも何かの拍子に消えてしまうと
面倒な事になりそうなので、他のユーザ等はそのまま残したいのです。標準コマンドレットのみで既に存在しているEveryoneのアクセス権の一部を変更するという処理はできないものなのでしょうか・・・。
(諸事情により別プリンタからセキュリティ内容をコピーする方法は利用できません。) -
Examplesのコードだと既存のDACLを完全に上書きしてしまうので、そのような結果になります。
Everyoneのアクセス権だけを変更するには、DACLに含まれるEveryone以外のACEを保持しておき、新たに生成したEveryoneのACEと結合させてDACLに反映させる必要がありそうです。
そのようなスクリプトを標準コマンドレットのみで作ってみました。
$user = "everyone" # 対象ユーザー名 $printerName = "RICOH RPCS Basic Color" # 対象プリンタ名 $printer = Get-WmiObject -Class win32_printer | Where-Object {$_.Name -eq $printerName} # プリンタのSecurity Descriptorを取得する $sd = $printer.GetSecurityDescriptor().Descriptor # DACLから$user以外のACEを取得する $aces = @($sd.DACL | Where-Object {$_.Trustee.Name -ne $user}) # ACEオブジェクトを生成する関数 # see: https://docs.microsoft.com/ja-jp/windows/desktop/CIMWin32Prov/setsecuritydescriptor-method-in-class-win32-printer function createAce { param([string]$user, [int]$accessMask, [int]$type, [int]$flags) $ace = ([WMIClass] "Win32_Ace").CreateInstance() $Trustee = ([WMIClass] "Win32_Trustee").CreateInstance() $SID = (new-object security.principal.ntaccount $user).translate([security.principal.securityidentifier]) [byte[]] $SIDArray = ,0 * $SID.BinaryLength $SID.GetBinaryForm($SIDArray,0) $Trustee.Name = $user $Trustee.SID = $SIDArray $ace.AccessMask = $accessMask $ace.AceType = $type $ace.AceFlags = $flags $ace.Trustee = $Trustee return $ace } # $user以外のACEと新しく作った$userのACEを結合 $aces += @(createAce -user $user -accessMask 983052 -type 0 -flags 0) + # ManagePrinters @(createAce -user $user -accessMask 983088 -type 0 -flags 9) # ManageDocuments $sd.DACL = [System.Management.ManagementBaseObject[]]$aces # DACLを更新 $printer.psbase.Scope.Options.EnablePrivileges = $true # 上書き許可 $ret = $printer.SetSecurityDescriptor($sd).ReturnValue # Security Descriptorを更新 if($ret -eq 0) { Write-Host "${user}の${printerName}に対するアクセス権を更新しました。" } else { Write-Host "アクセス権更新に失敗しました。" }
- 編集済み 牟田口大介Moderator 2018年7月28日 17:01
- 回答としてマーク ps_printer 2018年7月29日 11:46
-
実は、プリンタのプロパティダイアログを使い、手動でアクセス許可の「ドキュメントの管理」を「許可」にした際、生成するACEのAccessMask値とAceFlags値をそのまま使っているだけだったりします。
AceFlags=9は、OBJECT_INHERIT_ACE (0x01)とINHERIT_ONLY_ACE (0x08)のビット論理和で、子オブジェクトのみにACEを適用するという意味になります。
ちなみにAceFlags=0は適用先が「このオブジェクトのみ」になります。