question

Vargatron-7659 avatar image
0 Votes"
Vargatron-7659 asked MotoX80 answered

Powershell script will execute correctly locally but not remotely

I have a PowerShell script to remove an AlwaysOn VPN device tunnel connection from the PCs in my organization. The script executes and removes the connection as expected when I run it locally against the local connection. The problem is that I need to be able to deploy this to remote users and when I've tried it doesn't execute. I have tried to run the script through SCCM and also through a remote PowerShell command line. When I run the script through remote PowerShell session on our SCCM server (WinSvr 2012 R2), I get the following error:

PS C:\Windows\system32> Invoke-Command -FilePath D:\Sources\OS\Settings\Remove-AOVPNConnection-Test2.ps1 -ComputerName WIN10-IT-01
Cannot bind argument to parameter 'InputObject' because it is null.
+ CategoryInfo : InvalidData: (:) [Remove-CimInstance], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.Management.Infrastructure.CimCmdlets.Re
moveCimInstanceCommand
+ PSComputerName : WIN10-IT-01


When I run the script as a package through Microsoft Endpoint Configuration Manager v2006, it reports that the script ran successfully but the connection is not removed from the remote PC and I see the following information in the Ccm32BitLauncher log:

Commandline: "C:\WINDOWS\sysnative\windowsPowershell\v1.0\powershell.exe" -ExecutionPolicy Bypass -File .\Remove-AOVPNConnection-Test.ps1
Working directory: C:\WINDOWS\ccmcache\jh\
Interactive: 0
Window mode: 5

