How to find IpAddress of a virtual machine programmatically from hypervisor? - powershell

I am using HyperV WMI provider to to update virtual machine's configuration/settings (like hard ware, disks etc..)
How can I get IpAddress of a VM from HyperV?
How to do the same thing in VMWare?
Regards,
Dreamer!

This article describes how to get the IP address of a virtual
machine from Hyper-V (Windows 2008 R2 Hyper-V) using Powershell.
Using the PowerCli: (get-vm <name of your vm>).guest.ipaddress

For Hyper-V, this is how I usually pull an IP from a host box.
$vm = Get-WmiObject -computerName "." -NameSpace "Root\Virtualization" -query "SELECT * FROM Msvm_KvpExchangeComponent" #pulls VM WMI object ExchangeComponents
$vmitems = $vm.GuestIntrinsicExchangeItems
$ipitem = $vmitems[-4]#yay! a hack that relies on XML schemas!
$xmlip = [xml]$ipitem #convert string format to XML
$ipaddr = $xmlip.INSTANCE.PROPERTY[1].VALUE #playing with XML schemas again hopefully reliably
It's not the neatest/cleanest/nicest code, but it is a way to get that information.

Here's an alternate variation that I cooked up to demonstrate a more robust approach at finding the value for a given name. This doesn't rely on a specific relative ordering inside the schema of Caption, Data, Description, ElementName, Name or Source
$vmParams = #{
NameSpace = 'Root\Virtualization';
Query = 'SELECT * FROM Msvm_KvpExchangeComponent' #pulls VM WMI object ExchangeComponents
}
Get-WmiObject #vmParams |
% {
$xml = [Xml]"<properties>$($_.GuestIntrinsicExchangeItems)</properties>"
$xml.properties.INSTANCE.Property |
% {
$value = ($_.ParentNode.Property | ? { $_.Name -eq 'Data' }).VALUE
if ($_.Value -eq 'FullyQualifiedDomainName')
{
Write-Host "Host: $($value)"
}
if ($_.Value -eq 'RDPAddressIPv4')
{
Write-Host "RDP Address: $($value)"
}
}
}

Related

Change a Windows product key remotely with PowerShell

I'm trying to install/activate a MAK key on remote servers. All of them have RemotePS enabled and firewall exception rules in place.
$Results = Invoke-Command -ComputerName Server1 {
$Props = #{ComputerName = $env:ComputerName}
slmgr.vbs /ipk "12345-12345-12345-12345-12345"
$LicStatus = slmgr.vbs /dlv
$Props.Add('LicenseStatus',$LicStatus)
New-Object -TypeName PSObject -Property $Props
}
$Results | Select-Object ComputerName,LicenseStatus
The above does install the MAK key but I don't get any confirmation of this process which is why I've tried adding in the license check option (/dlv) but get nothing returned in the LicenseStatus field. I'm assuming this is because it returns a multi-value maybe!?
Ultimately I'm just trying to get confirmation that the key was installed. There are articles out there about performing this using RemotePS but they all say a notification message is returned for each computer which isn't the case in my experience: https://4sysops.com/archives/change-a-product-key-remotely-with-powershell/
Any ideas how I can check this?
I would call the slmgr.vbs script using Cscript.exe in order to get the results as string array. Otherwise the system will default to using Wscript.exe which is designed to output everything in a messagebox.
Unfortunately, all output of slmgr is localized, so using a regex or something on the LicenseStatus is a no go (on a Dutch NL machine it reads 'Licentiestatus')
What you can do is using switch /dli, because that returns a string array where the last (not empty) value has the status.
Try
$Results = Invoke-Command -ComputerName Server1 {
# install MAK key
$null = cscript.exe "$env:SystemRoot\System32\slmgr.vbs" /ipk "12345-12345-12345-12345-12345"
# test LicenseStatus
$LicStatus = (((cscript.exe "$env:SystemRoot\System32\slmgr.vbs" /dli) |
Where-Object { $_ -match '\S' })[-1] -split ':', 2)[1].Trim()
# return an object
[PsCustomObject]#{
ComputerName = $env:COMPUTERNAME
LicenseStatus = $LicStatus
}
}
$Results

How to Verify Reserved IP with Powershell

