Tigger installation in software center using SCCM 2012 & Powershell - powershell

I would need some directions where to look for an solution.
I need to trigger install on a few programs in SCCM 2012 software center on Windows 10 clients through Powershell. I guess some of those are User Based Packages(not sure about this at all) but when i run the following.
$Application = Get-CimInstance -Namespace "root\ccm\clientSDK" -ClassName CCM_application
$Application
I get some of the programs, but many of them is missing.
If I open software center and click install on any programs manually it will then appear when I use the command above.
I've been reading about CCM-Application I found something about you only get device based packages.
I cannot access any servers so accessing CMApplicationCatalog is not possible. Like in the links below.
Trigger available application catalog
install-user-based-application-or-packages
In my case using CCM_Application Client WMI Class seems to be hard, I've not found any other solutions then creating New-WebServiceProxy to do this, and I´m not allowed/have permissions to.
I've tried to get the needed parameters for one of the programs that don't appear with the code above from a computer I've installed it on through Software Center.
When I try to run it with the needed parameters on an new installed computer.
$Program = #{"EnforcePreference"=[UInt32]0
"Id" = [String]"ScopeId_MyScopeID, will leave this out for company rules."
"IsMachineTarget" = [Boolean]$false
"IsRebootIfNeeded" = [Boolean]$false
"Priority" = [String]"High"
"Revision" = [String]"7"
}
Invoke-CimMethod -Namespace Root\ccm\clientSDK -ClassName CCM_application -MethodName "Install" -Arguments $Program
I then get error below
Invoke-CimMethod : Not found At line:1 char:1
+ Invoke-CimMethod -Namespace Root\ccm\clientSDK -ClassName CCM_applica ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Root\ccm\clientSDK:CCM_application:String) [Invoke-CimMethod],
CimException
+ FullyQualifiedErrorId : HRESULT 0x80041002,Microsoft.Management.Infrastructure.CimCmdlets.InvokeCimMethodCommand
Maybe I am doing something wrong or what I am trying to do is not possible.
I've also tried uiresource.uiresourcemgr but It returns empty.
I used this much in SCCM 2007 and it worked great. But now it's not giving me anything.
$RunAdvProg = New-Object -ComObject uiresource.uiresourcemgr
$RunAdvProg.GetAvailableApplications();
With this said, Is there anyway way around this or does it exist another function/Method from another class or DLL?

Related

How do I attach a debugger to a process using Invoke-WmiMethod?