My preferred way to deploy this is through SCCM and originally I assumed that the issue was related to my client being Win10 64-bit and the SCCM client running the 32-bit version of PowerShell despite using the 'sysnative' path (although, I've also tried system32 and syswow64). However, the SCCM server that I ran the remote PS session from, is 64-bit and I still am getting the above error.

Below is the script. It is basically paired Any advice for running this remotely would be greatly appreciated.

[CmdletBinding(SupportsShouldProcess)]

$ProfileName="AlwaysOn VPN"

 # // Escape spaces in profile name
 $ProfileNameEscaped = $ProfileName -Replace ' ', '%20'

 # // Get VPN profile
 $CimInstance = Get-CimInstance -Namespace 'root\cimv2\mdm\dmmap' -ClassName 'MDM_VPNv2_01' -Filter "ParentID='./Vendor/MSFT/VPNv2' and InstanceID='$ProfileNameEscaped'"

 # // Remove VPN profile
 Write-Verbose "Removing VPN connection ""$ProfileName""..."
 Remove-CimInstance -CimInstance $CimInstance

// Registry clean-up


Write-Verbose "Cleaning up registry artifacts for VPN connection ""$ProfileName""..."

// Remove registry artifacts from ERM\Tracked

Write-Verbose "Searching for profile $ProfileNameEscaped..."

$BasePath = "HKLM:\SOFTWARE\Microsoft\EnterpriseResourceManager\Tracked"
$Tracked = Get-ChildItem -Path $BasePath

ForEach ($Item in $Tracked) {

 Write-Verbose "Processing $(Convert-Path $Item.PsPath)..."
 $Key = Get-ChildItem $Item.PsPath -Recurse | Where-Object { $_ | Get-ItemProperty -Include "Path*" }
 $PathCount = ($Key.Property -Match "Path\d+").Count
 Write-Verbose "Found a total of $PathCount Path* entries."

 # // There may be more than 1 matching key
 ForEach ($K in $Key) {

     $Path = $K.Property | Where-Object { $_ -Match "Path\d+" }
     $Count = $Path.Count
     Write-Verbose "Found $Count Path* entries under $($K.Name)."

     ForEach ($P in $Path) {

         Write-Verbose "Testing $P..."
         $Value = $K.GetValue($P)

         If ($Value -Match "$($ProfileNameEscaped)$") {

             Write-Verbose "Removing $Value under $($K.Name)..."
             $K | Remove-ItemProperty -Name $P
                
             # // Decrement count
             $Count--

         }

     } # // ForEach $P in $Path

     #  // Update count
     Write-Verbose "Setting count to $Count..."
     $K | Set-ItemProperty -Name Count -Value $Count

 } # // ForEach $K in $Key

} # // ForEach $Item in $Tracked

// Remove registry artifacts from NetworkList\Profiles

$Path = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles\'
Write-Verbose "Searching $path for VPN profile ""$ProfileName""..."
$Key = Get-Childitem -Path $Path | Where-Object { (Get-ItemPropertyValue $_.PsPath -Name Description) -eq $ProfileName }

If ($Key) {

 Write-Verbose "Removing $($Key.Name)..."
 $Key | Remove-Item

}

Else {

 Write-Verbose "No profiles found matching ""$ProfileName"" in the network list."

}

// Remove registry artifacts from RasMan\Config

$Path = 'HKLM:\System\CurrentControlSet\Services\RasMan\Config\'
$Name = 'AutoTriggerDisabledProfilesList'

Write-Verbose "Searching $Name under $Path for VPN profile called ""$ProfileName""..."

Try {

 # // Get the current registry values as an array of strings
 [string[]]$Current = Get-ItemPropertyValue -Path $Path -Name $Name -ErrorAction Stop

}

Catch {

 Write-Verbose "$Name does not exist under $Path. No action required."

}

If ($Current) {

 #// Create ordered hashtable
 $List = [Ordered]@{}
 $Current | ForEach-Object { $List.Add("$($_.ToLower())", $_) }

 # //Search hashtable for matching VPN profile and remove if present
 If ($List.Contains($ProfileName)) {

     Write-Verbose "Profile found. Removing entry..."
     $List.Remove($ProfileName)
     Write-Verbose "Updating the registry..."
     Set-ItemProperty -Path $Path -Name $Name -Value $List.Values

 }

}

Else {

 Write-Verbose "No profiles found matching ""$ProfileName""."

}

windows-server-powershell
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

RichMatheisen-8856 avatar image
0 Votes"
RichMatheisen-8856 answered Vargatron-7659 commented

Looks like the Get-CimInstance is failing. But you're not doing any error checking! Try wrapping that cmdlet in a Try/Catch and returning the information from the exception object so you can figure out why that's happening. It may be something as easy as "Access denied".

Be sure to add "-ErrorAction Stop" to the Get-CimInstance cmdlet too!

 $ProfileNameEscaped = "BlahBlahBlah"
 Try{
     $CimInstance = Get-CimInstance -Namespace 'root\cimv2\mdm\dmmap' -ClassName 'MDM_VPNv2_01' -Filter "ParentID='./Vendor/MSFT/VPNv2' and InstanceID='$ProfileNameEscaped'" -ErrorAction STOP
 }
 Catch{
     $_
 }


· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks I'll give that a try and post the results.

0 Votes 0 ·

Sorry, I posted results from the wrong session a minute ago... So wrapped the cmdlet in a try/catch and got the same result.

PS C:\Windows\system32> Invoke-Command -FilePath D:\Sources\OS\Settings\Remove-AOVPNConnection-Test2-mod.ps1 -ComputerName WIN10-IT-01
Cannot bind argument to parameter 'InputObject' because it is null.
+ CategoryInfo : InvalidData: (:) [Remove-CimInstance], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.Management.Infrastructure.CimCmdlets.Re
moveCimInstanceCommand
+ PSComputerName : WIN10-IT-01

For reference, the beginning of the script now looks like this...


[CmdletBinding(SupportsShouldProcess)]

$ProfileName="AlwaysOn VPN"

 # // Escape spaces in profile name
 $ProfileNameEscaped = $ProfileName -Replace ' ', '%20'

 # // Get VPN profile

Try{
$CimInstance = Get-CimInstance -Namespace 'root\cimv2\mdm\dmmap' -ClassName 'MDM_VPNv2_01' -Filter "ParentID='./Vendor/MSFT/VPNv2' and InstanceID='$ProfileNameEscaped'" -ErrorAction STOP
}
Catch{
$_
}

 # // Remove VPN profile
 Write-Verbose "Removing VPN connection ""$ProfileName""..."
 Remove-CimInstance -CimInstance $CimInstance





0 Votes 0 ·
RichMatheisen-8856 avatar image
0 Votes"
RichMatheisen-8856 answered Vargatron-7659 commented

When you run your script locally, are you using an account that has administrative privileges on the local machine?

If the account that uses the Invoke-Command to run the script on the remote machine doesn't have administrative privileges on the remote machine it'll probably fail. It's also not possible to elevate a script run on a remote machine because there's no way on that machine to deal with the UAC prompt.

You can provide the necessary credential in the Invoke-Command, though. If the account has administrative privilege on the target machine the script will run "elevated".

If you use SCCM to launch the script on the remote machine you can add "-RunAs" to the PowerShell.exe command line. That should help (if admin privilege is the problem).

You can also add "-Verbose" to the Get-CimInstance cmdlet. That may help.

In addition to all of that, try redirecting both the ERROR, WARNING, and VERBOSE data streams to the "SUCCESS" stream (i.e. the "STDOUT"). Add "4>&1 3>&1 2>&1" to the end of the Invoke-Command cmdlet to do that.

If no exception is being generated, there are no warnings, and the verbose data doesn't add anything that helps, it' possible that the problem is that the query isn't finding anything. If that's the case then just check for a $null value in $CimInstance and skip the Remove-CimInstance cmdlet if that's true.

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks for your replies so far. Yes, I am using an admin account that is both an admin on the server that I run the Invoke command from and on the client that I'm running the command against. Including Verbose and the STDOUT gives me the following output...

PS C:\Windows\system32> Invoke-Command -FilePath D:\Sources\OS\Settings\Remove-AOVPNConnection-Test2-mod.ps1 -ComputerName WIN10-IT-01 4>&1 3>&1 2>&1
VERBOSE: Perform operation 'Query CimInstances' with following parameters, ''queryExpression' = SELECT * FROM MDM_VPNv2_01 WHERE ParentID='./Vendor/MSFT/VPNv2
' and InstanceID='AlwaysOn%20VPN','queryDialect' = WQL,'namespaceName' = root\cimv2\mdm\dmmap'.
VERBOSE: Operation 'Query CimInstances' complete.
Cannot bind argument to parameter 'InputObject' because it is null.
+ CategoryInfo : InvalidData: (:) [Remove-CimInstance], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.Management.Infrastructure.CimCmdlets.RemoveCimInstanceCommand
+ PSComputerName : WIN10-IT-01

0 Votes 0 ·
RichMatheisen-8856 avatar image
0 Votes"
RichMatheisen-8856 answered

In the WQL query, isn't the "%" character a wildcard???? Shouldn't that "%20" (supposing an 'escaped' space?) be "[<space>]" (a single space character)? Does it even need to handled in some special way since it's inside a quoted string?

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Vargatron-7659 avatar image
0 Votes"
Vargatron-7659 answered RichMatheisen-8856 commented

No, that was my mistake. I edited out the first part of it because it included my company's initials. I meant to delete the first escaped space but didn't. Good catch though!

· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Also, it is stored that way in the registry (with the escaped spaces). That's why it's in that format.

0 Votes 0 ·

Why not try escaping the "%" in the name?

 $ProfileNameEscaped = $ProfileName -Replace ' ', '\%20'
0 Votes 0 ·
Vargatron-7659 avatar image
0 Votes"
Vargatron-7659 answered MotoX80 commented

So i have cleaned up the script. It now looks like this:

$ErrorActionPreference = "Continue"
Start-Transcript -path C:\output.txt -append

$CimInstance = Get-CimInstance -Namespace "root\cimv2\mdm\dmmap" -ClassName "MDM_VPNv2_01" -Filter "ParentID='./Vendor/MSFT/VPNv2' and InstanceID='AlwaysOn%20VPN'"
Remove-CimInstance -CimInstance $CimInstance

$BasePath = "HKLM:\SOFTWARE\Microsoft\EnterpriseResourceManager\Tracked"
$Tracked = Get-ChildItem -Path $BasePath

ForEach ($Item in $Tracked) {

 $Key = Get-ChildItem $Item.PsPath -Recurse | Where-Object { $_ | Get-ItemProperty -Include "Path*" }
 $PathCount = ($Key.Property -Match "Path\d+").Count
    
 ForEach ($K in $Key) {

     $Path = $K.Property | Where-Object { $_ -Match "Path\d+" }
     $Count = $Path.Count
        
     ForEach ($P in $Path) {

         $Value = $K.GetValue($P)

         If ($Value -Match "$('AlwaysOn%20VPN')$") {

             $K | Remove-ItemProperty -Name $P
                
             $Count--

         }

     }
        
     $K | Set-ItemProperty -Name Count -Value $Count

 }

}

$Path = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles\'
$Key = Get-Childitem -Path $Path | Where-Object { (Get-ItemPropertyValue $_.PsPath -Name Description) -eq 'WWP AlwaysOn VPN' }

If ($Key) {

 $Key | Remove-Item

}

Else {

 Write-Verbose "No profiles found matching WWP AlwaysOn VPN in the network list."

}

$Path = 'HKLM:\System\CurrentControlSet\Services\RasMan\Config\'
$Name = 'AutoTriggerDisabledProfilesList'


Try {

 [string[]]$Current = Get-ItemPropertyValue -Path $Path -Name $Name -ErrorAction Stop

}

Catch {

 Write-Verbose "$Name does not exist under $Path. No action required."

}

If ($Current) {

 $List = [Ordered]@{}
 $Current | ForEach-Object { $List.Add("$($_.ToLower())", $_) }

 If ($List.Contains("AlwaysOn VPN")) {

     $List.Remove("AlwaysOn VPN")
     Set-ItemProperty -Path $Path -Name $Name -Value $List.Values

 }

}

Else {

 Write-Verbose "No profiles found matching AlwaysOn VPN."

}
Stop-Transcript

I still get the following error when running remotely:

PS>TerminatingError(Remove-CimInstance): "Cannot bind argument to parameter 'InputObject' because it is null."
Remove-CimInstance : Cannot bind argument to parameter 'InputObject' because it is null.
At C:\WINDOWS\CCM\ScriptStore\0832E36A-1D14-4D93-86AC-3B460BE63DE0_E0892DBEC4B88BA44EA0013AC972535BDDF445FF0D6F543CC3ADD
67944C526B8.ps1:5 char:33
+ Remove-CimInstance -CimInstance $CimInstance
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Remove-CimInstance], ParameterBindingValidationException
+ FullyQualifiedErrorId :
ParameterArgumentValidationErrorNullNotAllowed,Microsoft.Management.Infrastructure.CimCmdlets.RemoveCimInstanceCommand
Remove-CimInstance : Cannot bind argument to parameter 'InputObject' because it is null.
At C:\WINDOWS\CCM\ScriptStore\0832E36A-1D14-4D93-86AC-3B460BE63DE0_E0892DBEC4B88BA44EA0013AC972535BDDF445FF0D6F543CC3AD
D67944C526B8.ps1:5 char:33
+ Remove-CimInstance -CimInstance $CimInstance
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Remove-CimInstance], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.Management.Infrastructure.CimCm
dlets.RemoveCimInstanceCommand

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

