WMIMethodException with .InstallProductKey - windows

First off, this is my first post, so if I incorrectly posted this in the wrong location, please let me know.
So, what we're trying to accomplish is building a powershell script that we can throw on our workstation image so that once our Windows 10 boxes are done imaging, that we can click on a powershell script, have it pull the key from the BIOS, and automagically activate it. That being said, here is the script that we've put together from various sources.
(Get-WmiObject -query ‘select * from SoftwareLicensingService’).OA3xOriginalProductKey | out-file c:\license.txt
$computer = gc env:computername
$key = get-content c:\license.txt
$service = get-wmiObject -query “select * from SoftwareLicensingService” -computername $computer
$service.InstallProductKey($key) <--------THIS IS WHERE IT FAILS
$service.RefreshLicenseStatus()
We start running into the issues on the line $service.InstallProductKey($key). It seems, that no matter how we try to invoke that, it will consistently fail with the error "Exception calling "InstallProductKey"". I've even replaced the variable ($key) with the specific activation key, and it STILL fails with the same error.
The reason we have it outputting to a license txt file part way through is so that we can verify that the command is indeed pulling the product key (which it is).
At this point, I'm not sure where to go. It seems that people have tried to do this before, however, nobody has really wrapped up their posting with what worked and/or what didn't. I can't imagine that this is impossible, but I'm also not fond of wasting anymore time than needed, so anybody that has any insight into this issue, I'd be very grateful.
We've gotten it to work on two machines that were previously activated, and later deactivated, but on new machines that have been freshly imaged, and have yet to be activated, it will fail every time.

Two things as per my observation:
(Get-WmiObject -query ‘select * from SoftwareLicensingService’).OA3xOriginalProductKey | out-file c:\license.txt
I don't think that it is returning any value to your license.txt.
If yes, then I would like you to see if there is any space before and after the license key. You can use trim during getting the content from the file.
Second thing, when you are getting the content from the file make sure it is not separating into multiple lines. In that case, you have to cast it as string like [String]$key or you can call toString() method for this.
One more important thing is to refresh after the installation.
$service.RefreshLicenseStatus()
Note: Make sure you are running the shell in elevated mode.
Alternative: Try Hardcoding the values and see the result
$key = "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX" # hardcode the key
$computer= "Computer01" # Hardcode the computer
$service = get-wmiObject -query "select * from SoftwareLicensingService" -computername $computer
$service.InstallProductKey($key)
$service.RefreshLicenseStatus()
For further thing ,please post the exact error.
Hope it helps...!!!

Found out that the key from Get-WmiObject has whitespace on the end. The original command will work if a .Trim() is added. Also not running as administrator will result in the same error.
(Get-WmiObject -query ‘select * from SoftwareLicensingService’).OA3xOriginalProductKey | out-file c:\license.txt
$computer = gc env:computername
$key = (get-content c:\license.txt).Trim() #trim here
$service = get-wmiObject -query “select * from SoftwareLicensingService” -computername $computer
$service.InstallProductKey($key)
$service.RefreshLicenseStatus()

Related

How to get full name from domain name

So a while back, I managed to make a bat file that would let me enter in somone's username.
Then, it would search the domain for the full name and I could use that for other work. The bat I used would spit out JUST the fullname and put it in a variable.I know I can use the net user /domain $username command, but that doesn't let you single out a result, as far as I'm aware
Unfortunately, I lost it and I can even fine the tutorial I used to help me with it. Does anyone know how this might be done? I did it a few years back on a windows 7 machine, I'm not sure if that changes anything.
Powershell is a much better option for pulling AD info and exporting it. Using the PS AD Module you could do something similar to Get-ADUser -filter $username -properties Name | Select-Object Name From here you could store this info in a variable or write it to a file etc. I will also link to the AD Module documentation for reference on Get-ADUser
If your variable $username is the SamAccountName for the user, just do PowerShell:
$user = Get-ADUser -Filter "SamAccountName -eq '$username'" -Properties DisplayName
You now have an object with these user properties: DistinguishedName, Enabled, GivenName, Name, ObjectClass, ObjectGUID, SamAccountName, SID, Surname, UserPrincipalName, DisplayName
Only DisplayName needs to be asked for, all other properties are returned by default using Get-ADUser
So if you want just the DisplayName ('FullName' as you call it), just return that:
$fullName = (Get-ADUser -Filter "SamAccountName -eq '$username'" -Properties DisplayName).DisplayName

How to get only the uptime of the server on Powershell?