I have a process already running on a remote computer and I'd like to attach a debugger to it. I would like to use Invoke-WMIMethod so that when I disconnect from that remote session, the debugger will remain attached to the process in the background.
So far I have:
$Qry = "Select * from Win32_Process where ProcessID like $ID"
$CimIO = Get-WMIObject -Query $Qry
Invoke-WMIMethod -InputObject $CimIO -Class Win32_Process -Name AttachDebugger -AsJob
And I'm getting the following error:
Invoke-WmiMethod : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:1
+ Invoke-WmiMethod -InputObject $CimIO -Class Win32_process -Name Attac ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-WmiMethod], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.InvokeWmiMethod
Am I on the right track? When I try other Methods from Win32_Process (like GetOwner), I get the same error message. What's going on here?
EDIT:
Perhaps I am going about this all wrong: My understanding was that the query would return a pointer to the running process which could then be used as an input object to Invoke-WmiMethod.
Debug-Process requires that a separate debugger already be downloaded and installed on the machine whereas "AttachDebugger" as a method is installed by default (at least I'm assuming since it was on a fresh copy of Windows 10). The reason why I want to use built-in methods only is because I would like this script to be usable in a production environment where I will not have control over what's installed on the computers.
I found the method by running the script found here which found the method residing in Win32_Process. I went with Invoke-WmiMethod because when -AsJob is invoked, it creates a job locally on the remote computer where the process I'm sending to a debugger resides.
Thank you for the help and I'm sorry for the confusion: this is part of my first powershell script.
The use case is follows:
In a SIEM environment the user sees a program on the network acting suspicious. The user then remotely logs into the victim computer and freezes the suspicious thread by sending it to a debugger. The user then logs out and will get back to analyzing the thread later. The thread will remain frozen until that time.
I've personally never tried or had a reason to try this use case.
However, AsJob is used for long running tasks. You are only querying to get a listing of a single Process ID and once that listing is provided, the job is done / stopped / completed.
There is nothing to attach to. Lastly, where are you getting this method --- AttachDebugger -- from?
There is no such method using the Get-WmiObject or Invoke-WmiMethod cmdlet parameters. That is what the error is about
Why are you not just using the built-in cmdlet for this effort.
# get function / cmdlet details
(Get-Command -Name Debug-Process).Parameters
Get-help -Name Debug-Process -Examples
Get-help -Name Debug-Process -Full
Get-help -Name Debug-Process -Online

WMI BatteryStatus from Windows Server 2012 using Powershell

I'm writing a Powershell script to do some server management when we have a power outage. Presently the script is using the WMI Win32)Battery class to see if BatteryStatus is a 1 (discharging) or a 2 (unknown (on A/C)) but I am not sure this is the best method. There are several statuses that could be true at the same time.
For example, the battery could be Discharging (1) and Partially Charged (11) or On AC (2) but Critical (5) or charging (6) or Partially Charged (11). This doesn't make sense to me. Is BatteryStatus reliable for my intended purpose? How does Windows determine which status is returned? In my testing I've not seen anything other than statuses of 1 or 2.
The documentation for Win32_Battery indicates Availability might also be an indicator that we are on battery. Is that a better way to go, maybe a combination of BatteryStatus and Availability?
In my search for answers I came across what looks like the perfect answer, using "PowerOnline" from the undocumented BatteryStatus class in the root\wmi namespace. This works great from my laptop but I get the following error when trying to access it from our Windows 2012 server:
PS C:\Windows\system32> gwmi -Class batterystatus -Namespace root\wmi
gwmi : Invalid class "batterystatus"
At line:1 char:1
+ gwmi -Class batterystatus -Namespace root\wmi
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidType: (:) [Get-WmiObject], ManagementException
+ FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Is this class not available on servers?
So using WMI, what is the most reliable way to know if I am on UPS battery or AC Power?

Early filtering within the root\ccm\cliensdk namespace

I recently wrote a script that updates registry values on remote desktops after checking, for instance, that a certain application, MyApp, is properly installed.
The aforementioned application is installed/deployed by SCCM (2012, not R2 for the moment).
In the process of optimizing the script, I wanted to change the test of the install state of MyApp (from late to early filtering).
So far, no luck and so far, no explanation either.
I can't properly understand why it seems not possible to do some early filtering with the following command :
gwmi -ComputerName myserver -Namespace root\ccm\clientsdk -query "select * from ccm_application where Fullname='MyApp'"
Of course, nor can we use :
gwmi -ComputerName myserver -Namespace root\ccm\clientsdk -class ccm_application -filter "Fullname='MyApp'"
Late filtering, of course, works but I wanted (and expected) early filtering to work, especially since I am checking the Install state of an app for quite a lot of remote desktops.
Of course, I do know that I could (can) use SCCM for that purpose (executing a script only if ...) but that still does not explain why I can't do early filtering.
Whenever I try to query that class with my installation while specifying either properties or a filter, I get the error "Provider is not capable of the attempted operation". It doesn't matter if I use Get-WmiObject or Get-CimInstance.
I get the same error when I run this:
PS C:\> WMIC.EXE /NAMESPACE:\\root\ccm\clientsdk PATH ccm_application GET FullName
Node - <SERVERNAME>
ERROR:
Description = Provider is not capable of the attempted operation
PS C:\> wmic /NAMESPACE:\\root\ccm\clientsdk PATH ccm_application WHERE "FullName='Java 32-bit'"
Node - <SERVERNAME>
ERROR:
Description = Provider is not capable of the attempted operation
Although this works just fine:
WMIC.EXE /NAMESPACE:\\root\ccm\clientsdk PATH ccm_application
Seems like a limitation of the provider then, not a problem with your code. -Filter and -Property don't work by design.
Note that I am using 2012 R2 SP1 (5.00.8239.1000), so this may not perfectly apply. However, it seems unlikely that they would remove the functionality from the provider moving from 2012 to 2012 R2.

Delete a SCCM collection from the command-line

When using the UI (SCCM 2012), to be able to delete a collection (let's say CollA), you need first to ensure it is not linked by any rule to another (let's say CollB, etc..) such as :
CollB includes CollA
CollC excludes CollA
When dealing with a lot of collections, deleting a collection can be time-consuming. For that reason, I have created a script,
usable remotely to avoid the need to connect through RDP
which checks that CollA has no rule left (even if that is not a problem if we want to delete CollA)
which checks if CollA is "linked" to other collections (include or exclude rules)
which deletes any rule found (between CollB and CollA, between CollC and CollA)
I'm stuck now for I can not find a way to delete CollA.
For authentication matters and for remote purpose, I use a lot Powershell and WMI.
$CollA=Get-WmiObject -computername servername -namespace root\sms\site_111 -credential $cred -query "select * from SMS_Collection where Name='Tartempion'"
$CollA.get()
At that point, I found a method Delete(), which when I try to use it, it gives me :
Exception calling "Delete" with "0" argument(s): "Generic failure "
At line:1 char:1
+ $coll.delete()
+ ~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
If that is the method that I should use, what are the arguments to be passed ?
EDIT 1
As pointed by theMadTechnician, the SCCM collection, once retrieved in $CollA, a System.Management.ManagementObject.
I should, as described in the MSDN pages, be able to use the following method :
Delete() > produces the error mentioned above
Delete(DeleteOptions) > I can not find the specs for the required options
Delete(ManagementOperationObserver) > I can not find the specs for the required options
To ensure I properly understood the MSDN page regarding *.Delete(), i tried (successfully) the following:
PS C:\> Set-WmiInstance -Class win32_environment -argument #{Name="testvar";VariableValue="testvalue";UserName="<SYSTEM>"}
PS C:\> (gwmi -class win32_environment -filter "Name='testvar'").gettype()
PS C:\> (gwmi -class win32_environment -filter "Name='testvar'").delete()
EDIT 2
The fact is that when deleting a SCCM collection through the console, the collection is not the only thing removed from the inventory : the assignments for instance, are too removed. It reminds of the CASCADE switch when dealing with MySQL or ORACLE. Maybe what I'm trying to do is not possible
without using the console
without using the SCCM cmdlets
If it can not be done that way, I just need to be sure.
EDIT 3
After some maturing, I am starting to wonder if it could be a authorization matter. I mean, the account I am using with the "-credential" switch or when connecting to the server, to open a SCCM console, allows me to create/update/delete collection but, for instance, it does not allow me to delete a device. I would expect the error message to be different but who knows ?
More or less about the same matter (sorry for the digression), trying to remove a device from the commandline, I found this and I have the same error message (see above). If it works for others and not me, could it be authorization related ?
EDIT 4
I requested a service account with more "privileges" than I have with my technical account.
I tested and I have the same error. I am putting aside the authorization hypothesis.
I just tested this in our SCCM 2012 environment by using the following command:
$CollA=Get-WmiObject -computername servername -namespace root\sms\site_111 -query "select * from SMS_Collection where Name='Tartempion'"
Basically, take the -credential out of there. Does it work now?
You could potentially setup a script like so:
#if the delete command fails...
if(!($?))
{
$limitedcollectionName = $colla.LimitedCollectionName
$limitedcollection = Get-WmiObject -computername servername -namespace root\sms\site_111 -query "select * from SMS_Collection where Name=`'$limitedcollectionname`'"
$limitedcollectionname.delete()
}

Powershell doesn't have access to a network share

I use powershell to check if the ports are opened on my computers. I got 8 windows 2008 R2 machines and I run the following script :
$localhost = get-content env:computername
foreach($port in get-content "\\computer1\txtfiles\ports.txt")
{
foreach ($hostname in get-content "\\compiuter1\txtfiles\servers.txt")
{
try {
$sock = new-object System.Net.Sockets.Socket -ArgumentList $([System.Net.Sockets.AddressFamily]::InterNetwork),$([System.Net.Sockets.SocketType]::Stream),$([System.Net.Sockets.ProtocolType]::Tcp)
$sock.Connect($hostname,$Port)
$output = $localhost+","+$hostname+","+$port+","+$sock.Connected
$output
$sock.Close()
}
catch {
$output = $localhost+","+$hostname+","+$port+","+$sock.Connected
$output
}
}
}
And I run this script on the 8 computer from computer1 using :
Invoke-Command -ComputerName computer1,computer2 -FilePath F:\scripts\port-test.ps1
On the first computer (computer1- the machine that I execute the script from ) I got an output but on the computer2 I got :
Cannot find path '\\computer1\txtfiles' because it does not exist.
+ CategoryInfo : ObjectNotFound: (\\computer1\txt
files:String) [Set-Location], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.SetLocationCommand
Why isn't Powershell seeing network share? How can I fix it?
Sounds like the double hop issue - http://blogs.technet.com/b/askds/archive/2008/06/13/understanding-kerberos-double-hop.aspx - basically you are remoting to one machine and then trying to access another machine. your kerberos token is seen as invalid as there's a machine in between the original and the destination.
What OS are you using (the source and the destination OS is relevant for CredSSP)? If it is Windows 2008 or Windows 7 all the way through and the issue is double hop you may be able to us CredSSP to avoid it - http://www.ravichaganti.com/blog/?p=1230
If it's not a problem with access control, then consider a similar problem I faced when copying files over servers with this error:
Cannot find path '\\computer1\d$\path' because it does not exist.
It works after adding Microsoft.PowerShell.Core\FileSystem:: in front of file name:
copy-item "Microsoft.PowerShell.Core\FileSystem::\\computer1\d$\path\installer.msi" "Microsoft.PowerShell.Core\FileSystem::\\computer2\d$\path\installer.msi"
Edit:
I was able to reproduce this and it can be the double-hop issue. I solved it as per the instructions here:
http://blogs.msdn.com/b/clustering/archive/2009/06/25/9803001.aspx
( or the link that Matt had given)
Make sure computer2 and other computers are able to see that share. If the other machines are not able to see the share in the first place, Powershell cannot do anything.
For a simple check do:
Invoke-Command -computer computer2 -script {dir \\computer1\txtfiles}