How about editing your post and putting the entire script into a Code Sample block? Click the "101010" icon.

0 Votes 0 ·
RichMatheisen-8856 avatar image
0 Votes"
RichMatheisen-8856 answered

Are you using the "Code Sample" editor when you post code? If not, please do so. Separating code from text is error prone (e.g., dropped '_' characters, 'smart quotes' instead of straight-quotes, hyphens replaced by En Dash, etc.).

Since you're not getting any result from your query, I'd suggest that you start by removing " and InstanceID='AlwaysOn%20VPN'" from the filter string and try it again. There's no need for you to test with the entire script. Just include the Get-CimInstance in the testing.

If removing the InstanceID part of the query still doesn't work, remove the entire "-Filter" and test again.

If the InstanceID turns out to be the problem, try using "AlwaysOn\%20VPN", and if that doesn't work "AlwaysOn VPN".

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Vargatron-7659 avatar image
0 Votes"
Vargatron-7659 answered
 $ErrorActionPreference = "Continue"
 Start-Transcript -path C:\output.txt -append
    
 $CimInstance = Get-CimInstance -Namespace 'root\cimv2\mdm\dmmap' -ClassName 'MDM_VPNv2_01' -Filter "ParentID='./Vendor/MSFT/VPNv2' and InstanceID='WWP%20AlwaysOn%20VPN'"
 Remove-CimInstance -CimInstance $CimInstance
    
 $BasePath = "HKLM:\SOFTWARE\Microsoft\EnterpriseResourceManager\Tracked"
 $Tracked = Get-ChildItem -Path $BasePath
        
 ForEach ($Item in $Tracked) {
    
     $Key = Get-ChildItem $Item.PsPath -Recurse | Where-Object { $_ | Get-ItemProperty -Include "Path*" }
     $PathCount = ($Key.Property -Match "Path\d+").Count
        
     ForEach ($K in $Key) {
    
         $Path = $K.Property | Where-Object { $_ -Match "Path\d+" }
         $Count = $Path.Count
            
         ForEach ($P in $Path) {
    
             $Value = $K.GetValue($P)
    
             If ($Value -Match "$('WWP%20AlwaysOn%20VPN')$") {
    
                 $K | Remove-ItemProperty -Name $P
                    
                 $Count--
    
             }
    
         }
            
         $K | Set-ItemProperty -Name Count -Value $Count
    
     }
    
 }
    
 $Path = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles\'
 $Key = Get-Childitem -Path $Path | Where-Object { (Get-ItemPropertyValue $_.PsPath -Name Description) -eq 'WWP AlwaysOn VPN' }
    
 If ($Key) {
    
     $Key | Remove-Item
    
 }
    
 Else {
    
     Write-Verbose "No profiles found matching WWP AlwaysOn VPN in the network list."
    
 }
    
 $Path = 'HKLM:\System\CurrentControlSet\Services\RasMan\Config\'
 $Name = 'AutoTriggerDisabledProfilesList'
    
    
 Try {
    
     [string[]]$Current = Get-ItemPropertyValue -Path $Path -Name $Name -ErrorAction Stop
    
 }
    
 Catch {
    
     Write-Verbose "$Name does not exist under $Path. No action required."
    
 }
    
 If ($Current) {
    
     $List = [Ordered]@{}
     $Current | ForEach-Object { $List.Add("$($_.ToLower())", $_) }
    
     If ($List.Contains("WWP AlwaysOn VPN")) {
    
         $List.Remove("WWP AlwaysOn VPN")
         Set-ItemProperty -Path $Path -Name $Name -Value $List.Values
    
     }
       
 }
    
 Else {
    
     Write-Verbose "No profiles found matching WWP AlwaysOn VPN."
    
 }
 Stop-Transcript
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

