Friday, January 10, 2014

Sysprep and Domain Join Over Wireless


We all know that there's a host of different ways and technologies available to mass deploy PCs, but thought I'd go over what I've recently done to prep a roll-out of new laptops for my organization. My main objective was to get these set up and configured on the wireless- no hard wires! So that will be my focus of this post.

These will be win 7 units, so sysprep is involved. Although we are a MS shop, we have not used WDS and MDT to any real extent. Still sticking to Ghost, being that we have a heavy investment of ghost images already.

Since I wanted the machines to join one of our SSIDs automatically at post image startup- this is what I came up with.

First, you join a machine to the SSID of choice, and use the Netsh wlan command to export your WLan profile to a config file

A great resouce for the syntax and options can be found here: http://technet.microsoft.com/en-us/library/cc755301(v=ws.10).aspx#bkmk_wlanExportProf

   netsh wlan export profile folder= "C:\Wireless\MyWlanProfile.xml"

You can check existing profiles you have with the show profiles command

   netsh wlan show profiles

Now you have your exported xml file that looks something like this:

<?xml version="1.0" ?>
- <WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
  <name>MyWlanProfile</name>
- <SSIDConfig>
- <SSID>
  <hex>545053204C414E</hex>
  <name>MySSID</name>
  </SSID>
  </SSIDConfig>
  <connectionType>ESS</connectionType>
  <connectionMode>auto</connectionMode>
- <MSM>
- <security>
- <authEncryption>
  <authentication>WPA2PSK</authentication>
  <encryption>AES</encryption>
  <useOneX>false</useOneX>
  </authEncryption>
- <sharedKey>
  <keyType>passPhrase</keyType>
  <protected>false</protected>
  <keyMaterial>yourSSIDKey</keyMaterial>
  </sharedKey>
  </security>
  </MSM>
  </WLANProfile>

What you'll need to do is change your very long WPA2 key material string to the clear text key that matches your pass phrase. And...change the protected tag to false. Reason being, after importing the file,  you won't be able to connect on a different laptop other than the one you originally created the file on. And actually, that didn't even work for me. Obviously, your WPA2 phrase sitting around in clear text is not desirable..so we'll take care of that later in the process.

Next, I placed my xml file in a folder on the c drive of my imaging model laptop. I simply restricted access to the folder and xml file to only the system and administrator accounts- no access for anything else.

Now- -to import your file at the miniset up after you've modeled your image unit and ran sysprep, you can use the FirstLogonCommands as shown below. You'll have 2 netsh wlan lines- one to import the Profile from the profile xml file your exported earlier, and one to connect to your SSID.

 <FirstLogonCommands>
       <SynchronousCommand wcm:action="add">
                    <CommandLine>netsh wlan add profile filename="C:\wireless\MyWlanProfile.xml
</CommandLine>
                    <RequiresUserInput>false</RequiresUserInput>
                    <Order>1</Order>
                    <Description>Add MyWLanProfile</Description>
                    </SynchronousCommand>
<SynchronousCommand wcm:action="add">
                    <CommandLine>netsh wlan connect name="MySSID"</CommandLine>
                    <RequiresUserInput>false</RequiresUserInput>
                    <Order>2</Order>
                    <Description>Connect MyWLanProfile Profile</Description>
</SynchronousCommand>
   </FirstLogonCommands>

I have an auto login directive in my unattend.xml file- the machine will login as the local administrator and the FirstLogonCommands will execute before the desktop is presented.

Now...what if you want to join the domain, or activate windows etc at mini-setup? Well you could put those commands here in the above FirstLogonCommands of your unattend.xml right? Well, they won't work. Not if your only network connection is the Wlan. The thing is, even though the Netsh commands are executed before the desktop appears, the wireless network connection does not connect until the desktop is loaded...which is well after the FirstLogonCommands execute. At least this was my experience.

And what about the %WINDIR%\Setup\Scripts\SetupComplete.cmd that mini-setup will execute if it exists? Same thing-- it executes too early- before the WLan is connected.