I am working on a little powershell 3.0 GWMI script that pulls computer information for use in an enterprise environment (ip, mac address, etc).
I'm trying to go through the WMI properties for NetworkAdapterConfiguration to see if there is a way to check for a reserved IP vs. a dynamically assigned one.
Would anyone have advice on how to pull this from WMI or elsewhere? Does (preferred) always indicate that an IP is reserved on the network?
I'm finding a lot of information for powershell and Azure but not a ton for figuring this out on a local box.
As Ron Maupin noted, Host computers will only know whether they were assigned an addressed from the DHCP, not if there was a reservation. But they will report which DHCP server they received their address from. So you can query that server (assuming you have read permissions).
Here is a script that after retrieving the information from a computer over WMI will check with the DHCP server if a reservation exists.
$ComputerName = "ExampleComputer"
$NetAdapters = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ComputerName | ? {$_.DHCPEnabled -eq $True -and $null -ne $_.IPAddress}
If ($NetAdapters) {
Foreach ($Adapter in $NetAdapters) {
foreach ($IP in $Adapter.IPAddress) {
$Reservation = Get-DhcpServerv4Reservation -ScopeId $IP -ComputerName $Adapter.DHCPServer | ? {$_.ScopeId -eq $_.IPAddress}
If ($Reservation) {
Write-Output "$IP is reserved on $($Adapter.DHCPServer)."
} Else {
Write-Output "$IP does not have a reservation."
}
}
}
} Else {
Write-Output "No DHCP Enabled NetAdapters with IPAddresses exist on host, likely Static"
}
Using the above script provided by BenH I was able to cobble together a script that worked across my fleet of AWS servers from SSM using the AWS-RunPowerShellScript run document which would give me a fail status if any of my instances weren't configured for DHCP. We had a few lingering out there which were using our DHCP Options Set in our VCP and this helped uncover them. Thanks!
$NetAdapters = Get-WmiObject Win32_NetworkAdapterConfiguration | ? {$_.DHCPEnabled -eq $True -and $null -ne $_.IPAddress} | Select Description
If ($NetAdapters) {
Foreach ($Adapter in $NetAdapters.Description) {
Write-Output "DHCP is enabled on $Adapter"
exit 0
}
} Else {
Write-Output "DHCP is not enabled on any adapters on host, likely Static"
exit 1
}

List of all COM ports shown in device manager by using PowerShell

I want to incorporate a dropdown menu that is populated with the list of available COM ports. I can't find any way to easily get the names of the available COM ports to put in the place of COM4 that creates the $port.
$port = new-Object System.IO.Ports.SerialPort COM4,19200,None,8,one
By using Win32_SerialPort I am able to easily extract COM1 and COM3.
Get-WmiObject Win32_SerialPort | Select-Object deviceid
Results:
deviceid
COM3
COM1
But my device manager shows 16 available ports from a remote serial hub.
Device Manager Snapshot
Here is what I have tried and I am able to narrow down the Name, but can't figure out how to extract just the (COM--) part.
Get-WmiObject Win32_pnpentity -Filter "Name LIKE 'devicemaster port%'" | Select-Object -Property Name
Result Screenshot
Adding a late answer because I just had a need for this...
You can use WMI ClassGuids to get the exact list (COM and LPT) that device manager shows:
$lptAndCom = '{4d36e978-e325-11ce-bfc1-08002be10318}'
get-wmiobject -Class win32_pnpentity | where ClassGuid -eq $lptAndCom | select name
Confirmed to work with a few LPT / COM extension cards (Brain Boxes / Exar), using Windows 8.1 up to server 2019 (Powershell 4 onwards).
The full list of ClassGuids is here:
https://learn.microsoft.com/en-us/windows-hardware/drivers/install/system-defined-device-setup-classes-available-to-vendors
Here is a more up-to-date solution to get the COM-port details:
cls
$portList = get-pnpdevice -class Ports -ea 0
$portCount = 0
if ($portList) {
$now = get-date
foreach($device in $portList) {
$id = $device.InstanceId
if ($device.Present) {
$date = $now
} else {
$info = Get-PnpDeviceProperty -InstanceId $id
$latest = $info | ?{$_.KeyName -eq "DEVPKEY_Device_LastRemovalDate"}
$date = [datetime]$latest.Data
}
$age = $now-$date
if ($age.Days -lt 14) {
"port name : $name"
"last active: $date"
""
$portCount++
}
}
}
"number of active COM-port devices in last 14 days: $portCount"
Leaving some work to you to figure out, but based on your Result Screenshot you can do something like this:
$ports = #()
$ports += 'devicemaster port (COM1)'
$ports += 'devicemaster port (COM2)'
$ports += 'devicemaster port (COM3)'
$ports += 'devicemaster port (COM4)'
$ports | % {
if ($_ -match "devicemaster port \((.*)\)") {
$matches[1]
}
}
with that object, assuming you store that in '$ports'. You may need to use '$ports.Name'...
Possibly see regex101.com for how the regex works.

