Powershell scripting Assistance *Windows Activation Status*

Experts Could use some scripting assistance

function Get-ActivationStatus {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [string]$DNSHostName = $Env:COMPUTERNAME
    )
    process {
        try {
            $wpa = Get-WmiObject SoftwareLicensingProduct -ComputerName $DNSHostName `
                -Filter "ApplicationID = '55c92734-d682-4d71-983e-d6ec3f16059f'" `
                -Property LicenseStatus -ErrorAction Stop
        }
        catch {
            $status = New-Object ComponentModel.Win32Exception ($_.Exception.ErrorCode)
            $wpa = $null    
        }
        $out = New-Object psobject -Property @{
            ComputerName = $DNSHostName;
            Status       = [string]::Empty;
        }
        if ($wpa) {
            :outer foreach ($item in $wpa) {
                switch ($item.LicenseStatus) {
                    0 {$out.Status = "Unlicensed"}
                    1 {$out.Status = "Licensed"; break outer}
                    2 {$out.Status = "Out-Of-Box Grace Period"; break outer}
                    3 {$out.Status = "Out-Of-Tolerance Grace Period"; break outer}
                    4 {$out.Status = "Non-Genuine Grace Period"; break outer}
                    5 {$out.Status = "Notification"; break outer}
                    6 {$out.Status = "Extended Grace"; break outer}
                    default {$out.Status = "Unknown value"}
                }
            }
        }
        else {$out.Status = $status.Message}
        $out
    }
}

#Get User Credentials
$cred = Get-Credential
<# $timer = (Get-Date -Format yyy-mm-dd-hhmm)

$HyperHostFileName = "c:\temp\" + $timer + "HyperVHostInfo.csv"
$HyperGuestFileName = "c:\temp\" + $timer + "HyperVGuestInfo.csv"
$HyperVFailoverFileName = "c:\temp\" + $timer + "HyperVFailoverInfo.csv" #>
$serverList = Get-ADComputer -Filter "Name -like '*K2*'" |Sort-Object -Property Name |Select-Object -ExpandProperty Name




