I'm quite new to batch files and I'm trying to do something decently advanced and am trying to figure out how to identify and parse the second line under DNS SERVERS in IPCONFIG /all. If the answer is quite advanced, I would appreciate it greatly if you could explain it thoroughly. Here is my code:
#echo off
setlocal enabledelayedexpansion
set adapter=Ethernet adapter Local Area Connection
set adapterfound=false
for /f "usebackq tokens=1-4 delims=:" %%f in (`ipconfig /all`) do (
set item=%%f
if /i "!item!"=="!adapter!" (
set adapterfound=true
) else if not "!item!"=="!item:DNS Servers=!" if "!adapterfound!"=="true" (
rem echo DNS: %%g
set Globaldns=%%g
set adapterfound=false
)
)
for /f "tokens=1-2 delims= " %%m in ("%Globaldns%") do set Globaldns=%%m
echo DNS: %Globaldns%
If someone has two DNS servers set, I need a way to pull the second DNS address and store it in a second variable, the code above is able to pull the first DNS but I have not figured out a way to pull the second. Thank you for your help!!
EDIT:
Another piece of information. This needs to be able to be run on anything from Windows Vista to Windows 10 and it needs to be able to target a specific connection (we are only reconfiguring Ethernet devices, no wireless) So we need to be able to use the adapter's connection name to parse (i.e. Local Area Connection,Ethernet).
LotPings is right, ipconfig output is difficult to parse. Parsing wmic output could be easier.
Take a look at Win32_NetworkAdapter class and Win32_NetworkAdapterConfiguration class and their wmic aliases NIC and NICCONFIG, respectively.
For the first identification, use wmic NIC get /VALUE. Note the /VALUE switch and notice the NetConnectionID property: name of the network connection as it appears in the Network Connections Control Panel program. Then, parse output from
wmic NIC where "NetConnectionID = 'Local Area Connection'" get Index, MACAddress
to get Index property (index number of the Windows network adapter configuration. The index number is used when there is more than one configuration available) value to a varible, e.g. _index and use it as follows:
wmic NICCONFIG where "Index = %_index%" get /Value
For easier parsing, you can narrow output to only desired properties and change format to csv, for instance
set "_properties=DefaultIPGateway,DHCPServer,DNSServerSearchOrder,IPAddress,IPSubnet"
wmic NICCONFIG where "Index = %_index%" get %_properties% /format:CSV
Please notice and apply Dave Benham's WMIC and FOR /F: A fix for the trailing <CR> problem.
Edit: fixed a mistake with path keyword:
NIC is a wmic alias for path Win32_NetworkAdapter
NICCONFIG is a wmic alias for path Win32_NetworkAdapterConfiguration
so e.g. next commands represent the same ˙WQL˙ query:
wmic NICCONFIG where "Index = %_index%" get /Value
wmic path Win32_NetworkAdapterConfiguration where "Index = %_index%" get /Value
Not a direct answer to the question but this powershell script might help, albeit I don't know if it will work back to vista.
gwmi Win32_NetworkAdapter -filter "netconnectionid is not null"|
%{ gwmi Win32_NetworkAdapterConfiguration `
-filter "interfaceindex=$([int]$_.interfaceindex)"|
select -expandproperty DNSServerSearchOrder}
As I have only one dns server configured my result is proper but meaningless.
Related
To get the drive the current batch resides in is easy using
set batchdrive=%~d0
But how is it possible to check if %batchdrive% is on a local drive and not on a (mapped) network share?
Checking for %SYSTEMDRIVE% or a fixed list "C:" "D:" ... is not reliable.
To check whether a drive (%~d0) is a local one, you could use a wmic query:
wmic LogicalDisk where(DeviceID="%~d0" AND DriveType=3) get Description,DeviceID,DriveType
Given that %~d0 expands to the local drive C:, the output looks like:
Description DeviceID DriveType
Local Fixed Disk C: 3
In case %~d0 is a network drive Z:, the error output is:
No Instance(s) Available.
Unfortunately, wmic does not set the ErrorLevel in case of no matches, but the above message is returned at the STDERR stream rather than the STDOUT stream, so we can apply redirection to discard STDOUT (in case the drive matches; so the get query is omitted as it is not used anyway) and redirect STDERR to STDOUT instead (so the error message is returned at STDOUT in case):
2>&1 > nul wmic LogicalDisk where (DeviceID="%~d0" AND DriveType=3)
Hence the command line returns nothing in case %~d0 is a local drive, but something otherwise. Now let us capture the (redirected) STDOUT by a for /F loop:
for /F "delims=" %%L in ('
2^>^&1 ^> nul wmic LogicalDisk where ^(DeviceID^="%~d0" AND DriveType^=3^)
') do echo Drive "%~d0" is not local!
So if %~d0 points to a local drive, the body of for /F is not executed, but otherwise it is.
According to this resource, WMI and therefore the wmic command line tool is available since Windows XP (Prof.) onward; it was not available on Windows XP Home though. wmic does not require administrative privileges. The Win32_LogicalDisk class is available since availability of WMI. Reference the following resources for more information about WMI/wmic: Windows Management Instrumentation: Frequently Asked Questions and WMIC - Take Command-line Control over WMI.
The first thing to check is if batchdrive is an unmapped network share (this happens if you start the batch file outside of cmd.exe, for example via double click or via a system call):
if "%batchdrive%" == "\\" set nshare=1
The second thing is to check if batchdrive is in the list of network shares. These are shown with net use, which output is similar to
status local remote network
-------------------------------------------------------------------
OK D: \\computer1\share1 Microsoft Windows Network
OK E: \\computer1\share2 Microsoft Windows Network
disconnected F: \\computer2\share Microsoft Windows Network
Command executed successfully.
Therefore we filter the output for all lines that looks like a disk drive with findstr /r /c:" [A-Z]: " and took the second part of the output via for /f "tokens=2".
Complete snipped (working on WinXP and above):
if "%~d0" == "\\" (
set nshare=1
) else (
set nshare=0
for /f "tokens=2" %%a in ('net use ^| findstr /r /c:" [A-Z]: "') do (
if "%%a" == "%~d0" set nshare=1
)
)
Comments for possible issues requested :-)
I need to deploy windows images to several computers that came with Windows 8.1.
I did manage to inject drivers and updates and some necessary softwares to the installation image, but somehow it seems that just installing Windows won't activate the operating system, and I have to find the license keys embedded in the BIOS and activate them manually.
I found out that wmic path softwarelicenseingservice get oa3xoriginalproductkey could be used to extract the product key from the bios, and I am thinking about composing a batch file that uses this command in joint with slmgr -ipk and slmgr -ato, and then make it run as the firstlogon command.
The trouble is that I don't know a lot about batch syntax, and I am having a hard time assigning the product key as a variable and passing it over to slmgr commands.
It seems that the wmic command returns the result as:
OA3xOriginalProductKey
XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
<blank line>
So there it returns the product key in a three line text, with the actual useful information sandwiched between other strings. How can I just get the middle(or second) line from this text and assign it as a variable?
Maybe this will work for you. Note it does involve a temporary text file.
wmic path softwarelicenseingservice get oa3xoriginalproductkey > temp.txt
3<temp.txt (
set /p var= <&3
set /p var= <&3
)
del temp.txt
Echo %var%
Which will always extract the second line of output from the command.
I have tested this with the data you provided and it outputted XXXXX-XXXXX-XXXXX-XXXXX-XXXXX. TO access this variable always refer to it as %var%.
Here's how i would do it
Logon scripts accept powershell scripts which has much more features and strength in it than the old batch files.
$key = Get-WmiObject -Class SoftwareLicensingService |
Select-Object OA3xOriginalProductKey | foreach { "{0}" -f $_.OA3xOriginalProductKey }
with this command, you get your ProductID into the $key variable and free to do any manipulation you'd like with it
cscript.exe C:\Windows\System32\slmgr.vbs /upk
cscript.exe C:\Windows\System32\slmgr.vbs /cpky
for /f "tokens=2 delims='='" %%K IN ('wmic path softwarelicensingservice get OA3xOriginalProductkey /value') do set pk=%%K
cscript.exe C:\Windows\System32\slmgr.vbs /ipk %pk%
cscript.exe C:\Windows\System32\slmgr.vbs /ato
cscript.exe C:\Windows\System32\slmgr.vbs /dli
save this as batch file and try
This is what I needed.
It works perfect.
for /f "tokens=2 delims='='" %%K IN ('wmic path softwarelicensingservice get OA3xOriginalProductkey /value') do set pk=%%K
slmgr.vbs /ipk "%pk%"
slmgr.vbs /ato
When I do a "net use" on my command prompt, it will display the following:
New connections will be remembered.
Status Local Remote Network
-------------------------------------------------------------------------------
OK W: \\hfs2\ATS\Novell Profile Backup\wk\one\two\three\four\five\six\seven\eight\nine\ten\eleven\twelve\thirteen
Microsoft Windows Network
OK X: \\hfs2\ATS\Novell Profile Backup\wk\one\two\three\four\five\six\seven\eight\nine\ten
Microsoft Windows Network
OK Y: \\hfs2\ATS\Novell Profile Backup
Microsoft Windows Network
Unavailable Z: \\hfs2\ATS Microsoft Windows Network
The command completed successfully.
How do I extract ONLY get the drive alphabet and pathname?
W:
\\hfs2\ATS\Novell Profile Backup\wk\one\two\three\four\five\six\seven\eight\nine\ten\eleven\twelve\thirteen
X:
\\hfs2\ATS\Novell Profile Backup\wk\one\two\three\four\five\six\seven\eight\nine\ten
Y:
\\hfs2\ATS\Novell Profile Backup
Z:
\\hfs2\ATS
EDIT
WMIC does not require administrator rights
It does require rights for what you are trying to do. You can't use it to do admin things if not an admin.
It also requires an administrator to run it once on a system to set it up.
From Help
User Account Control
Under UAC, accounts in the local Administrators group have two access tokens, one with standard user privileges and one with administrator privileges. Because of UAC access token filtering, a script is normally run under the standard user token, unless it is run "as an Administrator" in elevated privilege mode. Not all scripts required administrative privileges.
Scripts cannot determine programmatically whether they are running under a standard user security token or an Administrator token. The script may fail with an access denied error. If the script requires administrator privileges, then it must be run in the elevated mode. Access to WMI namespaces differs depending on whether the script is run in elevated mode. Some WMI operations, such as getting data or executing most methods, do not require that the account run as an administrator. For more information about default access permissions, see Access to WMI Namespaces and Executing Privileged Operations.
Wmic
The first time you run Wmic after system installation, it must be run from an elevated command prompt. The elevated mode may not be required for subsequent executions of Wmic unless the WMI operations require administrator privilege.
Use WMIC
wmic netuse get /format:list
gives you what's available.
Use something like
wmic netuse get remotepath, localname /format:list
To put the output in a file or on the clipboard.
WMIC specific switch
/output or /append
eg
wmic /node:"#%userprofile%\desktop\ComputerName.txt" /output:"%userprofile%\desktop\EventLog.html" /failfast:on PATH Win32_NTLogEvent where (EventIDentifier=42 or eventidentifier=1003) get /format:hform
(/node is a list of IP addresses and/or computer names of computers to run the command against, one IP address or computer name per line)
General Command Prompt File Redirection
Appending >filename.ext (or >>filename.ext to append to a file)to a command writes the output to the file rather than the screen.
wmic baseboard get product,Manufacturer,model,partnumber>MotherboardPartNum.txt
General Command Prompt Piping
Appending |command sends the output to a command rather than the screen. The usefull commands that output is sent to are
find or findstr (finds and filters text)
sort (sorts the output)
more (displays output to screen one page at a time)
clip (puts output onto the clipboard)
null (makes the data disappear for good - used for unwanted error messages)
wmic baseboard get product,Manufacturer,model,partnumber|clip
Combining Piping and Redirection
So we can combine them. To send the list to a file on the desktop in reversed sort order (z to a) with blank lines removed.
wmic service get name,displayname /format:list|findstr .|sort /r>"%userprofile%\desktop\services_reversed.txt"
WMIC Output Options
The output options are
/Format:list (a list - use notepad to view)
/format:table (a table - use notepad to view)
/format:hform (an html list - name the file's extension .html so IE will show)
/format:htable (an html table - name the file's extension .html so IE will show)
/format:csv (comma seperated variable - used for importing data into other programs such as excel)
also value, mof, rawxml, and xml.
So,
sort /?
find /?
findstr /?
more /?
clip /?
There are some problems in the output of net use
The Status field can hold information or be empty.
The Network field can have multiple values depending of network mapping. In my case i have "Microsoft Windows Network" and "Netware Services". So, there is no direct substitution.
The Network field can be in the same line that the Remote field or can be on the next line, and as the Remote field may include spaces, checking the character at the column limit position is not reliable. It is necessary to delay the check until the next line is readed to determine if it contains remote data.
So, not a one liner to handle it
#echo off
setlocal enableextensions disabledelayedexpansion
set "drive="
for /f "skip=6 tokens=1,* delims=\" %%a in ('net use') do (
if defined drive (
setlocal enabledelayedexpansion
if "%%b"=="" (
echo !drive! !networkPath!
) else (
echo !drive! !networkPath:~0,26!
)
endlocal
set "drive="
)
if not "%%b"=="" for /f "tokens=2" %%c in ("x%%a") do (
set "drive=%%c"
set "networkPath=\\%%b"
)
)
%%a loop will read the lines from net use and split them using a backslash as delimiter. This will allow us to determine if the line contains or not a network path (if there is no second token, the line did not contain a backslash).
As we are delaying the output of the information in one line until the next is readed (to determine if the remote path continues in the Network column), the first operation inside the for loop is to determine if we have data pending from previous loop. If there is data, depending on the content of the current line we select what to output.
Once the data is echoed, if the current line contains network information, it is saved for later output.
This is the faster solution, but there are two alternatives that require less code:
multiple net use commands
#echo off
setlocal enableextensions disabledelayedexpansion
rem For each line in the output of the net use that includes a drive letter
for /f "delims=" %%a in ('net use^|find ":"') do (
rem Retrieve the drive letter from the line
for /f "tokens=2" %%b in ("x%%a") do (
rem Run a net use with the drive letter and output the drive and the path
for /f "tokens=1,* delims=\" %%c in ('net use %%b') do if not "%%d"=="" echo(%%b \\%%d
)
)
Less code, but as multiple net use commands are executed, it is slower
Use WMIC
#echo off
setlocal enableextensions disabledelayedexpansion
for /f "tokens=2,3 delims=," %%a in (
'wmic netuse get LocalName^, RemoteName^, Status /format:csv ^| find ":"'
) do echo(%%a %%b
Less code, but in this case, adminitrator righs are required to run the command
I might be a little late but this helped me
WMIC NETUSE GET LocalName, RemotePath /FORMAT:TABLE | FIND /i ":"
I've written a Windows script to change NIC interface metrics, and need to condense it to two commands, because of the manner in which it is executed. To render a long story short, I support an application (BladeLogic Server Automation [BSA]) that uses remote agents to call system commands.
I've hypothesized that when BSA runs the script, each command executes in a separate Command Prompt environment, so the environment variables used to store the route strings aren't persistent.
for /f "delims=" %a in ('netsh interface ipv4 dump ^| find "nexthop=1.1.1.1"') do #set VAR1=%a
netsh interface ipv4 set %VAR1:~4% metric=200
for /f "delims=" %a in ('netsh interface ipv4 dump ^| find "nexthop=2.2.2.1"') do #set VAR2=%a
netsh interface ipv4 set %VAR2:~4% metric=500
I've condensed the script as such and am testing it at the Command Prompt.
for /f "delims=" %a in ('netsh interface ipv4 dump ^| find "nexthop=1.1.1.1"') do #set VAR1=%a && netsh interface ipv4 set %VAR1:~4% metric=200
for /f "delims=" %a in ('netsh interface ipv4 dump ^| find "nexthop=2.2.2.1"') do #set VAR2=%a && netsh interface ipv4 set %VAR2:~4% metric=500
Unfortunately, it doesn't seem to recognize the proper syntax for the second command:
The following command was not found: interface ipv4 set %VAR1:~4% metric=200
Is there another way I could append the second command, so it's interpreted as being syntactically correct? I'm open to suggestions!
Matt,
You're correct that BladeLogic fires up separate shells for each statement, however, depending on what you're trying to achieve, it may be possible to "persuade" it to run a complete script remotely on your target.
If you're still facing this issue, please respond with a little more info about what you're trying to achieve and which approaches you've tried, and we can look a the alternatives.
-John.
I have a script that is run over a network, with VPN being the same as a LAN environment.
The script previously worked fine, as we had variables that stored the username and password for the administrator. However, due to a recent change, when we map a drive over the network and whatnot, the machine name is now needed in front of the administator username, E.g. machinename2343\administrator.
What I would like to do is take an existing command - perhaps such as nbtstat - and after entering the ip address, have the program pull the machine name and insert it into a variable.
I have found that Nbtstat can give me the machine name, but provides large amounts of unnecessary information for my task. Is there a way to filter out just the machine name in a reliable and consistent manner, or is there perhaps another network related command that perform in the same capacity?
`#echo off
FOR /f "tokens=1* delims= skip=23 " %%a IN ('nbtstat -a IPADDRESS) DO (
SET VARIABLE=%%a
GOTO Done
)
:Done
echo Computer name: %VARIABLE%`
You could do ping /a. The computer name is resolved. And this computer name is the second token. I haven't taken care of Error checking. I believe you could implement that yourself.
Try this:
#ECHO OFF
FOR /f "tokens=2* delims= " %%a IN ('PING -a -n 1 IPADDRESS') DO (
SET Variable=%%a
GOTO Done
)
:Done
echo Computer name: %Variable%
Put this in your batch file where it would fit.
You could just use the %computername% environment variable.
When I first read your post I thought you were running the batch file remotely on each machine. If that were the case having %computername% in the batch file would work, because when the batch file is executed remotely %computername% would be expanded based on the remote machine's environment variable not the local machine.
Looking back on it, it's still not very clear, but based on your comment I assume the batch file is running locally and then connecting to a set of machines to perform some operation(s).
You could use tool the WMI command-line tool to get the computer name. The solution would look similar to #Thrustmaster's, but I think it's a little cleaner since the output of wmic, in this case, does "filter out just the machine name in a reliable consistent manner." Of course you'd replace the 127.0.0.1 with the ip you want to query.
#ECHO OFF
FOR /F "tokens=*" %%A IN ('wmic /node:127.0.0.1 ComputerSystem Get Name /Value ^| FIND "="') DO (
SET COMP.%%A
)
ECHO %COMP.NAME%