How to verify whether a windows server has mountpoint or not using WMI

I am generating a report where I need to find which servers has mountpoints configured on it..
can you help how to get that infor using WMI or powershell.
I mean I need to identify the servers, if mountpoints exists in it.. and also their names....
Get a list of all servers from textfile, AD, etc. and run a foreach loop with something like this:
Get-Wmiobject -query “select name,driveletter,freespace from win32_volume where drivetype=3 AND driveletter=NULL” -computer servername
A quick google search for "windows mount point wmi" would return THIS (source).
Then export the results to CSV, HTML or whatever you need. Your question is lacking a lot of details and any sign of effort from your part, so I can't/won't go any further.
UPDATE: Does this help? It lists mount points(folder paths, not driveletters).
$servers = #("server1","server2","server3","server4","server5")
$servers | % {
$mountpoints = #(Get-WmiObject Win32_MountPoint -ComputerName $_ | Select-Object -ExpandProperty Directory | ? { $_ -match 'Win32_Directory.Name="(\w:\\\\.+)"' }) | % { [regex]::Match($_,'Win32_Directory.Name="(\w:\\\\.+)"').Groups[1].Value -replace '\\\\', '\' }
if($mountpoints.Count -gt 0) {
New-Object psobject -Property #{
Server = $_
MountPoints = $mountpoints
}
}
}
Server MountPoints
------ -----------
{server1} {D:\SSD, C:\Test}

NetBIOS domain of computer in PowerShell