What I did was add a setupcomplete.cmd file to the Startup folder of the local administrator account as I was modeling the image unit.....pre-sysprep. (Path below on Win7)

  "%userprofile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\startup

With the script in the Startup folder, it will get execute AFTER the desktop sets up- which is what we want. Below is my file....I added ping delays to slow down the script down in places....giving it time to get the WLan connected before executing commands that are dependent on the network.

echo off
echo 30 Second Delay
ping 1.1.1.1 -n 1 -w 30000 >NUL
echo.
echo.
echo Join Domain
netdom.exe join %computername% /Domain:yourdomain.com /UserD:user1 /PasswordD:password
echo.
echo.
echo Activate Windows
ping 1.1.1.1 -n 1 -w 5000 >NUL
cscript c:\windows\system32\slmgr.vbs /ato
echo Activate Office
ping 1.1.1.1 -n 1 -w 5000 >NUL
cscript "c:\Program Files (x86)\Microsoft Office\Office14\ospp.vbs" /act
echo.
echo.
echo "Note: If setup script is not deleted from the Startup folder of the Default user profile
echo "for whatever reason, it will get copied to, and run on all subsequent user logins!"
echo.
echo.
ping 1.1.1.1 -n 1 -w 7000 >NUL
echo Remove Startup Scripts and Restart
shutdown -r -t 60
echo Deleting SetupComplete.cmd from Default Profile
ping 1.1.1.1 -n 1 -w 5000 >NUL
del "C:\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\*.*" /F /Q
echo Deleting MyWlanProfile.xml
ping 1.1.1.1 -n 1 -w 5000 >NUL
del C:\wireless\MyWlanProfile.xml /F /Q
echo Deleting SetupComplete.cmd from Current Profile
ping 1.1.1.1 -n 1 -w 5000 >NUL
del "%userprofile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\startup\*.*" /F /Q
Exit

Some things to note: I use Netdom to join the domain- I could never get my unattend.xml to do it-- even with a wired connection.

You'll want to have those delete lines at the end to cover your tracks so to speak and get rid of the sensitive setup files from prying eyes. The last one being the SetupComplete.cmd file itself

Saturday, January 4, 2014

SIP SoftPhone Registration with Cisco CME


   This I'm sure this is no revelation to seasoned Cisco voice engineers, but for those just building their skills, I wanted to put out a little how to for attaching and registering SIP softphones to your Cisco Call Manger Express router.

I've integrated many Cisco phones with CME using the native SCCP protocol- Cisco's native signaling and communications protocol otherwise known as Skinny for short.
Assuming all your prerequisite router\CME configurations are in place.... ie...interfaces, tftp-server phone loads files for your phone types, dhcp pool, telephony-service entries etc..... you would add the MAC address of the SCCP phone under the corresponding ephone section of your router config...like so

ephone  1
 mac-address 0021.A075.D474
 after-hours exempt
 paging-dn 30
 type 7941
 button  1:1 2:21
 pin 1111

This ephone would have a matching ephone-dn section to define the line for the ephone (or skinny phone)...like this:

ephone-dn  1  dual-line
 number 1001
 label Tony Montana
 name Tony Montana

But SIP phones require similar configurations under similar sections, but with different syntax.


First you need to allow sip to sip connections under voice service voip

voice service voip
 allow-connections sip to sip

Also...do not forget this part--as I did! You need to turn on the registrar for SIP...so the sip phones have something to register to. Add this to your voice service voip section

sip
registrar server expires max 600 min 60  turns on the SIP registrar! 

Next you'll add your global configuration lines under voice register global- this would be similar to the telephony-service section used for SCCP phones


voice register global
mode cme
source-address 192.168.0.254 port 5060
max-dn 5
max-pool 5
authenticate register  optional for remote phones- digest authentication is used-
don't use if you want to use MAC address authentication                                                                          
authenticate realm mydomain.local
timezone 13
voicemail 2222
tftp-path flash:
create profile sync 0025196614655748