MotoX80 avatar image
0 Votes"
MotoX80 answered

Your code is assuming that Get-CimInstance is going to return something. If you have already uninstalled the VPN, then there won't be anything returned, and yes you are going to get an error. At the least you need to check to see to see that you have an object to delete.

Going back to Rich's recommendation, forget about your script and just test to see what instances you get back.

Maybe like this.

 $servers =@('server01','server02','server03')
    
 $sb = {
     "Executing on {0}" -f $env:COMPUTERNAME
     $cimStuff = Get-CimInstance -Namespace 'root\cimv2\mdm\dmmap' -ClassName 'MDM_VPNv2_01'
     "I found {0} instances." -f $cimStuff.count
     if ($cimStuff.count -gt 0) {
         # Here is where can put the code to process each instance. 
         $cimStuff | Format-List -Property *
     }
 }
    
 foreach ($server in $servers) {
     Invoke-Command -ComputerName $server -scriptblock $sb
 }

If you encounter a PC where the above script does not find any instances, but you believe that this machine should have an instance, then RDP to the machine and just run the single command locally. That will verify the local vs remote question.

 Get-CimInstance -Namespace 'root\cimv2\mdm\dmmap' -ClassName 'MDM_VPNv2_01'

Note that I do not have any way to test this code.

If you can't get the WQL wildcard correct, then let get-ciminstance return all instances and then use an IF statement or Where-Object to select the instance that you want to remove.




5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.