Invoke-WmiMethod -ArgumentList not accepting variables? - powershell

So I am very new to Powershell and I am almost certain that what I am doing is not the most efficient way of going about it. But I really want to understand why what I am doing is not working.
I am trying to trigger Configuration Manager client actions using Powershell by running the following code:
Invoke-Command -ComputerName $ComputerName -ScriptBlock {
Invoke-WmiMethod -Namespace "Root\CCM" -Class SMS_Client -Name
TriggerSchedule -ArgumentList "{00000000-0000-0000-0000-000000000042}"
}
This runs fine. But I wanted to be able to call a variable or something where all of those long codes are instead of having to put those in each time I want to change the client action. So here is where I started playing around and was unable to get anything to work.
$ApplicationDeployment = '"{00000000-0000-0000-0000000000000042}"'
Invoke-Command -ComputerName $ComputerName -ScriptBlock {
Invoke-WmiMethod -Namespace "Root\CCM" -Class SMS_Client -Name
TriggerSchedule -ArgumentList $ApplicationDeployment
}
This gives me an error. I also tried the following:
$hash = #{"ApplicationDeployment" = "{00000000-0000-0000-0000-000000000042}"}
Invoke-Command -ComputerName $ComputerName -ScriptBlock {
Invoke-WmiMethod -Namespace "Root\CCM" -Class SMS_Client -Name
TriggerSchedule -ArgumentList $hash.'ApplicationDeployment'
}
and finally
$Object = #{ApplicationDeployment = '{00000000-0000-0000-0000-000000000042}'}
Invoke-Command -ComputerName $ComputerName -ScriptBlock {
Invoke-WmiMethod -Namespace "Root\CCM" -Class SMS_Client -Name
TriggerSchedule -ArgumentList $Object.ApplicationDeployment
}
I have also tried
$($ApplicationDeployment).ArgumentList
But this gives the same error as everything else.
I would really appreciate an explanation as to why this isn't working... Thank you in advance.

Your issue is that remote machine doesn't have your variable initialized locally. You need to pass it to remote machine when executing script.
To do this, replace $Object.ApplicationDeployment with $Using:Object.ApplicationDeployment as in code below:
$Object = #{ApplicationDeployment = '{00000000-0000-0000-0000-000000000042}'}
Invoke-Command -ComputerName $ComputerName -ScriptBlock {
Invoke-WmiMethod -Namespace "Root\CCM" -Class SMS_Client -Name TriggerSchedule -ArgumentList $Using:Object.ApplicationDeployment
}

Related

PowerShell cmdlet get-service returns different results remotely

If I run the following command remotely from a server it returns a list of 37 services.
get-service -computername <computer name>
If I connect to the remote host and run the same command through a remote session it returns a list of 161 services.
new-pssession <computer-mame>
enter-pssession <session id>
get-service
can anybody point to me to an explanation please?
I cannot reproduce your result. Try the following snippets:
$ComputerName = 'ComputerName'
$ServiceList = Get-Service -ComputerName $ComputerName
$ServiceList.count
$PSSession = New-PSSession -ComputerName $ComputerName
Invoke-Command -Session $PSSession -ScriptBlock {
$ServiceList = Get-Service
$ServiceList.count
}
Try Invoking the command on the remote computer and storing the results in a Variable
$remoteCommputer = "RemoteComputerName"
$GetServiceData = (invoke-command -ComputerName $remoteCommputer -ScriptBlock { get-service })

How to get local computer name after New-PSSession -Computername?