Note the create profile command-this command builds the sip cnf and xml SIP phone files in the path specified by the tftp-path command above it.  The sync xxxxxxxx.. is appended automatically by the IOS. I'll come back to the authenticate register command later.

Now, you'll define your dn and line number with the voice register dn # command...like this

voice register dn 1
number 1041
allow watch
name 3cxOffice
label 3cxOffice
mwi


Next, you'll tie the actual phone to the DN with the


voice register pool 1
id mac 0000.0000.0000 Not relevant when using digest authentication- if not, put actual MAC here
number 1 dn 1
presence call-list
dtmf-relay rtp-nte
username 1041 password cisco   Digest Authentication
codec g711ulaw


Now...if you use the authenticate register option in your global settings (see above), you will NOT be able to authenticate your phone via mac address as you normally would a SCCP phone. This option makes the id mac line your voice register pool section irrelevant. This, from what I understand, tells your phone to use Digest Authentication...hence the user name and password. This would normally be used for remote phones- phones not connected on the same lan....due to ARP not passing the MAC of the remote device across routers- makes sense! An excellent explanation can be found here: thanks to the author )



So,,,there you have it. If all is straight, you should see your SIP phones register now. You can check it with this command- you would see similar to the output below

show sip status registrar

Line          destination      expires(sec)  contact
transport     call-id
             peer
============================================================
1041          192.168.0.38     85            192.168.0.38
UDP           YTE0MTBjNjk0YTVhZDFiNWQ2NzEwMjk5MWE0Nzg0NWM.
             40001

Or, you can check them like this too:

show voice register dial-peer

Dial-peers for Pool 1:
dial-peer voice 40001 voip
destination-pattern 1041
session target ipv4:192.168.0.38:64375
session protocol sipv2
dtmf-relay rtp-nte
codec  g711ulaw bytes 160
 after-hours-exempt   FALSE

Wednesday, January 1, 2014

Exchange 2013 Public Folder Migration- PublicFolderToMailboxMapGenerator.ps1 script Error


   When migrating our public folders to Exchnage 2013, from 2007....I came across a little oddity. An oddity? From Microsoft? How can that be!! Public folder migration is well documented online...so I won't rehash that. I used the Technet guide found here:


So you basically download and run the various scripts as outlined from the Exchange Shell. After you've run the PublicFolderToMailboxMapGenerator.ps1 script:

.\PublicFolderToMailboxMapGenerator.ps1 <Maximum mailbox size in bytes> <Folder to size map path> <Folder to mailbox map csv path>

And created the actual PF Mailboxes on your Exchange 2013 server (a single PF mailbox sufficed for our environment) with this command...

New-Mailbox -PublicFolder PFMailboxName -HoldForMigration:$true -Database MailboxDatabaseName

You'll want to open and edit the PF mailbox name in the csv file you just created with the PublicFolderToMailboxMapGenerator.ps1 script. Make the PF mailbox name or names match the the name(s) of the actual PF Mbxs you created. Sounds easy enough.... well, when I did this, and saved the the file, and then ran the migration request command next as such... (which references the PFFoldertoMailbox map csv file)

New-PublicFolderMigrationRequest -SourceDatabase (Get-PublicFolderDatabase -Server <Source server name>) -CSVData (Get-Content <Folder to mailbox map csv path> -Encoding Byte) -BadItemLimit $BadItemLimitCount

I ended up receiving an error and the migration would not kick off. Turns out that Excel botched the file syntax ever so slightly for whatever reason...or maybe the script itself did. Took me some time to notice.... so take note of this if you get this behavior. Your FFoldertoMailboxMap csv file should look like this:


"FolderPath","TargetMailbox"

"\","PFMailbox1"



My PFmailbox name being PFMailbox1. I made the change using Notepad++ or similar this time..saved it...and re-ran the migration command. All was fine after...


Happy migrating!