Mapping Disks to Initiators using Powershell - powershell

I am using Windows Server 2016 with Powershell 7.0.2. I want to get the target IDs (WWNs or iSCSI Addresses) for my connected storages shown as disks. I get the disks on my Windows Server using get-disk
$Disks=get-disk
I can get if these are attached through iscsi or FC from BusType attribute. Then I can get the local port info
$Ports=Get-initiatorPort
I can get the Address (FC or ISCSI) from NodeAddress. At this point I am stuck.
How do I map which disk is using which NodeAddress on initiator
How do I get the target system ID (icsci iqn or FC WWN)

You can pass your disk object right to Get-IscsiSession which can give you some of the details you're looking for.
An example:
$DiskList = Get-Disk | Where-Object { $_.BusType -eq 'iSCSI' ]
foreach ($Disk in $DiskList) {
$SessionList = $Disk | Get-IscsiSession
foreach ($Session in $SessionList) {
[PSCustomObject]#{
Name = $Disk.FriendlyName
InitiatorNode = $Session.InitiatorNodeAddress
TargetNode = $Session.TargetNodeAddress
}
}
}
The only server I have to test on has PowerShell 4 with iSCSI multipath connections. You may not need the SessionList loop if you don't use MPIO.

Related

In PowerShell, how do I determine if a domain-joined computer is connected to the domain network?

