NetBIOS domain of computer in PowerShell - 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

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

PowerShell Script to implement ipsec rule

I am troubleshooting an issue in our local IT infrastructure. Some time ago a GPO was pushed that blocked traffic from our IT administration program to our production devices.
Long story short the big company made a decision which wrongly affects our very specific IT needs/design in our department.
Due to sheer coincidence we managed to resolve the issue by manually adding an IPSEC security exception on a device to solve a different issue.
Now the below dodgy attempt by me to make a PS command is just a base as the correct parameters are still to be decided after meeting with multiple sides of the business and IT.
But to reduce the time I need to implement the solution on hundreds of our devices I would like to get a script working where I just have to add or adjust the parameters when I receive the word "go"
I would need the command below to be useable with an input (list/array) of all our devices. I am looking into the CimSession cmdlet but I struggle to come up with a solution to loop through a list/array and add both the target computer and its IP address to the script.
Thank you in advance for your tips on how to proceed.
With the responses below I have expanded the script to the following:
```Powershell
# Ask for the csv file
$CsvLocation = Read-Host -Prompt 'input the location of the csv file (for
example c:\Users\USERNAME\Documents\workstations.csv)'
$CsvFile = Import-CSV -Path $CsvLocation
# Create empty Hash Table
$Machines = #{Workstation = "Test" ; IP = "123"}
# create a hashtable to store the parameters in for splatting
$ruleParams = #{
Confirm = $false
Enabled = $true
Description = 'This rule is instated to allow MobiControl
Administration to be performed on this device.'
DisplayName = 'MobiControl connection'
IPsecRuleName = 'Mobicontrol connection'
OutboundSecurity = 'None'
InboundSecurity = 'None'
Platform = '6.1+'
PolicyStore = 'PersistentStore'
Profile = 'Any'
RemoteAddress = '10.133.120.207'
RequireAuthorization = $false
Protocol = 'any'
}
# For each Element in the csv file add name and ip address to the hash
table
$CsvFile | ForEach-Object {
$Workstation = $_.Workstation
$IpAddress = [System.Net.Dns]::GetHostAddresses($Workstation) |
Where-Object { $_.AddressFamily -eq 'InterNetwork' } | Select-Object -
ExpandProperty IpAddressToString
$Machines.add($Workstation, $IpAddress)
# fill in the two remaining parameters with the IP address and computer
name
<# test print contents
Read-Host "press enter to see the values for hostname and ip address"
Echo $Machines.keys
Read-Host "press enter to continue"
#>
$ruleParams['LocalAddress'] = $_.Value # IP Address
$ruleParams['CimSession'] = $_.Key # HostName
# execute using the ruleParams splat
Write-Host "Creating IPsecRule on computer $() with IP address $()"
# New-NetIPsecRule #ruleParams
}
This looks to be more in the direction I want. Any obvious flaws?
the input csv file would just be a list of workstation names.
Testing the code all seems to be in working order up until the execution of the New-NetIPsecRule. The values inside the hashtable $Machines are non valid inputs for their related parameters.
The way you add the parameters to the cmdlet is incorrect and would require the much hated backticks at the end of each line, preceeded with a space.
Similar that, but much better is to use Splatting
# create a hashtable to store the parameters in for splatting
$ruleParams = #{
Confirm = $false
Enabled = $true
Description = 'This rule is instated to allow MobiControl Administration to be performed on this device.'
DisplayName = 'MobiControl connection'
IPsecRuleName = 'Mobicontrol connection'
OutboundSecurity = 'None'
InboundSecurity = 'None'
Platform = '6.1+'
PolicyStore = 'PersistentStore'
Profile = 'Any'
RemoteAddress = '10.133.120.207'
RequireAuthorization = $false
# I'm not sure about the Protocol parameter..
# The docs say it is a String, but also refer to the Get-NetFirewallPortFilter
# cmdlet where this parameter is a string array (String[])
Protocol = 'TCP,UDP'
}
# now iterate over the $machines hashtable, fill in the two missing parameters in the hash and execute
$machines.GetEnumerator() | ForEach-Object {
$CimSession = Get-CimSession -ComputerName $_.Key
# fill in the two remaining parameters with the IP address and computer name
$ruleParams['LocalAddress'] = $_.Value # IP Address
$ruleParams['CimSession'] = $CimSession
# execute using the ruleParams splat
Write-Host "Creating IPsecRule on computer $($_.Key) with IP address $($_.Value)"
New-NetIPsecRule #ruleParams
$CimSession | Remove-CimSession
}
Disclaimer.. I cannot try this myself, and as I'm not sure the Protocol parameter should be a single comma separated string or a string array, please try this on a limited test set of machines first.
P.S. When creating the $machines hashtable, change this line
$IpAddress = [System.Net.Dns]::GetHostAddresses($Workstation) |
Where-Object { $_.AddressFamily -eq 'InterNetwork' } | select IpAddressToString
into
$IpAddress = [System.Net.Dns]::GetHostAddresses($Workstation) |
Where-Object { $_.AddressFamily -eq 'InterNetwork' } | Select-Object -ExpandProperty IpAddressToString

Powershell - Local Network scan (no domain)

Just wondering if anybody knows a way in powershell to scan the local network for Computers, resolving their name's and IP's.
I know a possibility with Get-ADComputer, but this network is not in a domain.
You can use the .net DNS class in powershell.
reference: http://msdn.microsoft.com/en-us/library/system.net.dns%28v=vs.110%29.aspx
example:
PS C:\> $dns = [system.net.dns]
PS C:\> $dns::GetHostEntry("198.252.206.16") | format-list
HostName : stackoverflow.com
Aliases : {}
AddressList : {198.252.206.16}
Scanning example if your network as a 192.168.1.0/24:
$results = #() ; 1..255 | % { $results += $dns::GetHostByAddress("192.168.1.$_") }

Wbadmin & powershell - latest backup version identifier

I need to get the latest backups version identifier in a powershell script. If I run wbadmin get versions, I get a list of backups and the last one is the one I need.
Is there a way to do a kind of select top 1 version identifier from backups order by date or parsing the wbadmin output and getting this.
edit
It may be the windows.serverbackup module and versionId of Get-WBBackupSet I'm looking for but still need help parsing this.
VersionId : 04/17/2013-21:00
BackupTime : 17/04/2013 22:00:55
BackupTarget : U:
RecoverableItems : Volumes, SystemState, Applications, Files, BareMetalRecovery
Volume : {System Reserved, Local disk (C:), Local disk (I:), Local disk (O:)...}
Application : {"Cluster", "Registry", "Microsoft Hyper-V VSS Writer"}
VssBackupOption : VssFullBackup
SnapshotId : 58999c7d-dfbf-4272-a5b9-21361d171486
Give this a try, Use -Last instead of -First to get the last item:
Get-WBBackupSet |
Sort-Object BackupTime |
Select-Object -First 1 -ExpandProperty VersionId
You can also play with the order of sorting with the -Ascending switch
Edit: revised version
For use with mixed environments (Windows Server 2008, 2008R2, 2012, 2012R2 as of this writing):
function Get-MyWBSummary
{
<#
.SYNOPSIS
Retrieves the history of backup operations on the local or any number of remote computers.
.DESCRIPTION
The Get-MyWBSummary cmdlet retrieves the history of backup operations on the local or any number of remote computers with remoting enabled. This information includes backuptime, backuplocation, bersion identifier and recovery information.
To use this cmdlet, you must be a member of the Administrators group or Backup Operators group on the local or remote computer, or supply credentials that are.
.PARAMETER ComputerName
Retrives backup results on the specified computers. The default is the local computer.
Type the NetBIOS name, an IP address, or a fully qualified domain name of one or more computers. To specify the local computer ignore the ComputerName parameter.
This parameter rely on Windows PowerShell remoting, so your computer has to be configured to run remote commands.
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The default is the current user. Type a user name, such as "User01", "Domain01\User01", or User#Contoso.com. Or, enter a PSCredential object, such as an object that is returned by the Get-Credential cmdlet. When you type a user name, you are prompted for a password.
.PARAMETER Last
Specifies the last (newest/latest) backup versions.
.EXAMPLE
Get-MyWBSummary
Retrieves all Windows Server backupversions from the local computer
.EXAMPLE
Get-MyWBSummary | Where BackupTime -gt (Get-Date).AddDays(-7)
Retrieves all Windows Server backupversions from the local computer within the last week
.EXAMPLE
Get-MyWBSummary -ComputerName $server1, $server2 -Last 1 -Credential $credential -ErrorAction SilentlyContinue -ErrorVariable sessionErrors
Retrieves the last (newest) Windows Server Backup backupversion from remote servers $server1 and $server2
.NOTES
Written by Anders Præstegaard (#aPowershell).
Version 1.0 (20-01-2016)
#>
[CmdletBinding()]
[OutputType([PSCustomObject])]
param
(
[string[]]$ComputerName = $env:COMPUTERNAME,
[System.Management.Automation.PSCredential]$Credential,
[int]$Last
)
begin
{
if ($Credential)
{
$PSDefaultParameterValues['New-PSSession:Credential'] = $Credential
}
$psSession = New-PSSession -ComputerName $ComputerName
}
Process
{
$scriptBlock = {
if (-not (Test-Path -Path 'C:\Windows\System32\wbadmin.exe'))
{
## Windows Server Backup not installed
continue
}
$content = WBAdmin.exe GET VERSIONS
if (-not $content)
{
## no versions found
continue
}
## Get linenumbers for each entity
$newJobLines = #($content | Select-String -Pattern 'Backup time: ')
if ($Using:Last -and $using:Last -lt $newJobLines.Count)
{
$newJobLines = $newJobLines[- $using:Last.. -1]
}
$newJobLines |
ForEach-Object{
## Location
$lineNumberLocation = $_.LineNumber
$backupLocation = $content[$lineNumberLocation] -replace 'Backup location: '
## Version Identifier
$lineNumberVersionIdentifier = $_.LineNumber + 1
$backupVersionIdentifier = $content[$lineNumberVersionIdentifier] -replace 'Version identifier: '
## Backuptime UTC
# Version identifier string in WBAdmin output represents the UTC datetime formated in 'MM/dd/yyyy-HH:mm'
$wbAdminDateStringFormat = 'MM\/dd\/yyyy-HH:mm'
$backupDateTimeFromVersionIdentifier = [DateTime]::ParseExact($backupVersionIdentifier, $wbAdminDateStringFormat, $null)
$backupDateTimeUtcSpecified = [DateTime]::SpecifyKind($backupDateTimeFromVersionIdentifier, [System.DateTimeKind]::Utc)
# NB WBAdmin calculates the time statically compared to your timezone (ie +1 hour)
# If your timezone support "Daylight Saving Time" then WBAdmin calculation is wrong
# ~ half of the year (as far as I can perceive)
$backupDateTimeLocalTime = $backupDateTimeUtcSpecified.ToLocalTime()
## Can recover
$lineNumberCanRecover = $_.LineNumber + 2
$backupVersionCanRecover = $content[$lineNumberCanRecover] -replace 'Can recover: '
[PSCustomObject]#{
BackupTime = $backupDateTimeLocalTime
BackupTimeUtc = $backupDateTimeUtcSpecified
BackupLocation = $backupLocation
VersionIdentifier = $backupVersionIdentifier
CanRecover = $backupVersionCanRecover
}
}
} # Scriptblock
Invoke-Command -Session $psSession -ScriptBlock $scriptBlock |
Select-Object -Property * -ExcludeProperty RunspaceId
}
end
{
if ($psSession)
{
Remove-PSSession -Session $psSession
}
}
}

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