#Get HyperV Guest Information
$HyperVGuestInfo = Invoke-Command -ComputerName $serverList -Credential $cred -ScriptBlock {
    $vMList = Get-VM |Select-Object Name -ExpandProperty Name
	Get-VM | Select-Object -Property `
		@{n='ComputerName';				e={$ENV:ComputerName}},
		VMName,
        State,
        @{n='License Status';				e={($vMList | Get-ActivationStatus)}}
      
} |
	Select-Object -Property * -ExcludeProperty PSComputerName, RunspaceId |
	Sort-Object -Property ComputerName, VMName
$HyperVGuestInfo | Out-GridView
<# write-host "Exported Hyper-V Guest Information to c:\Temp\"
$HyperVGuestInfo | Export-Csv -NoTypeInformation -Path $HyperGuestFileName #>

Open in new window


The License Status row is coming back completely blank, can someone please show me the error of my ways:

        @{n='License Status';                        e={($vMList | Get-ActivationStatus)}}
LVL 15
ITguy565Asked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

yo_beeDirector of Information TechnologyCommented:
Have you looked VAMT from MS?
https://docs.microsoft.com/en-us/windows/deployment/volume-activation/volume-activation-management-tool 
This is a GUI that will do what you are trying and it is much easier.
1
ITguy565Author Commented:
@Yo_bee

Thanks for the comment!

That is a very good suggestion, but I am really at this point looking to find out what was wrong with my script. A powershell script lets me query on a much more granular level than the VAMT GUI will allow. For instance, I am looking for only Virtual Machines on Specific HyperV Hosts.
0
ITguy565Author Commented:
There is something simple I am missing. If I test that function on machines that DO NOT sure powershell remoting then it works just fine..

For instance :

serverlist.txt
machine1
machine2
machine3
machine4

$serverlist = get-content c:\serverlist.txt

$serverlist | get-activationstatus

This will return the proper information for those workstations.

Once I add PSREMOTING into the equation and attempt to use the get-vm command everything falls apart.
0
Make Network Traffic Fast and Furious with SD-WAN

Software-defined WAN (SD-WAN) is a technology that determines the most effective way to route traffic to and from datacenter sites. Register for the webinar today to learn how your business can benefit from SD-WAN!

Philip ElderTechnical Architect - HA/Compute/StorageCommented:
Line 42: <# $timer = (Get-Date -Format yyy-mm-dd-hhmm)

Shouldn't that be yyyy-mm-dd-hhmm) ?

This is what comes out for me:
PS C:\WINDOWS\system32> Get-ActivationStatus

ComputerName Status
------------ ------
MyPCName Licensed

PS C:\WINDOWS\system32>

Open in new window

0
Philip ElderTechnical Architect - HA/Compute/StorageCommented:
My search foo really sucks right now but, Invoke-Command on a remote machine requires a change in PowerShell Execution policy on the destination/remote system IIRC?
0
ITguy565Author Commented:
@phillip


There is more to that script than just the function get-activationstatus


If you copy the script and save it as test1.ps1
execute the script after changing the $serverlist variable to something that works on your network.

Then you should come out with something like this.

image.png
0
Philip ElderTechnical Architect - HA/Compute/StorageCommented:
PowerShell is a challenge for me at best but, maybe it's this?
Script Variables
Shouldn't those variables have different IDs?

EDIT: And, if I'm not being helpful, my apologies for the waste of time. :)
0
ITguy565Author Commented:
The ComputerName Column contains the name of the HyperVisor
The VMName is right below it

The other line you reference is just taking a list of computers and sending it to get-activationstatus
0
ITguy565Author Commented:
This command will pull the output I need in that column but I need it for all of my VM's

((get-vm).name[1] |get-activationstatus).status
0
footechCommented:
The problem with your original is that the function definition for Get-ActivationStatus is only run on the local machine.  When you run Invoke-Command to run the commands on the remote machines, they have no idea what Get-ActivationStatus is.  So you have to include the function in the scriptblock to be run remotely.

$scriptblock = {
    function Get-ActivationStatus {
        [CmdletBinding()]
        param(
            [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
            [string]$DNSHostName = $Env:COMPUTERNAME
        )
        process {
            try {
                $wpa = Get-WmiObject SoftwareLicensingProduct -ComputerName $DNSHostName `
                    -Filter "ApplicationID = '55c92734-d682-4d71-983e-d6ec3f16059f'" `
                    -Property LicenseStatus -ErrorAction Stop
            }
            catch {
                $status = New-Object ComponentModel.Win32Exception ($_.Exception.ErrorCode)
                $wpa = $null    
            }
            $out = New-Object psobject -Property @{
                ComputerName = $DNSHostName;
                Status       = [string]::Empty;
            }
            if ($wpa) {
                :outer foreach ($item in $wpa) {
                    switch ($item.LicenseStatus) {
                        0 {$out.Status = "Unlicensed"}
                        1 {$out.Status = "Licensed"; break outer}
                        2 {$out.Status = "Out-Of-Box Grace Period"; break outer}
                        3 {$out.Status = "Out-Of-Tolerance Grace Period"; break outer}
                        4 {$out.Status = "Non-Genuine Grace Period"; break outer}
                        5 {$out.Status = "Notification"; break outer}
                        6 {$out.Status = "Extended Grace"; break outer}
                        default {$out.Status = "Unknown value"}
                    }
                }
            }
            else {$out.Status = $status.Message}
            $out
        }
    }

    $vMList = Get-VM |Select-Object Name -ExpandProperty Name
	Get-VM | Select-Object -Property `
		@{n='ComputerName';				e={$ENV:ComputerName}},
		VMName,
        State,
        @{n='License Status';				e={($vMList | Get-ActivationStatus)}}
      
}

#Get HyperV Guest Information
$HyperVGuestInfo = Invoke-Command -ComputerName $serverList -Credential $cred -ScriptBlock $scriptblock |
	Select-Object -Property * -ExcludeProperty PSComputerName, RunspaceId |
	Sort-Object -Property ComputerName, VMName

Open in new window

0
David Johnson, CD, MVPOwnerCommented:
get-vm | select-object -expandproperty name | get-activationstatus

Open in new window

gave me a list of machines with their status
0
ITguy565Author Commented:
footech,

we are much closer

Currently this is what the output is showing from your code:

The License status information is still off as you can see:

The output should read
ComputerName |VMName |      License Status
HYPNA1                |Machine1 |     RPC Unavailable
HYPNA2                |Machine2 |    Licensed

 
output.png
0
ITguy565Author Commented:
@David

Rodger that sir.. The Get-ActivationStatus function isn't the issue. The issue at this point appears to be getting the array to display on this table correctly.
0
ITguy565Author Commented:
The lines of code that are still in question are the following :

vMList = Get-VM |Select-Object Name -ExpandProperty Name
	Get-VM | Select-Object -Property `
		@{n='ComputerName';				e={$ENV:ComputerName}},
		VMName,
        State,
        @{n='License Status';				e={($vMList | Get-ActivationStatus)}}

Open in new window


 @{n='License Status';                        e={($vMList | Get-ActivationStatus)}}
0
ITguy565Author Commented:
Want to thank everyone for their help so far.. We are much further ahead than where we started!!!
0
footechCommented:
This line needs to be changed.
@{n='License Status';e={($vMList | Get-ActivationStatus)}}
Instead of $vMList, we need to pass the name of the specific VM to the pipeline for Get-ActivationStatus to act on.  Get-ActivationStatus queries remote computers via RPC/DCOM to look at WMI information.  The function would have to be changed if we wanted to use PS Remoting instead.  At present, the firewall on each VM would need to allow the WMI traffic.

I'm not familiar with what the out from Get-VM is.  We just need to reference the correct property.  Something like below (which references the name property).
@{n='License Status';e={($_.Name | Get-ActivationStatus)}}

Open in new window

2

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ITguy565Author Commented:
That was exactly where I needed to go.. You were EXTREMELY close on the syntax. The final Syntax was

 @{n='License Status';e={($_.Name | Get-ActivationStatus).Status}}

$scriptblock = {
    function Get-ActivationStatus {
        [CmdletBinding()]
        param(
            [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
            [string]$DNSHostName = $Env:COMPUTERNAME
        )
        process {
            try {
                $wpa = Get-WmiObject SoftwareLicensingProduct -ComputerName $DNSHostName `
                    -Filter "ApplicationID = '55c92734-d682-4d71-983e-d6ec3f16059f'" `
                    -Property LicenseStatus -ErrorAction Stop
            }
            catch {
                $status = New-Object ComponentModel.Win32Exception ($_.Exception.ErrorCode)
                $wpa = $null    
            }
            $out = New-Object psobject -Property @{
                ComputerName = $DNSHostName;
                Status       = [string]::Empty;
            }
            if ($wpa) {
                :outer foreach ($item in $wpa) {
                    switch ($item.LicenseStatus) {
                        0 {$out.Status = "Unlicensed"}
                        1 {$out.Status = "Licensed"; break outer}
                        2 {$out.Status = "Out-Of-Box Grace Period"; break outer}
                        3 {$out.Status = "Out-Of-Tolerance Grace Period"; break outer}
                        4 {$out.Status = "Non-Genuine Grace Period"; break outer}
                        5 {$out.Status = "Notification"; break outer}
                        6 {$out.Status = "Extended Grace"; break outer}
                        default {$out.Status = "Unknown value"}
                    }
                }
            }
            else {$out.Status = $status.Message}
            $out
        }
    }

    $vMList = (Get-VM |Select-Object Name -ExpandProperty Name | Get-ActivationStatus).Status
	Get-VM | Select-Object -Property `
		@{n='ComputerName';				e={$ENV:ComputerName}},
		VMName,
        State,
        @{n='License Status';e={($_.Name | Get-ActivationStatus).Status}}
        #@{n='License Status';				e={($vMList | Get-ActivationStatus).Status}}
       
}

#Get HyperV Guest Information
$cred = Get-Credential
$ServerList = Get-ADComputer -Filter "Name -like '*K2*'" |Sort-Object -Property Name |Select-Object -ExpandProperty Name

$HyperVGuestInfo = Invoke-Command -ComputerName $serverList -Credential $cred -ScriptBlock $scriptblock |
	Select-Object -Property * -ExcludeProperty PSComputerName, RunspaceId |
    Sort-Object -Property ComputerName, VMName
    $HyperVGuestInfo | Out-GridView

Open in new window

0
ITguy565Author Commented:
Thanks for the assistance on this!!!
0
footechCommented:
Glad to help!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Powershell

From novice to tech pro — start learning today.