How can I get the NetBIOS (aka 'short') domain name of the current computer from PowerShell?
$ENV:USERDOMAIN displays the domain of the current user, but I want the domain that the current machine is a member of.
I've discovered you can do it pretty easily in VBScript, but apparently ADSystemInfo isn't very nice to use in PowerShell.
Update
Here's my final solution incorporating the suggestion of using Win32_NTDomain, but filtering to the current machine's domain
$wmiDomain = Get-WmiObject Win32_NTDomain -Filter "DnsForestName = '$( (Get-WmiObject Win32_ComputerSystem).Domain)'"
$domain = $wmiDomain.DomainName
In most cases, the default NetBIOS domain name is the leftmost label in the DNS domain name up to the first 15 bytes (NetBIOS names have a limit of 15 bytes).
The NetBIOS domain name may be changed during the installation of the Active Directory, but it cannot be changed.
The WIN32_ComputerSystem WMI object gives informations on a Windows computer
PS C:\> Get-WmiObject Win32_ComputerSystem
Domain : WORKGROUP
Manufacturer : Hewlett-Packard
Model : HP EliteBook 8530w (XXXXXXXXX)
Name : ABCHPP2
PrimaryOwnerName : ABC
TotalPhysicalMemory : 4190388224
So the domain Name is given by :
PS C:\> (gwmi WIN32_ComputerSystem).Domain
But in domain installation, the DNS name is given. In this case, you can use nbtstat -n command to find the NetBIOS domain name which is displayed like this <DOMAIN><1B>.
The PowerShell Command may be :
nbtstat -n | Select-String -Pattern "^ *(.*) *<1B>.*$" | % {$_ -replace '^ *(.*) *<1B>.*$','$1'}
Here is another way using WMI
PS C:\> (gwmi Win32_NTDomain).DomainName
Use env: to get environment settings through PowerShell
NetBIOS: $env:userdomain
FQDN: $env:userdnsdomain
To see all the values:
dir env: (no $)
import-module activedirectory
(Get-ADDomain -Identity (Get-WmiObject Win32_ComputerSystem).Domain).NetBIOSName
From Here
# Retrieve Distinguished Name of current domain.
$Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$Root = $Domain.GetDirectoryEntry()
$Base = ($Root.distinguishedName)
# Use the NameTranslate object.
$objTrans = New-Object -comObject "NameTranslate"
$objNT = $objTrans.GetType()
# Invoke the Init method to Initialize NameTranslate by locating
# the Global Catalog. Note the constant 3 is ADS_NAME_INITTYPE_GC.
$objNT.InvokeMember("Init", "InvokeMethod", $Null, $objTrans, (3, $Null))
# Use the Set method to specify the Distinguished Name of the current domain.
# Note the constant 1 is ADS_NAME_TYPE_1779.
$objNT.InvokeMember("Set", "InvokeMethod", $Null, $objTrans, (1, "$Base"))
# Use the Get method to retrieve the NetBIOS name of the current domain.
# Note the constant 3 is ADS_NAME_TYPE_NT4.
# The value retrieved includes a trailing backslash.
$strDomain = $objNT.InvokeMember("Get", "InvokeMethod", $Null, $objTrans, 3)
OP is after "computer domain" so the answer would be $GetComputerDomain (below) but I will add the $GetUserDomain also for reference.
$GetComputerDomain = ([System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain()).Name
$GetUserDomain = ([System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).Name
I find the wmi (gwmi) option to be extremely slow, especially, when you are querying the Win32_NTDomain class. I have a multi-trusted domain environment and it takes forever when I just need that simple info quick.
Use the Active Directory Cmdlet Get-ADDomain:
(Get-ADDomain -Current LocalComputer).NetBIOSName
The below powershell command works great! I tested after trying various solutions.
If you use the following .Net command:
[System.Net.Dns]::GetHostByAddress('192.168.1.101').hostname
It works too, but it is using DNS to resolve, in my case, we have WINS setup to support an application that requires it, so can't use it. Below is what I ended up using as part of a script I use to check for WINS registration for each client:
$IPAddress = "<enterIPAddress>" (remove brackets, just enter IP address)
(nbtstat -A $IPAddress | ?{$_ -match '\<00\> UNIQUE'}).Split()[4]
http://social.technet.microsoft.com/Forums/en-US/f52eb2c7-d55d-4d31-ab4e-09d65d366771/how-to-process-cmd-nbtstat-a-ipaddress-output-and-display-the-computer-name-in-powershell?forum=ITCG
The above link has the thread and conversation.
Using NetGetJoinInformation and P/Invoke:
Add-Type -MemberDefinition #"
[DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern uint NetApiBufferFree(IntPtr Buffer);
[DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int NetGetJoinInformation(
string server,
out IntPtr NameBuffer,
out int BufferType);
"# -Namespace Win32Api -Name NetApi32
function GetDomainName {
$pNameBuffer = [IntPtr]::Zero
$joinStatus = 0
$apiResult = [Win32Api.NetApi32]::NetGetJoinInformation(
$null, # lpServer
[Ref] $pNameBuffer, # lpNameBuffer
[Ref] $joinStatus # BufferType
)
if ( $apiResult -eq 0 ) {
[Runtime.InteropServices.Marshal]::PtrToStringAuto($pNameBuffer)
[Void] [Win32Api.NetApi32]::NetApiBufferFree($pNameBuffer)
}
}
This can also be done by using .NET framework (which is much faster than WMI)
PS > [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()
Will return
HostName : SurfaceBook
DomainName : mydomain.com
NodeType : Hybrid
DhcpScopeName :
IsWinsProxy : False
Using the ADSystemInfo COM object should work, with no delay from Win32_NTDomain lookup:
$ADSystemInfo = New-Object -ComObject "ADSystemInfo"
$ADSystemInfo.GetType().InvokeMember("DomainShortName", "GetProperty", $null, $ADSystemInfo, $null)
There are other AD-related properties available from this COM object too:
https://learn.microsoft.com/en-us/windows/win32/adsi/iadsadsysteminfo-property-methods
[EDITED - Originally included code for the WinNTSystemInfo COM object instead but a commenter pointed out this only returns the user's short domain - but ADSystemInfo does return the computer's short domain]
Here is another faster method than Win32_NTDomain, for getting the NetBIOS domain of the computer.
# Get the computer system CIM/WMI
$computersystem = Get-CimInstance Win32_ComputerSystem
# Create a Windows Identity Principal object based on the name and domain in Win32_ComputerSystem
$ComputerPrincipal = [System.Security.Principal.WindowsIdentity]::new("$($computersystem.name)#$($computersystem.domain)")
# Split the NetBIOS name on \ and get the first value which should be the domain
($ComputerPrincipal.Name -split "\\")[0]
# Bonus point, the WindowsIdentity Principal has a bunch of other useful information.
# Like quick enumeration of the groups it's in (but needs to be translated from SID to NTAccount format).
$ComputerPrincipal.Groups.Translate([System.Security.Principal.NTAccount]).value