Before querying Active Directory, I need to make sure that the computer is actually attached to the corporate network (i.e., a domain network) with a secure connection to a domain controller. Network Location Awareness does this behind the scenes and presents the network profile in the GUI.
How do I do this in PowerShell?
This appears to work well, and should work on all versions of PowerShell:
function Test-DomainNetworkConnection
{
# Returns $true if the computer is attached to a network where it has a secure connection
# to a domain controller
#
# Returns $false otherwise
# Get operating system major and minor version
$strOSVersion = (Get-WmiObject -Query "Select Version from Win32_OperatingSystem").Version
$arrStrOSVersion = $strOSVersion.Split(".")
$intOSMajorVersion = [UInt16]$arrStrOSVersion[0]
if ($arrStrOSVersion.Length -ge 2)
{
$intOSMinorVersion = [UInt16]$arrStrOSVersion[1]
} `
else
{
$intOSMinorVersion = [UInt16]0
}
# Determine if attached to domain network
if (($intOSMajorVersion -gt 6) -or (($intOSMajorVersion -eq 6) -and ($intOSMinorVersion -gt 1)))
{
# Windows 8 / Windows Server 2012 or Newer
# First, get all Network Connection Profiles, and filter it down to only those that are domain networks
$domainNetworks = Get-NetConnectionProfile | Where-Object {$_.NetworkCategory -eq "Domain"}
} `
else
{
# Windows Vista, Windows Server 2008, Windows 7, or Windows Server 2008 R2
# (Untested on Windows XP / Windows Server 2003)
# Get-NetConnectionProfile is not available; need to access the Network List Manager COM object
# So, we use the Network List Manager COM object to get a list of all network connections
# Then we get the category of each network connection
# Categories: 0 = Public; 1 = Private; 2 = Domain; see: https://msdn.microsoft.com/en-us/library/windows/desktop/aa370800(v=vs.85).aspx
$domainNetworks = ([Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]"{DCB00C01-570F-4A9B-8D69-199FDBA5723B}"))).GetNetworkConnections() | `
ForEach-Object {$_.GetNetwork().GetCategory()} | Where-Object {$_ -eq 2}
}
return ($domainNetworks -ne $null)
}
With this function defined, simply type:
Test-DomainNetworkConnection
If it returns $true, then you know you have connectivity to a domain controller.

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
}

Get iscsi mapped drive letter from iscsi initiator name

In PowerShell I'm trying to get the drive letter that an ISCSI target is mapped to. I'm using the following to get the ISCSI initiator name.
Get-IscsiTarget | ? {$_.IsConnected -eq $True} | Select -ExpandProperty NodeAddress
I have tried using Get-Disk | Select * and Get-PSDrive | Select * but these cmdlets do not seem to have any fields that I can link a target to, to obtain its drive letter.
As long as you have one active partition (not including reserved) per ISCSI target, you can use the following to match an ISCSI address to its corresponding drive letter.
foreach ($disk in (Get-Disk | ?{$_.BusType -Eq "iSCSI"})){
$DriveLetter = ($disk | Get-Partition | ?{$_.Type -eq "Basic"}).DriveLetter
$ISCSI = $disk | Get-IscsiSession
[pscustomobject]#{
DiskNumber=$disk.Number;
DriveLetter=$DriveLetter;
InitiatorNodeAddress=$ISCSI.InitiatorNodeAddress;
InitiatorIP=$ISCSI.InitiatorPortalAddress;
Size=$disk.Size;
}
}
This will check all connected ISCSI disks and get their corresponding drive letter, then it will put all the information into a customer PowerShell object and return it.

CPU core count from a Hyper-V host under SCVMM 2012

I asked this question on the TechNet forums without any luck (link), so I thought I'd see if anyone around here might have an answer:
At our company we have a VMM server (SCVMM 2012) controlling two physical Hyper-V hosts (let's call them HOST01 and HOST02). I'm trying to get some information about HOST01 via PowerShell queries on the VMM server:
Get-VMHost -ComputerName HOST01
..which among other things returns some CPU info:
...
LogicalProcessorCount = 12
PhysicalCPUCount = 1
CoresPerCPU = 12
L2CacheSize = 2048
L3CacheSize = 20480
BusSpeed = 100
ProcessorSpeed = 2294
ProcessorModel = Xeon
ProcessorManufacturer = Intel
ProcessorArchitecture = 9
ProcessorFamily = 179
CpuUtilization = 33
...
Now, I happen to know that HOST01 runs on a 6 core CPU with hyperthreading *), so LogicalProcessorCount = 12 is correct, but I expected to see CoresPerCPU = 6 (not 12). Why doesn't VMM show the correct number of physical cores? Am I looking in the wrong place?
Alternatively, is there a way to see whether hyperthreading is activated on the host, so I could divide by 2 as a last resort?
*) HOST01 is our own test server, so I have queried it separately through WMI to get CPU data, but in a production environment we cannot rely on having access to anything but the VMM server.
With Hyper-Threading enabled you get 2 logical processors per core. Since VMM cares only about the number of logical processors I doubt you'll be able to get "lower level" CPU information out of it. To get the actual number of cores for each CPU you have to query the processor information via WMI:
Get-WmiObject Win32_Processor -Computer HOST01 |
select Name, NumberOfCores, NumberOfLogicalProcessors
Edit: In a situation where user and host have no access at all to the hypervisors I don't think you'll be able to obtain that information. Not without making some changes to the infrastructure, that is. The following might provide a viable approach, if you have someone who can set it up on the VMM host for you.
Periodically collect the information from the hypervisors with a scheduled task running the following script on the VMM host:
$datafile = 'C:\path\to\data.csv'
$hypervisors = Get-SCVMHost | select -Expand Name
Get-WmiObject Win32_Processor -Computer $hypervisors |
select Name, NumberOfCores | Export-Csv $datafile -NoType -Encoding ASCII
Publish the content of the datafile with a custom web server on the VMM host:
$port = 8000
$datafile = 'C:\path\to\data.csv'
$lastUpdate = Get-Date 0
$data = ''
function Get-Data {
$filedate = (Get-Item $datafile).LastWriteTime
if ($filedate -gt $lastUpdate) {
$script:data = Import-Csv 'C:\Temp\text.csv' | ConvertTo-Json
$script:lastUpdate = $filedate
}
$script:data
}
If (-not (Test-Path -LiteralPath $datafile)) {
New-Item -ItemType File -Path $datafile | Out-Null
}
$listener = New-Object Net.HttpListener
$listener.Prefixes.Add("http://+:$port/")
$listener.Start()
while ($listener.IsListening) {
$response = $listener.GetContext().Response
$response.Headers.Add('Content-Type', 'text/plain')
$buffer = [Text.Encoding]::ASCII.GetBytes((Get-Data))
$response.ContentLength64 = $buffer.Length
$response.OutputStream.Write($buffer, 0, $buffer.Length)
$response.Close()
}
$listener.Stop()
If the Windows Firewall is enabled on the VMM host you need to open the listener port in it.
With that in place you can access the data from a server or workstation like this:
Invoke-WebRequest 'http://vmmserver:8000/' | select -Expand Content |
ConvertFrom-Json

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

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)"
}
}
}