I am getting the below error, please advise how to fix this error for null-valued expression
You cannnot call a method on a null-valued expression
+CategoryInfo : InvalidOoperation: (:)[], RuntimeException
+FullyQualifiedErrorId: InvokeMethodonNull
+PSComputerName: DC1
Code below
function myfunction (){
$remoteserver = 'DC1'
$Session = New-PSSession -Computername $remoteserver -Credential $Cred
Import-Module ActiveDirectory
$local= $env:COMPUTERNAME
Invoke-Command -ComputerName $remoteserver -Credential $cred -ScriptBlock
{$using:local
if($local.substring(5,3) -imatch "Sys") {
Get-ADComputer $local | Move-ADObject -Targetpath "ou=PRD,ou=Servers,dc=com,dc=Companycorp,dc=net"}
}
} #end function
Invoke-Command -ComputerName $remoteserver -ScriptBlock ${Function:myFunction}
What you're looking for is the $using: scope. If you define variables that you want to use in your remote execution, you need to access them like:
$PC = $env:ComputerName
Invoke-Command -Computer DC01 -ScriptBlock { $using:PC <# logic #> }
If you mean you want to remote into DC01 to run commands against localhost, you're going to run into the second-hop problem due to Kerberos.
Update: Your new example looks pretty convoluted. Here's an example that should work:
$MyPC = $env:ComputerName
$Session = New-PSSession -Credential (Get-Credential) -ComputerName 'DC1'
Invoke-Command -Session $Session -ScriptBlock {
Import-Module -Name 'ActiveDirectory'
$PC = $using:MyPC
If ($PC.Substring(5,3) -eq 'sys')
{
Get-ADComputer -Identity $PC |
Move-ADObject -TargetPath 'ou=PRD,ou=Servers,dc=com,dc=Companycorp,dc=net'
}
}
What I think you're asking is 'how do I open a session on a remote pc, but then still run commands on my local PC'. If that's so, then let's walk through it.
First, we can open a remote connection to another computer in PowerShell by creating a new PSSession, as you're doing here:
$session = New-PSSession -Computername DC01 -Credential $cred
You can then either step into the remote computer wholly using Enter-PSSession, or just send individual commands to the remote computer using:
Invoke-Command -ScriptBlock {#Commands to run on the remote PC}`
-Session $session
Once you enter the remote PC, you can return to your own PC using the Exit-PSSession command.
#Enter Remote PC
Enter-PSSession $session
DC01> hostname
*DC01*
#Step out of Remote PC
Exit-PSSession
PS> hostname
*YOURPCNAME*
If this isn't what you want to do, let me know and we'll get you sorted.
You have to use Invoke-Command :
$session = New-PSSession -Computername DC01 -Credential $cred
Invoke-Command -Session $session -ScriptBlock {
$remoteComputerName = $env:computername
}

Powershell: Get-WmiObject cannot run asJob in loop

I want to sometimes check some info from our servers in domains. In this example, I am trying to remotely get windows versions (just one server, currently without loop):
$cr=Get-Credential "domain\adm_user"
$computer="serverA"
Invoke-Command { Get-WmiObject -Class Win32_OperatingSystem -Namespace root/cimv2 -Computer $computer -Credential $cr | Format-List -Property Name, OSArchitecture, SerialNumber} -AsJob -ComputerName .
Get-Job | Wait-Job
Get-Job | Receive-Job
Output:
Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
Seems, that scriptblock {} cannot see variable $computer.
When I replace variable -computer $computer to name of server, it is working.
For variable expansion inside Invoke-Command use a param block and specify arguments:
$computer = 'localhost'
Invoke-Command {param($computer) Get-WmiObject Win32_OperatingSystem -Computername $computer } -ArgumentList $computer
Working on PS v5.

Invoking remote powershell command not returning all results

I'm pretty new to powershell and I'm trying to invoke a remote powershell command to return the size of a drive but am having trouble.
If I run the below command directly on the server, then I get a result of 4.
import-module virtualmachinemanager
$checks = get-vm -Name DC1 | get-scvmcheckpoint
foreach ($disk in $checks){
$disk.virtualdiskdrives.virtualharddisks.size
}
I then try to run the command remotely using the below, but I don't get a result. The $checks variable contains a number of other values though.
$session = New-PSSession -ComputerName VM01 -ConfigurationName Microsoft.Powershell32 -Credential administrator
$checks = Invoke-Command -Session $session -ArgumentList VM01 -ScriptBlock {
import-module virtualmachinemanager
get-vm -Name DC1 | get-scvmcheckpoint
}
foreach ($disk in $checks){
$disk.virtualdiskdrives.virtualharddisks.size
}
The most likely issue here, (haven't tested the code on actual VMM server) is that objects returned from remote session are Serialized and De-serialized. Here is a reference How objects are sent to and from remote sessions.
To get around this, I would suggest doing all the processing on a remote machine and only return simple PS objects.
$session = New-PSSession -ComputerName VM01 -ConfigurationName Microsoft.Powershell32 -Credential administrator
$checks = Invoke-Command -Session $session -ArgumentList VM01 -ScriptBlock {
import-module virtualmachinemanager
$disks = get-vm -Name DC1 | get-scvmcheckpoint
foreach ($disk in $disks){
$disk.virtualdiskdrives.virtualharddisks.size
}
}
foreach ($disk in $checks){
write-host "Disk size = $disk"
}

Powershell - Check on Remote Process, if done continue

As part of a backup operation, I am running the 7zip command to compress a folder into a single .7z file. No problems there as I am using the InVoke-WMIMethod.
Example:
$zip = "cmd /c $irFolder\7za.exe a $somedirectory.7z $somedirectory"
"InVoke-WmiMethod -class Win32_process -name Create -ArgumentList $zip -ComputerName $remotehost"
My problem comes in as my script continues, the 7za.exe process hasn't completed. I am then attempting to copy the item off of the remote system and it is either incomplete or fails.
Can someone point me in the direction to figure out how to identify if the 7za.exe process is still running, wait until it is dead, then proceed with the rest of my script?
I can grasp pulling the process from the remote system via...
get-wmiobject -class Win32_Process -ComputerName $remotehost | Where-Object $_.ProcessName -eq "7za.exe"}
Not sure how to turn that into usable info for my issue.
Answer UPDATE: (thx to nudge by #dugas)
This will do it with some feedback for those that need it...
do {(Write-Host "Waiting..."),(Start-Sleep -Seconds 5)}
until ((Get-WMIobject -Class Win32_process -Filter "Name='7za.exe'" -ComputerName $target | where {$_.Name -eq "7za.exe"}).ProcessID -eq $null)
You can invoke the Wait-Process cmdlet on the remote computer with the Invoke-Command cmdlet. Example:
$process = Invoke-WmiMethod -Class Win32_Process -Name create -ArgumentList notepad -ComputerName RemoteComputer
Invoke-Command -ComputerName RemoteComputer -ScriptBlock { param($processId) Wait-Process -ProcessId $processId } -ArgumentList $process.ProcessId
Since you mentioned using Invoke-Command is not an option, another option is polling.
Example:
$process = Invoke-WmiMethod -Class Win32_Process -Name create -ArgumentList notepad -ComputerName hgodasvccr01
$processId = $process.ProcessId
$runningCheck = { Get-WmiObject -Class Win32_Process -Filter "ProcessId='$processId'" -ComputerName hgodasvccr01 -ErrorAction SilentlyContinue | ? { ($_.ProcessName -eq 'notepad.exe') } }
while ($null -ne (& $runningCheck))
{
Start-Sleep -m 250
}
Write-Host "Process: $processId is not longer running"
You should be able to do it with a do... while loop that just sleeps until the process is finished.
do {
"waiting"
start-sleep 10
} while (gwmi -class win32_process -ComputerName $remotehost | Where ProcessName -eq "7za.exe")