_This came up when trying to work around #12427. It led to stackoverflow#61398748 which remains unresolved._
To workaround #12427 I've been trying to substitute the functionality of Add-OdbcDsn
, etc by invoking the PowerShell 7 CIM cmdlets directly. The problem is that some DSNs are not successfully created using Invoke-CimMethod
. Add-OdbcDsn
(invoked from powershell.exe) succeeds using what seems to be the same arguments. My guess is that this has something to do with the wildcards in the driver names, but I'm not sure.
I can't tell if this is a PowerShell or CIM or ODBC issue. But this issue has arisen from our transition away from Windows PowerShell, so I'm hoping I can find some help here.
Compared with my invocation of Invoke-CimMethod
, it seems like Add-OdbcDsn
must be doing something different with arguments before making the system calls. But I haven't yet found information about the implementation of Wdac (at least not that I understand).
Invoke pwsh .\test.ps1
# test.ps1
param( [Parameter(Position=1)]
[ValidateSet('add','remove','get','all')]
$Mode = 'get')
"$Mode $($PSVersionTable.PSVersion)"
if ($Mode -eq 'all') {
$test = $MyInvocation.InvocationName
powershell $test add
powershell $test get
powershell $test remove
pwsh $test add
powershell $test get
powershell $test remove
return
}
@{ Name = 'excel test'; DriverName = 'Microsoft Excel Driver (*.xls)' },
@{ Name = 'SQL test' ; DriverName = 'SQL Server' } |
% {
$arguments = @{ Name = $_.Name ; DsnType = 'User';
Platform = '32-bit' ; DriverName = $_.DriverName }
if ( $PSVersionTable.PSVersion.Major -le 5 ) {
Import-Module Wdac # powershell.exe uses Wdac
switch ($Mode) {
'add' { Add-OdbcDsn @arguments } # This call succeeds for both drivers.
'remove' { Remove-OdbcDsn @arguments -ea si } # Use powershell.exe for
'get' { Get-OdbcDsn $arguments.Name -ea si | # remove and get during test.
select Name,DriverName }
}
return
}
try {
# This call fails for the excel driver but not the SQL driver.
Invoke-CimMethod -ClassName MSFT_OdbcDsnTask `
-Namespace ROOT\Microsoft\Windows\Wdac `
-MethodName 'Add' `
-Arguments $arguments `
-ErrorAction Stop | Out-Null
} catch {
Write-Error "Error adding $($arguments.DriverName)"
Write-Error $_ }
}
all 7.0.0
add 5.1.14409.1018
get 5.1.14409.1018
Name DriverName
---- ----------
excel test Microsoft Excel Driver (*.xls)
SQL test SQL Server
remove 5.1.14409.1018
add 7.0.0
get 5.1.14409.1018
Name DriverName
---- ----------
excel test Microsoft Excel Driver (*.xls)
SQL test SQL Server
remove 5.1.14409.1018
all 7.0.0
add 5.1.14409.1018
get 5.1.14409.1018
Name DriverName
---- ----------
excel test Microsoft Excel Driver (*.xls)
SQL test SQL Server
remove 5.1.14409.1018
add 7.0.0
Write-Error: Error adding Microsoft Excel Driver (*.xls)
Write-Error: The requested object could not be found.
get 5.1.14409.1018
Name DriverName
---- ----------
SQL test SQL Server
remove 5.1.14409.1018
Name Value
---- -----
PSVersion 7.1.0-preview.2
PSEdition Core
GitCommitId 7.1.0-preview.2
OS Microsoft Windows 6.3.9600
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0螕脟陋}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
If you execute this command on PowerShell 7 x86, it works :
$Method = @{
ClassName = "MSFT_OdbcDsnTask"
Namespace = "ROOT\Microsoft\Windows\Wdac"
MethodName = "Add"
}
Invoke-CimMethod @Method -Arguments @{
Name = "test_{0}" -f [guid]::NewGuid().Guid.Split('-')[0]
DsnType = "User"
Platform = "32-bit"
DriverName = "Microsoft Access Driver (*.mdb)"
}
I guess arguments is not right. You could try wmic utility.
This works on PowerShell 7 x86 and x64 :
Import-Module C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Wdac\Wdac.psd1
but only PowerShell 7 x86 is able to modify 32-bit platform and only PowerShell 7 x64 for 64-bit platform. On PowerShell 5.1 x64 , i am able to do both.
| | 32bits driver via Invoke-CimMethod | 64bits driver via Invoke-CimMethod | 32bits driver via cdxml | 64bits driver via cdxml |
| ------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ----------------------- | ----------------------- |
| PowerShell 5.1 x86 | OK | Failed (Invoke-CimMethod : The requested object could not be found) | OK | OK |
| PowerShell 5.1 x64 | Failed (Invoke-CimMethod : The requested object could not be found) | OK | OK | OK |
| PowerShell 7.1 x86 | OK | Failed (Invoke-CimMethod : The requested object could not be found) | OK | OK |
| PowerShell 7.1 x64 | Failed (Invoke-CimMethod : The requested object could not be found) | OK | OK | OK |
Driver x64 : Microsoft Access Driver (*.mdb, *.accdb)
$Method = @{
ClassName = "MSFT_OdbcDsnTask"
Namespace = "ROOT\Microsoft\Windows\Wdac"
MethodName = "Add"
}
Invoke-CimMethod @Method -Arguments @{
Name = "test_{0}" -f [guid]::NewGuid().Guid.Split('-')[0]
DsnType = "User"
Platform = "64-bit"
DriverName = "Microsoft Access Driver (*.mdb, *.accdb)"
}
Import-Module C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Wdac\Wdac.psd1
Add-OdbcDsn -Name ("test_{0}" -f [guid]::NewGuid().Guid.Split('-')[0]) -Platform 64-bit -DsnType User -DriverName "Microsoft Access Driver (*.mdb, *.accdb)"
Drive x86 : Microsoft Access Driver (*.mdb)
$Method = @{
ClassName = "MSFT_OdbcDsnTask"
Namespace = "ROOT\Microsoft\Windows\Wdac"
MethodName = "Add"
}
Invoke-CimMethod @Method -Arguments @{
Name = "test_{0}" -f [guid]::NewGuid().Guid.Split('-')[0]
DsnType = "User"
Platform = "32-bit"
DriverName = "Microsoft Access Driver (*.mdb)"
}
Import-Module C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Wdac\Wdac.psd1
Add-OdbcDsn -Name ("test_{0}" -f [guid]::NewGuid().Guid.Split('-')[0]) -Platform 32-bit -DsnType User -DriverName "Microsoft Access Driver (*.mdb)"
@alx9r if you import directly the module, everything is working :)
For Microsoft Excel Driver (*.xls) too?
@iSazonov Yes.
@fMichaleczek
Invoking pwsh { Import-Module C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Wdac\Wdac.psd1 }
on this computer results in the following error using both 7.0.0 and 7.1.0:
Import-Module: Failed to generate proxies for remote module 'Wdac'. Running the Get-FormatData command in a remote session reported the following error: Unable to cast object of type 'Microsoft.PowerShell.Commands.Internal.Format.ControlReference' to type 'Microsoft.PowerShell.Commands.Internal.Format.ComplexControlBody'..
That is the same error as #12427 using Import-Module -UseWindowsPowerShell
.
I wonder what the difference is that it works on your computer but not here.
I wonder what the difference is that it works on your computer but not here.
My OS Version : Windows 10 18363
PS C:\Users\LEXPEC> $PSVersionTable
Name Value
---- -----
PSVersion 7.0.0
PSEdition Core
GitCommitId 7.0.0
OS Microsoft Windows 10.0.18363
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0鈥
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
I try on a Windows 2012R2, it works as expected with this command
Import-Module Wdac -SkipEditionCheck
I test Add-OdbcDsn/Get-OdbcDns successly.
@iSazonov I see you have added the "Resolution Answered". The original question has not been answered. All we have is an irreplicable workaround for #12427, which is a different issue. As far as I can tell this original question remains.
The behaviour for Invoke-CimMethod and wmic.exe are identical.
C:\Windows\system32\wbem\wmic.exe /namespace:\\ROOT\Microsoft\Windows\Wdac CLASS MSFT_OdbcDsnTask CALL Add DriverName="Microsoft Access Driver (*.mdb)" DsnType="User" Name="test123" Platform="32-bit"
Executing (MSFT_OdbcDsnTask)->Add()
ERROR:
Description = Not found
C:\Windows\syswow64\wbem\wmic.exe /namespace:\\ROOT\Microsoft\Windows\Wdac CLASS MSFT_OdbcDsnTask CALL Add DriverName="Microsoft Access Driver (*.mdb)" DsnType="User" Name="test987" Platform="32-bit"`
Executing (MSFT_OdbcDsnTask)->Add()
Method execution successful.
Out Parameters:[abstract]
class __PARAMETERS
{
[out] uint32 ReturnValue = 0;
};
@fMichaleczek
The behaviour for Invoke-CimMethod and wmic.exe are identical.
I'm not surprised. That suggests Add-OdbcDsn
is doing somewhat more than simply passing the arguments through to the system call. I've been reading through the files in C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\Wdac
but I haven't puzzled out how PowerShell interprets those files to make the system calls. Do you have any insight there?
@alx9r "Cmdlet definition XML (CDXML) is a way to create a Windows PowerShell module from a WMI class by using the cmdlets-over-objects technology that was introduced in Windows PowerShell 3.0"
https://devblogs.microsoft.com/scripting/registry-cmdlets-first-steps-with-cdxml/
It's deep inside the OS, in my opinion, these CIM classes has been made to be consume by CDXML first (see bellow [OUT]cmdletOutput(array of object:MSFT_OdbcDsn) ) . It's why, it will hard to diagnostic more. You can import WDAC module natively (SkipEdition has been added for that), so i don't see what to do more. At the end, you have a solution to move on this problem. I let you test more, because I only take my free time to give you a way.
C:\Windows\system32\wbem\wmic.exe /namespace:\\ROOT\Microsoft\Windows\Wdac CLASS MSFT_OdbcDsnTask CALL /?
The following verb(s)/method(s) are available:
Call [ In/Out ]Params&type Status
==== ===================== ======
Add [IN ]DriverName(string) Implemented
[IN ]DsnType(string)
[IN ]Name(string)
[IN ]PassThru(boolean)
[IN ]Platform(string)
[IN ]SetPropertyValue(array of string)
[OUT]cmdletOutput(array of object:MSFT_OdbcDsn)
[OUT]ReturnValue(uint32)
Scripting BlogSummary: Richard Siddaway shows how to start creating CDXML cmdlets. Honorary Scripting Guy, Richard Siddaway, here today filling in for my good friend, The Scripting Guy. This is the second post in a series. Yesterday, in Registry Cmdlets: Working with the Registry,
wmic shows that the error comes from Windows and you should ask Windows team.
Or reverse engineering Add-OdbcDsn.
You could use WMI tracing https://docs.microsoft.com/en-us/windows/win32/wmisdk/tracing-wmi-activity
Starting with Windows聽Vista, the WMI service does not use the WMI Log Files. Instead, it uses Event Tracing for Windows (ETW) and events are available through Event Viewer or the Wevtutil command-line tool.
It's deep inside the OS, in my opinion, these CIM classes has been made to be consume by CDXML first (see bellow [OUT]cmdletOutput(array of object:MSFT_OdbcDsn) ) . It's why, it will hard to diagnostic more.
I see.
You can import WDAC module natively (SkipEdition has been added for that)
I agree. Thank you for pointing out that flag. I have Import-Module Wdac -SkipEditionCheck
working here and it's looking promising that that will ultimately be the solution.
I'm not entirely comfortable that the original question does not have an answer. It means that we don't have a fallback when transitioning WMI/CIM functionality we have in Windows PowerShell to PowerShell 7. Being able to trace the WMI/CIM system calls that a module working under Windows PowerShell performs would have meant that the worst-case scenario would be to rewrite something to make those same system calls in PowerShell 7. But it looks like that capability doesn't exist. That suggests either a lot of regression of WMI/CIM management ability from Windows PowerShell to PowerShell 7 or indefinite dependence on remoting into Windows PowerShell to get the job done.
You could use WMI tracing...
I can see the log events of the calls in Microsoft/Windows/Wmi-Activity/Trace
and /Debug
but none of those events reveal the arguments, at least not to the degree that the difference between Add-OdbcDsn
and Invoke-CimMethod
are apparent.
reverse engineering Add-OdbcDsn
This is a minimal version of Add-OdbcDsn :
function Add-CustomOdbcDsn {
param(
[Parameter(Mandatory, Position=0)]
[ValidateLength(1, 32)]
[ValidateNotNullOrEmpty()]
[string]
$Name,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]
$DriverName,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[ValidateSet('32-bit','64-bit')]
[string]
$Platform,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[ValidateSet('User','System')]
[string]
$DsnType
)
$className = 'Root/Microsoft/Windows/Wdac/MSFT_OdbcDsnTask'
$methodName = 'Add'
$methodParameters = [System.Collections.Generic.List[Microsoft.PowerShell.Cmdletization.MethodParameter]]$(
[Microsoft.PowerShell.Cmdletization.MethodParameter]@{Name = 'Name'; ParameterType = 'System.String'; Bindings = 'In'; Value = $Name; IsValuePresent = $true}
[Microsoft.PowerShell.Cmdletization.MethodParameter]@{Name = 'DriverName'; ParameterType = 'System.String'; Bindings = 'In'; Value = $DriverName; IsValuePresent = $true}
[Microsoft.PowerShell.Cmdletization.MethodParameter]@{Name = 'Platform'; ParameterType = 'System.String'; Bindings = 'In'; Value = $Platform; IsValuePresent = $true}
[Microsoft.PowerShell.Cmdletization.MethodParameter]@{Name = 'DsnType'; ParameterType = 'System.String'; Bindings = 'In'; Value = $DsnType; IsValuePresent = $true}
)
$cimAdapter = [Microsoft.PowerShell.Cmdletization.Cim.CimCmdletAdapter]::new()
$cimAdapter.Initialize($PSCmdlet, $className, '1.0.0', '1.0.0', [System.Collections.Generic.Dictionary[string,string]]::new())
$cimAdapter.BeginProcessing()
$cimAdapter.ProcessRecord([Microsoft.PowerShell.Cmdletization.MethodInvocationInfo]::new($methodName, $methodParameters, $null))
$cimAdapter.EndProcessing()
}
Add-CustomOdbcDsn -Name ("Test_{0}" -f [guid]::NewGuid().Guid.Split('-')[0]) -DriverName "Microsoft Access Driver (*.mdb)" -Platform "32-bit" -DsnType "User"
Here, the WMI trace between the 2 commands (https://github.com/luctalpe/WMIMon)
Invoke-CimMethod : (Error : The requested object could not be found.)
***** 10:17:15.030 Grp=96149 _ClientProcessId=10364 [pwsh.exe] MYCOMPUTER MYCOMPUTER\MYUSER
IWbemServices::Connect
***** 10:17:15.047 Grp=96152 Op=96153 _ClientProcessId=10364 [pwsh.exe] MYCOMPUTER MYCOMPUTER\MYUSER
Start IWbemServices::ExecMethod - Root\Microsoft\Windows\Wdac : MSFT_OdbcDsnTask::Add
***** 10:17:15.185 Grp=96162 _ClientProcessId=10364 [pwsh.exe] MYCOMPUTER MYCOMPUTER\MYUSER
IWbemServices::Connect
***** 10:17:15.189 Stop Op=96162 0x0
***** 10:17:15.193 Stop Op=96149 0x0
***** 10:17:15.193 Stop Op=96153 0x80041002
0x80041002 => WBEM_E_NOT_FOUND
Add-CustomOdbcDsn : (No Error)
***** 10:23:02.394 Grp=96239 _ClientProcessId=10364 [pwsh.exe] MYCOMPUTER MYCOMPUTER\MYUSER
IWbemServices::Connect
***** 10:23:02.411 Grp=96240 Op=96241 _ClientProcessId=10364 [pwsh.exe] MYCOMPUTER MYCOMPUTER\MYUSER
Start IWbemServices::ExecMethod - Root\Microsoft\Windows\Wdac : MSFT_OdbcDsnTask::Add
***** 10:23:02.416 Grp=96242 Op=96243 _ClientProcessId=10428 [] MYCOMPUTER MYCOMPUTER\MYUSER
Start IWbemServices::ExecMethod - Root\Microsoft\Windows\Wdac : MSFT_OdbcDsnTask::Add
***** 10:23:02.450 Stop Op=96243 0x0
***** 10:23:02.452 Stop Op=96241 0x0
GitHubTool to monitor WMI activity on Windows. Contribute to luctalpe/WMIMon development by creating an account on GitHub.
@fMichaleczek I really appreciate your help. I think you've got me on the right track. I still haven't seen arguments, but the WMIMon reveals that Add-OdbcDsn always attempts the WMI call itself, but sometimes that call is followed by the same call by WinPrvSE.exe. I suspect this is able to overcome the platform mismatch.
I ran this script and monitored the traffic with WMIMon. The results are as follows:
| id | exe Platform | Method | DSN Platform | Result | executables |
|-- |-- |-- |-- |-- |-- |
| 1 | x86 | CimCmdletAdapter | 32-bit | OK | powershell |
| 2 | x86 | CimCmdletAdapter | 64-bit | | |
| 3 | x86 | CimMethod | 32-bit | OK | powershell |
| 4 | x86 | CimMethod | 64-bit | | |
| 5 | x86 | Wdac | 32-bit | OK | powershell |
| 6 | x86 | Wdac | 64-bit | | |
| 7 | x64 | CimCmdletAdapter | 32-bit | OK | powershell, WinPrvSE |
| 8 | x64 | CimCmdletAdapter | 64-bit | | |
| 9 | x64 | CimMethod | 32-bit | The requested object could not be found. | powershell |
| 10 | x64 | CimMethod | 64-bit | | |
| 11 | x64 | Wdac | 32-bit | OK | powershell, WinPrvSE |
| 12 | x64 | Wdac | 64-bit | | |
Note the lines where there is a mismatch between the powershell .exe and DSN driver platforms. Success seems to be achieved by CimMethod, and CimCmdletAdapter by way of WinPrvSE.exe. On the other hand, CimMethod does not result in traffic from WinPrvSE.exe and fails.
I have not yet reproduced the corresponding results for 64-bit DSN platform because I do not have the corresponding 64-bit driver available on this system.
My hypothesis is as follows:
Microsoft Access Driver (*.mdb)
driver we would see "The requested object not found" for id 4 and WinPrvSE.exe traffic for id 2 and 6.When we try to invoke the static method Add, on the class Root\Microsoft\Windows\Wdac:MSFT_OdbcDsnTask we see 2 different results between the Cmdlet Invoke-CimMethod and the Cmdlet Add-OdbcDsn from the CDXML module WDAC.
There is 2 API in PowerShell which use Wmi v2 aka Microsoft.Management.Infrastructure :
*
-Cim*
)After a lot of reverse-engineering and debug, I found a difference between the 2 API in the use of Microsoft.Management.Infrastructure.Options.CimOperationOptions :
Microsoft.Management.Infrastructure.CimCmdlets set WriteErrorMode to CimCallbackMode.Inquire
https://github.com/PowerShell/PowerShell/blob/f4382202ae4622bf26795e29a7b39b9d7cdfb3fb/src/Microsoft.Management.Infrastructure.CimCmdlets/CimSessionProxy.cs#L623-L630
Microsoft.PowerShell.Cmdletization.Cim set by default WriteErrorMode to CimCallbackMode.Report and use the method SetPromptUserRegularMode with parameters CimCallbackMode.Ignore and automaticConfirmation to true
https://github.com/PowerShell/PowerShell/blob/f4382202ae4622bf26795e29a7b39b9d7cdfb3fb/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimChildJobBase.cs#L473-L486
https://github.com/PowerShell/PowerShell/blob/f4382202ae4622bf26795e29a7b39b9d7cdfb3fb/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimChildJobBase.cs#L453-L471
The API Microsoft.Management.Infrastructure hasn't a lot of documentation because it's a wrapper for libMI, but there is more in this documentation [MS-WSMV]: Web Services Management Protocol Extensions for Windows Vista :
If I understand the problem correctly, "Invoke-Method" doesn't handle interactive prompt while the Cmdletization.Cim API handle a little bit better (depending of ErrorActionPreference value) and at least configure prompt to response automatically by default.
Currently, I don't have enough perspective to know if it impacts more than the Wdac namespace, but at least, we have an explanation on the differences in behavior. Changing default behaviour of Invoke-CimMethod would be a breaking change, since it's identical to Invoke-WmiMethod.
You will find below the different API behaviors, this can also be useful if someone has other problems around WMI / CMI static method and want a starter pack to debug.
# On a computer with Office 32-bit from a PowerShell x64
$namespace = "Root/Microsoft/Windows/Wdac"
$className = "MSFT_OdbcDsnTask"
$methodName = "Add"
$arguments = @{
Name = "ExcelTest"
DriverName = "Microsoft Excel Driver (*.xls)"
PassThru = $true
Platform = "32-bit"
DsnType = "User"
}
# Wmi v1 - WMIC
$arguments.Name = "ExcelTest_{0}" -f [guid]::NewGuid().Guid.Split('-')[0]
& "$env:windir\system32\wbem\wmic.exe" @(
'/namespace:\\{0}' -f $namespace.Replace('/', '\')
'CLASS'
$className
'CALL'
'Add'
'Name="{0}"' -f $arguments.Name
'DriverName="{0}"' -f $arguments.DriverName
'PassThru="{0}"' -f $arguments.PassThru
'Platform="{0}"' -f $arguments.Platform
'DsnType="{0}"' -f $arguments.DsnType
)
# Executing (MSFT_OdbcDsnTask)->Add()
# ERROR:
# Description = Not found
# Wmi v1 - System.Management
$arguments.Name = "ExcelTest_{0}" -f [guid]::NewGuid().Guid.Split('-')[0]
([wmiclass]"${namespace}:${className}").$methodName(
$arguments.Name,
$arguments.DriverName,
$null,
$arguments.PassThru,
$arguments.Platform,
$arguments.DsnType
)
# MethodInvocationException: Exception calling "Add" : "Not found "
# Wmi v2 - Microsoft.Management.Infrastructure.CimCmdlets
$arguments.Name = "ExcelTest_{0}" -f [guid]::NewGuid().Guid.Split('-')[0]
Invoke-CimMethod -Namespace $namespace -ClassName $className -MethodName $methodName -Arguments $arguments
# Invoke-CimMethod: The requested object could not be found.
# Wmi v2 - CDXML Module WDAC
$arguments.Name = "ExcelTest_{0}" -f [guid]::NewGuid().Guid.Split('-')[0]
Add-OdbcDsn @arguments
# Name : ExcelTest_a6b6e56a
# DsnType : User
# Platform : 32-bit
# DriverName : Microsoft Excel Driver (*.xls)
# Attribute : {SafeTransactions, UserCommitSync, FirstRowHasNames, Threads鈥
# Wmi v2 - Microsoft.PowerShell.Cmdletization.Cim
function Invoke-CmdletizationCimMethod {
param(
[Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Namespace,
[Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $ClassName,
[Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $MethodName,
[Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [hashtable] $Arguments
)
$methodParameters = [System.Collections.Generic.List[Microsoft.PowerShell.Cmdletization.MethodParameter]]::new()
$Arguments.GetEnumerator().Foreach{
if ( $null -ne $_.Value) {
$methodParameters.Add([Microsoft.PowerShell.Cmdletization.MethodParameter]@{
Name = $_.Name
ParameterType = $_.Value.GetType().FullName
Bindings = 'In'
Value = $_.Value
IsValuePresent = $true
})
}
}
$methodParameters.Add([Microsoft.PowerShell.Cmdletization.MethodParameter]@{
Name = 'CmdletOutput'
ParameterType = 'Microsoft.Management.Infrastructure.CimInstance[]'
ParameterTypeName = 'Microsoft.Management.Infrastructure.CimInstance#{0}' -f $ClassName
Bindings = 'Out'
Value = $null
IsValuePresent = $true
})
$returnValue = [Microsoft.PowerShell.Cmdletization.MethodParameter]@{
Name = 'ReturnValue'
ParameterType = 'System.Int32'
Bindings = 'Error'
Value = $null
IsValuePresent = $false
}
$cimAdapter = [Microsoft.PowerShell.Cmdletization.Cim.CimCmdletAdapter]::new()
$cimAdapter.Initialize($PSCmdlet, "$Namespace/$ClassName", '1.0.0', '1.0.0', [System.Collections.Generic.Dictionary[string,string]]::new())
$cimAdapter.BeginProcessing()
$cimAdapter.ProcessRecord([Microsoft.PowerShell.Cmdletization.MethodInvocationInfo]::new($MethodName, $methodParameters, $returnValue))
$cimAdapter.EndProcessing()
}
$arguments.Name = "ExcelTest_{0}" -f [guid]::NewGuid().Guid.Split('-')[0]
Invoke-CmdletizationCimMethod -Namespace $namespace -ClassName $className -MethodName $methodName -Arguments $arguments
# Name : ExcelTest_f5141a52
# DsnType : User
# Platform : 32-bit
# DriverName : Microsoft Excel Driver (*.xls)
# Attribute : {SafeTransactions, UserCommitSync, FirstRowHasNames, Threads鈥
# Wmi v2 - Microsoft.Management.Infrastructure
function Invoke-InfrastructureCimMethod {
param(
[Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Namespace,
[Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $ClassName,
[Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $MethodName,
[Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [hashtable] $Arguments,
[switch] $SetPromptUserRegularMode
)
$methodParameters = [Microsoft.Management.Infrastructure.CimMethodParametersCollection]::new()
$Arguments.GetEnumerator().Foreach{
if ( $null -ne $_.Value) {
$methodParameters.Add([Microsoft.Management.Infrastructure.CimMethodParameter]::Create(
$_.Name,
$_.Value,
[Microsoft.Management.Infrastructure.CimFlags]::None
))
}
}
$operationOptions = [Microsoft.Management.Infrastructure.Options.CimOperationOptions]::new()
if ($SetPromptUserRegularMode) {
$operationOptions.SetPromptUserRegularMode([Microsoft.Management.Infrastructure.Options.CimCallbackMode]::Ignore, $true)
$operationOptions.WriteErrorMode = [Microsoft.Management.Infrastructure.Options.CimCallbackMode]::Report
}
else {
$operationOptions.WriteErrorMode = [Microsoft.Management.Infrastructure.Options.CimCallbackMode]::Inquire
}
$cimSession = [CimSession]::Create(".")
$result = $cimSession.InvokeMethod($Namespace, $ClassName, $MethodName, $methodParameters, $operationOptions)
$cimSession.Dispose()
if ($result.OutParameters) {
$result.OutParameters["cmdletOutput"].Value
}
}
# Without SetPromptUserRegularMode
$arguments.Name = "ExcelTest_{0}" -f [guid]::NewGuid().Guid.Split('-')[0]
Invoke-InfrastructureCimMethod -Namespace $namespace -ClassName $className -MethodName $methodName -Arguments $arguments
# Exception calling "InvokeMethod" with "5" argument(s): "The requested object could not be found."
# With SetPromptUserRegularMode
$arguments.Name = "ExcelTest_{0}" -f [guid]::NewGuid().Guid.Split('-')[0]
Invoke-InfrastructureCimMethod -Namespace $namespace -ClassName $className -MethodName $methodName -Arguments $arguments -SetPromptUserRegularMode
# Name : ExcelTest_d115cdfa
# DsnType : User
# Platform : 32-bit
# DriverName : Microsoft Excel Driver (*.xls)
# Attribute : {SafeTransactions, UserCommitSync, FirstRowHasNames, Threads鈥
@iSazonov The error doesn't come from Windows but from Invoke-CimMethod which doesn't handle the interactive prompt or automatic response.
Changing default behaviour of Invoke-CimMethod would be a breaking change, since it's identical to Invoke-WmiMethod.
I believe we could accept this, maybe for ErrorAction Continue or SilentlyContinue.
Most helpful comment
@iSazonov The error doesn't come from Windows but from Invoke-CimMethod which doesn't handle the interactive prompt or automatic response.