I have the following code, It's work when I use directly within powershell:
Get-WmiObject win32_operatingsystem | select #{LABEL=’LastBootUpTime’;EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)
And it returns:
LastBootUpTime
--------------
14/09/2019 10:41:50
But when I use the command within a Powershell script .ps1 with invoke-command the output returns more informations:
LastBootUpTime PSComputerName RunspaceId
-------------- -------------- ----------
9/14/2019 10:41:50 AM 192.168.0.20 af08d2d8-c4f1-4f85-9d6c-e3f4ffe475c6
Why this happen?
If possible, I'd like without the header LastBootUpTime too.
Invoke-Command will always return additional information, in this case where the command was run and the runspace id. You can always get results into a variable and simply print out the property you want.E.g.
$result = invoke-command {your-command}
$result.LastBootUpTime
or for short
(invoke-command {your-command}).LastBootupTime
Note that when you are using wmi, you do not need to necessarily use invoke-command, you can also directly pass -computer parameter to it to run the command against a remote computer:
Get-WmiObject win32_operatingsystem -computer "remote_computer_name"
Since you're ultimately only interested in the (transformed) property value, there's no need to use Select-Object (whose alias is select) at all - use ForEach-Object instead:
Get-WmiObject Win32_OperatingSystem |
ForEach-Object { $_.ConvertToDateTime($_.LastBootUpTime) }
Note: The extra properties you saw, added by a remote Invoke-Command call with a -ComputerName argument (described below), are still technically present on the result, but they won't display.
That said, the WMI cmdlets were deprecated in PowerShell version 3. Using Get-CimInstance in lieu of Get-WmiObject actually makes the .ConvertToDateTime() call unnecessary (the .LastBootUpTime now directly contains a [datetime] instance), in which case you can simply use Select-Object's -ExpandProperty parameter in order to return the property value only (rather than a [pscustomobject] instance with the requested property):
Get-CimInstance CIM_OperatingSystem | Select-Object -ExpandProperty LastBootUpTime
Note: Get-CimInstance directly supports a -ComputerName argument, so you don't need Invoke-Command -ComputerName for the invocation; unlike the firewall-unfriendly DCOM protocol that the WMI cmdlets use, the CIM cmdlets use the same, firewall-friendly transport as PowerShell remoting.
Or, more succinctly and efficiently, especially in a case such as this where the command returns only a single object, use direct property access:
(Get-CimInstance CIM_OperatingSystem).LastBootUpTime
This answer contrasts the pros and cons of these two approaches and shows other alternatives.
As for what you tried, which generally relates to:
Managing the origin properties automatically added by remote operations:
In remoting scenarios, PowerShell decorates the objects returned with additional properties that provide origin information. These properties are (mostly) of type NoteProperty and are added:
when PowerShell remoting is involved - such as via Invoke-Command -ComputerName in your case.
when CIM cmdlets such as Get-CimInstance are directly used remotely, such as with the -ComputerName parameter.
These properties are:
.PSComputerName (the name of the remote computer on which the code was executed)
Note: On objects returned from remote CIM calls, .PSComputerName appears as a regular property (type Property), not a NoteProperty.
The associated hidden .PSShowComputerName property, which defaults to $true, which explains why you saw a PSComputerName column in the display output.
If you capture the objects before printing them to the screen, you can set the property to $false on them, in which case their .PSComputerName property won't show (but will still be there) - however, the .RunspaceId property may - situationally - still show, and would have to be explicitly excluded - see below.
PowerShell remoting only (not remote CIM calls): .RunspaceId (the ID of the remote runspace)
To exclude these from local display / presence on the object, use the following techniques:
If you're only interested in select properties, make the Select-Object call locally, which, by virtue of locally constructing new [pscustomobject] instances with the properties of interest only, implicitly excludes the remoting-added properties:
Invoke-Command -ComputerName ... { ... } |
Select-Object Name, LastBootUpTime # LOCAL call to Select-Object
If you're interested in all properties except the remoting-added ones, use Select-Object -ExcludeProperty to eliminate them explicitly:
# Get remote output, then locally exclude the remoting-added properties.
Invoke-Command -ComputerName ... { ... } |
Select-Object * -ExcludeProperty PSComputerName, PSShowComputerName, RunSpaceId
Note: Select-Object generally returns [pscustomobject] instances whose properties are static copies of the input objects and which lack the input type's methods.
I found one way! if someone to need here is:
Get-WmiObject win32_operatingsystem | select #{LABEL=’LastBootUpTime’;EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}|Select-Object -ExpandProperty lastbootuptime
Here is how I used (I'm creating a report in HTML for my database)
write-output "<p> Horario do Ultimo boot: $(Get-WmiObject win32_operatingsystem | select #{LABEL=’LastBootUpTime’;EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}|Select-Object -ExpandProperty lastbootuptime)</p>"
The output was (in my language and region):
Horario do Ultimo boot: 09/14/2019 10:41:50

How to format CCM_UserAffinity output to tyoe Microsoft.PowerShell.Commands.LocalPrincipal

I am trying to create a deployment script which adds freshly deployed workstation primary users to local admin group. I utilized CCM_userAffinity class to obtain username, however - Add-LocalGroupMember does not accept its output.
Ive tried creating task sequence variable to pass into powershell script which adds to group with no success either. Preferably the solution would be integrated within deployment TS, however due to no success i have reverted to ps package deployment.
$computer = "LocalHost"
$namespace = "root\ccm\Policy\Machine"
$query = "ConsoleUser"
$PrimaryUser = Get-WmiObject -class CCM_UserAffinity -computername $computer -namespace $namespace | select-object $query | format-wide
i expected the output from -class CCM_UserAffinity to be accepted by Add-LocalGroupMember, however i get this instead -
Add-LocalGroupMember : Cannot bind parameter 'Member'. Cannot convert the "Microsoft.PowerShell.Commands.Internal.Format.FormatStartData" value of type
"Microsoft.PowerShell.Commands.Internal.Format.FormatStartData" to type "Microsoft.PowerShell.Commands.LocalPrincipal".
As you plan on using the value you retrieve and not displaying it there is no need to use something like "format-wide" which only makes the output human readable and is the reason for your FormatStartData datatype.
You can just use :
$PrimaryUser = (Get-WmiObject -class CCM_UserAffinity -computername $computer -namespace $namespace).ConsoleUser
which returns a string and that is taken by the -Member argument of Add-LocalGroupMember
One thing to keep in mind is that in theory there can be more than one ConsoleUser per machine. So the ConsoleUser might be an Array or not. If you can guarantee that there is always only one user in your environment per machine (at the point where the ts runs) you can just use it as is. Otherwise you would have to specify which user you want to use and I can of course not tell you what a good rule for that for your environment would be.
Also I hope you checked that the WMI class CCM_UserAffinity is already populated at the stage where you want to run this script, I could not tell you if this is the case.

Detection script for windows hotfixes

So we have recently had issues with the KB971033 update within our network and i have managed to get a working script for removing it and reactivating windows, however when trying to get a detection script working to assure it only runs on effected computers i cant get it to correctly output true or false when testing against installed KBs.
So far this is what im running. No matter what i do it will output false. Anything obvious i am missing?
if ((get-hotfix).hotfixid -eq "KB971033") {$true} else {$false}
(get-hotfix).hotfixid returns an array, so you should not compare that with -eq.
This ought to do it:
((Get-HotFix | Select-Object -ExpandProperty HotFixID) -contains 'KB971033')
or for short:
(((Get-HotFix).HotFixID) -contains 'KB971033')
It's IMO quite inefficient to sieve through all Hotfixes when testing a distinct one.
if (Get-Hotfix -ID KB971033 -EA 0) {$true} else {$false}
-EA 0 is an abbreviation for -ErrorAction SilentlyContinue
Maybe Try
if ($(get-hotfix).hotfixid -eq "KB971033") {$true} else {$false}
The "$" is going to make "Get-Hotfix" result into an object with member ".hotfixID".
In my Windows Server 2016 Environment your Code works fine...maybe the Hotfix is not installed or not listed with 'get-hotfix'
Otherwise you can try this:
$HotfixID= "KB971033"
IF((get-hotfix).hotfixid | ?{ $_ -eq $HotfixID}){$true} else {$false}
It works also on Remote Computer:
(get-hotfix).hotfixid -ComputerName "***SomeDNSName / FQDN***"

PowerShell - WMI returns incorrect profile last use time

I use Get-WMIObject with the Win32_UserProfile class and LastUseTime property to filter a Win7/Server2008R2 profile deletion script, and recently noticed that the date returned is not matching any of the applicable fields in Windows (Date Accessed, Date Modified, or Date Last Saved).
For example when checking a profile that was last accessed on 5/1/2015 at 1:54 PM per Windows, PowerShell returns the following:
Get-WmiObject -Class Win32_UserProfile -ComputerName TESTCOMPUTER |
Where{$_.LocalPath -Like "*TESTUSER*"} |
ForEach-Object{
Write-Host $_.LastUseTime
Write-Host $_.ConvertToDateTime($_.LastUseTime)}
20150502112839.854000+000
5/2/2015 4:28:39 AM
What am I missing? I though it might have something to do with time zone, but the minute difference throws that off for me. I've spent considerable time searching through Google, but haven't had any luck. Any insight you can provide would be greatly appreciated!
If you run a program under the credentials of TESTUSER but without loading the environment this can happen. Both DateTimes aren't very accurate.
What do you mean with "last accessed? Logon, Logoff, ...?

Resources