Showing posts with label Windows Imaging. Show all posts
Showing posts with label Windows Imaging. Show all posts

Friday, June 10, 2016

PowerShell & Google Maps Time Zone API: Check and Change Computer Time using Internet Time

I've been using WinPE to install images on new PC's and found that since Dell computers come from Texas, the Time Zone and PC clock time needs to be updated to my Time Zone. I'm probably over complicating this process but thought I'd share this anyway:

#Google's time variable is based on the start date/time of 1/1/1970, universal time zone
$startdatetime = [datetime]"1/1/1970 00:00:00Z"

#getting local time and converting to universal time zone
$currentdatetime = (get-date).touniversaltime()

#Google time variable takes the 1/1/1970 date and wants the total seconds from that date to current time
[int]$totalseconds = ($currentdatetime - $startdatetime).totalseconds

#get a server key by signing up for the Google Maps Time Zone API 
#read more here
#note: location just has to be somewhere in your area/time zone
$timezone = invoke-restmethod ("https://maps.googleapis.com/maps/api/timezone/json?location=46,-122" + "&Timestamp=" + $totalseconds + "&key=")
$timezonename = $timezone.timezonename

#since I live in Washington, I have the two possible time zones. Obviously you'll want to add/change time zones based on your location(s).
if ($timezonename -eq "Pacific Daylight Time"){$TZDiff = -7}
if ($timezonename -eq "Pacific Standard Time"){$TZDiff = -8}

#Now I'm pulling local timezone information
$tz = ([timezoneinfo]::local).id
write-host "Local Timezone setting: $tz"

#creating a variable in case the timezone is incorrect
#The ref'd timezone.ps1 script is from Peter Henchley's blog
$changetime = "e:\scripts\timezone.ps1 $timezonename"
if ($tz -ne $timezonename){powershell -executionpolicy bypass $changetime;write-host "Changed Timezone" -f yellow}

#Once the time zone has been adjusted, now we check for time
#We pull current time from www.timeapi.org, convert it to universal time, and add our time zone difference so it equals our current time zone
$webtime = (([datetime](iwr http://www.timeapi.org/utc/now -usebasicparsing).content).touniversaltime()).addhours($TZDiff)
$localhour = (get-date).hour
if ($localhour -ne $webtime.hour){set-date $webtime;write-host "Changed Local Time" -f yellow}

An example of a Google Map Time Zone API reply

dstOffset    : 3600
rawOffset    : -28800
status       : OK
timeZoneId   : America/Los_Angeles
timeZoneName : Pacific Daylight Time

Let me know if you know of a better method of checking for time zones and time without using local computers or domain servers.

Sunday, May 22, 2016

PowerShell & SCCM 2012: Get Old Computer SCCM Software Packages, add more software, and Export CSV out for New Computer

Using PowerShell and WMI to access the SCCM server, this post shows how to transfer a software list from the old computer and export it for the new one. In another post I describe how to automate the new computers software package collection addition process after its registered itself with the SCCM server and installed the SCCM client software.

$SCCMserver = SCCMServer01
$namespace = "root\sms\site_xx1"
$adminname = "Domain\AdmUser"
$password = get-content .\adminpassword.txt|convertto-securestring -key (1..16)
$admcred = new-object system.management.automation.pscredential($adminname,$password)
$i = 0

$OldComputerSoftware = Get-WmiObject -Namespace $namespace -Class SMS_fullcollectionmembership -ComputerName $SCCMServer -filter "Name = '$SCCMoldcomputer'" -credential $admcred
$OldComputerCollectionMemberList = $CollectionList|? {$OldComputerSoftware.collectionID -contains $_.collectionID}

Above I declare my variables, query the SCCM server for all the software on the old computer, and compare it to the $CollectionList collections filtering array. Next I create $NewPCSoftwareList using the old computer software list. Add line numbers and filter unwanted collections via $XList. The $AddedSoftware variable displays the existing software from the old computer and will be updated with software selections in the read-host menu below:

$NewPCSoftwareList = $OldComputerCollectionMemberList|select Name,CollectionID
foreach ($C in $NewPCSoftwareList){$i++;$C|add-member -notepropertyname line -notepropertyvalue $i}
$NewPCSoftwareList = $NewPCSoftwareList|? {$xlist.name -notcontains $_.name}
$addedsoftware = $collectionlist|? {$NewPCSoftwareList.name -contains $_.name}


Available SCCM Software Packages
 1 Adobe Acrobat Pro
 2 Adobe Acrobat Standard
 3 Base Camp
 5 Topography Software
 6 Google Earth Pro
 7 Windows Mobile Device Center

OldComputerName SCCM Software will be installed on NewComputerName 

 4 7-Zip
 8 Microsoft Office 2013

Enter line number to add SCCM software to NewComputerName
Enter DONE if satisfied with install list
(Line number or Done): _


do{
cls
write-host "Available SCCM Software Packages" -f white
$collectionlist|? {$InstalledSoftwareList.name -notcontains $_.name}|format-table line,name
write-host "SCCM Software already installed on $computername" -f white
$InstalledSoftwareList|format-table line,name -hidetableheaders
if ($newsoftware){
write-host "Software to be added" -f yellow
$newsoftware|format-table line,name -hidetableheaders

}
write-host "Enter " -nonewline;write-host "line number" -f white -nonewline;write-host " to add SCCM software to $computername"
write-host "Enter " -nonewline;write-host "DONE" -f white -nonewline;write-host " if satisfied with install list"
$addpackages = read-host "(Line number or Done)"
if ($addpackages -ne "done"){
$newsoftware += $collectionlist|? line -eq $addpackages
}
} while ($addpackages -ne "done")
The starting menu displays the full available software list minus those software already pre-selected to be added to the new computer. I input the number for each additional software I want added to the new computer then type DONE when finished adding software. Note that the line numbers disappear from the top list when selected on the bottom one. After DONE is typed, the $addedsoftware array gets exported to a CSV that the new computer will access in order to install that software. That part of the process will be in another post.

if ($addedsoftware){$addedsoftware|export-csv .\NewComputerName-SCCMsoftware.csv}

PowerShell & SCCM 2012: Retrieving and Filtering Collections

In order to expedite my computer replacement process, I decided to automate the software transfer from the old computer to the new one. This post goes over the first part of that process. I thank the many great people that have posted how to retrieve information from SCCM via WMI. I built upon their success and customized it for my needs. In this first snippet, I declare my variables, poll the SCCM server, then query the SCCM server for all its collections ($CollectionList). I also import my collection filtering CSV file ($xlist).

$SCCMserver = SCCMServer01
$namespace = "root\sms\site_xx1"
$adminname = "Domain\AdmUser"
$password = get-content .\adminpassword.txt|convertto-securestring -key (1..16)
$admcred = new-object system.management.automation.pscredential($adminname,$password)
$i = 0

if (test-connection $SCCMServer){
$xlist = import-csv \\server\share\SCCMscripts\CollectionFilter.csv
$CollectionList = get-wmiobject -query "Select * from SMS_Collection" -namespace $namespace -computername $SCCMserver -credential $admcred
$CollectionList = $CollectionList|? {$xlist.name -notcontains $_.name}
foreach ($C in $CollectionList){$i++;$C|add-member -notepropertyname line -notepropertyvalue $i}
}

With the above, I've filtered through the complete collection list using my collection filtering CSV, added a new array property named line, and have run the resulting list through a line numbering loop so I can present the collection list for further filtering as in the example below.

Available SCCM Software Packages
 1 Adobe Acrobat Pro
 2 Adobe Acrobat Standard
 3 7 Zip
 4 Google Earth
 5 AutoCAD LT

Enter software package line number to remove from availability list
Enter NONE if no changes are needed
(Line number or NONE:): 5
Available SCCM Software Packages - Updated
 1 Adobe Acrobat Pro
 2 Adobe Acrobat Standard
 3 7 Zip
 4 Google Earth

Enter software package line number to remove from availability list
Enter NONE if no changes are needed
(Line number or NONE:): NONE

In the above example, my filtered $CollectionList displayed five software packages. I typed in number 5 to remove AutoCAD LT from my software list, press Enter, and the list now only has the four remaining packages. Once finished updating the software list, I will use the filtered list to apply against the old computer's software list. This helps me select software for its replacement without wading through all the other arbitrary collections and packages. I'll show that software selection process in another post.

do{
if (!($remove)){write-host "Available SCCM Software Packages" -f white}
if ($remove){write-host "Available SCCM Software Packages" -f white -nonewline;write-host " - Updated" -f green}
$CollectionList|format-table line,name -hidetableheaders
write-host "Enter software package " -nonewline;write-host "line number" -f white -nonewline;write-host " to remove from availability list"
write-host "Enter " -nonewline;write-host "NONE" -f white -nonewline;write-host " if no changes are needed"
$addtoxlist = read-host "(Line number or NONE)"
if ($addtoxlist -ne "none"){
[array]$remove += $CollectionList|? line -eq $addtoxlist|select name,collectionID
$CollectionList = $CollectionList|? {$remove.name -notcontains $_.name}
}
} while ($addtoxlist -ne "none")

After "None" is typed, the $remove list is applied to $xlist then exported back out to the filter list.

if ($remove){
$xlist = $xlist|select Name,CollectionID #removing the line number object
$xlist += $remove|select Name,CollectionID #adding the selected collection items to the filter list
$xlist = $xlist|sort CollectionID -unique #removing duplicate entries
$xlist|export-csv \\server\share\SCCMscripts\CollectionFilter.csv}

Friday, February 8, 2013

PowerShell: Post-SysPrep scripts to Rename & Add Computer to Domain (using alternate credentials)


I tasked myself with the mission of using Microsoft's Windows 8 ADK to create a bootable Windows PE 4.0 UFD, and save a sysprepped workstation hard drive image (.wim) to the UFD. The UFD's WinPE boot sequence would have a PE-hooked batch file in which the user presses one button, walks away for 20 - 30 minutes and returns to a new PC which is on the Domain, in the correct OU, and has all its drivers loaded and GPO's applied.  The renaming and Domain adding portion of this process involved PowerShell's access to the win32_computersystem rename command and Add-Computer.

On my first attempt, I tried to rename the computer and add it to the domain during one boot. It just didn't work.  I had to reopen the pre-sysprep image and change the unattend.xml sysprep file's administrator login count from 1 to 2.  So the first boot checks then changes the computers name and places a RunOnce registry entry to kick off the second half of the process.  The second boot checks the computers name and if it is changed, grabs the IP address and starts a Add-Computer command associated with the OU of the corresponding IP subnet.

The PowerShell script during the first boot will create the computer name, add a regkey reboot hook, rename the computer, and restart it (it becomes passive during the second boot due to the computer name checks):

$ComputerName = ("Domain" + (gwmi win32_systemenclosure).SMBIOSAssetTag)

#A hook into the post-sysprep start script so it can be reran on next boot:

if ((gwmi win32_computersystem).name -ne $ComputerName){reg.exe add HKLM\Software\Microsoft\Windows\CurrentVersion\Runonce /v Restart /t REG_SZ /d "c:\scripts\start.bat" /f}

#Renaming the computer and restarting:

if ((gwmi win32_computersystem).name -ne $ComputerName){(gwmi win32_computersystem).rename($ComputerName);restart-computer}

#The second boot PowerShell script encrypts a domain user/pass, 
#determines the PC's IP subnet, then executes Add-Computer and 
#places the PC in the correct OU. Upon restart, kicks off GPUpdate at first Domain login.

#Saving the alternate Active Directory credentials:

$Username = "domain\delegateuser" 
$Password = convertto-securestring "secret" -asplaintext -force 
$Cred = new-object system.management.automation.pscredential($Username,$Password)

#Use ADSI to search for the computer object on the domain.  
#If one is found, add-computer with no OU is used.  If not then the script 
#finds the IP subnet and assigns the computers object to the appropriate OU


$searcher = [adsisearcher][adsi]""
$searcher.filter ="(cn=$ComputerName)"
$searchparm = $searcher.FindOne()
if (!($searchparm)){

#Checking the computer name then finding its IP subnet:

$ComputerName = ("Domain" + (gwmi win32_systemenclosure).SMBIOSAssetTag)
if ((gwmi win32_computersystem).name -ne $ComputerName){write "something went wrong with renaming the computer"|out-gr

idview;cmd /c pause}
$IP = [system.net.dns]::GetHostAddresses($env:computername)|?{$_.IPAddresstostring -like '192.168.*'}

#We've captured IP addresses to two octets and now find the 
#Active Directory Site via the third IP octet and perform the 
#add-computer command combined with the saved AD credentials and correct OU location:

if ($ip -like '192.168.0.*'){add-computer -domain MyDomain -Credential $cred -OUPath "OU=HQ,OU=WORKSTATIONS,DC=MyDomain,DC=COM"}
if ($ip -like '192.168.1.*'){add-computer -domain MyDomain -Credential $cred -OUPath "OU=Site1,OU=WORKSTATIONS,DC=MyDomain,DC=COM"}
if ($ip -like '192.168.2.*'){add-computer -domain MyDomain -Credential $cred -OUPath "OU=Site2,OU=WORKSTATIONS,DC=MyDomain,DC=COM"}

#closing the if statement concerning finding a computer object or not.
#The Else adds the computer to the domain and reattaching it to it's existing
#computer object

#Update 2/21/14
#I found it more efficient to take away the else statement and instead just create a catch-all:   add-computer -domain MyDomain -Credential $cred
#Another problem was re-imaging existing domain computers.  AD would try
#creating another GUID and cause GPO and other problems.  
#To fix this, I added:
start-process powershell.exe -credential $cred -argumentlist 'if (!(test-computersecurechannel)){test-computersecurechannel -repair}

#so if the computer is in the domain but not in one of the above mentioned subnets, it'll still be added to the domain.

}else{add-computer -domain MyDomain -Credential $cred}

#The computer is now a member of the Domain.  Next add a 
#Registry RunOnce key entry so the next boot will start a 
#forced application of GPUpdate relevant to it's OU:

reg.exe add HKLM\Software\Microsoft\Windows\CurrentVersion\Runonce /v GPUpdate /t REG_SZ /d "gpupdate /force" /f

Lastly, delete the scripts with passwords in them and restart the computer so it can change its network affiliation from WORKGROUP to the new Domain assignment:

reg.exe add HKLM\Software\Microsoft\Windows\CurrentVersion\Runonce /v DelPS1 /t REG_SZ /d "del c:\scripts*.ps1 /q" /f
restart-computer

This process works and has a positive side-effect: It stops the computer from joining the domain if the Computer Object already exists (which stops any sort of SID problems or unintended OU movements).

It's been suggested by a fellow Redditor that I should create a switch instead of the If statements breaking down the IP subnets.  I'll update this post after I've tested that portion.  Let me know if you have any questions, comments, or suggestions.

PowerShell: Passing PS Variables to Batch Files

I couldn't find many easy ways to transfer variables from PowerShell to cmd.exe batch files so I came up with my own solution.  We delete the old temp variable holding file, use PowerShell to create the variable and write the output to a go-between batch file, call that go-between batch file from your original batch file, and use the transferred variable.  Let me know if you don't get it, have questions, or have better suggestions:

1. Delete the variable-holding batch file from the last time it was used:
If exist d:\computername.bat del d:\computername.bat >nul

2.  From your batch file, create your PowerShell variable (I wanted to pick up the computer name):

powershell "$ComputerName = ('HQ-' + (gwmi win32_systemenclosure).SMBIOSAssetTag);write ('set PC=' + $computername)|out-file d:\computername.bat -encoding ASCII"

Note: In your new computername.bat file you have:
Set PC=HQ-R0xxxx
Which is a valid DOS batch command to create a variable named PC.

3. By writing the results into a batch file (computername.bat), you can call the new batch file from your original one.  Also, by writing a batch command to set a DOS variable, you've now transferred your PowerShell variable to a batch file.  From your original script:
call d:\computername.bat

4.  Now you can use the %PC% variable in your DOS batch file without having to load PowerShell each time you want to pull up the variable.  Obviously you can create all your variables from one PowerShell instance and have the command write out all the Set commands.

Also note, most systems have a restrictive PowerShell script execution policy so writing PS one-liners makes them easier to run since you don't have to worry about the script policy.

Example Batch File:


@Echo Off
if exist d:\computername.bat del d:\computername.bat >nul
PowerShell "$ComputerName = ('HQ-' + (gwmi win32_systemenclosure).SMBIOSAssetTag);write ('set PC=' + $computername)|out-file d:\computername.bat -encoding ASCII"
call d:\computername.bat
:InstallImage
cls
Echo.
Echo                               MAIN IMAGING MENU (%PC%)
Echo.
...


Sunday, November 4, 2012

Virtual PC: Mounting a Windows 7 32-bit VM

The following is an overview of the Windows 7 Virtual Machine (VM) for Windows 7 Virtual PC creation process:
1. Download the AIK (MS Automated Installation Kit) with SP1.
2. Copy a file from the AIK to a hard drive with ample room for the VM.
3. Download and move a script which converts a Windows 7 install CD into a VHD.
4. Download and install Windows 7 Virtual PC.
5. Create a virtual machine.
6. Start the Windows 7 VHD virtual machine.
7. Install Windows 7 as normal.
8. Install the Integration Components.

Detailed Instructions:
1. Download the Automated Installation Kit; which is an ISO file.  ISO's are not normally readable by Windows so I used Slysoft's free virtual clone drive.  Slysoft's software will install a virtual DVD drive which shows up in the system tray with a new drive letter.



Right click on its system tray icon and "mount" the AIK.ISO file that you downloaded.  Let autorun start the AIK install or alternatively double-click on StartCD.exe.  Install the software.

2. Download the Automated Installation Kit Service Pack 1.  Mount the downloaded waik_supplement_en-us (or equiv).ISO and copy the contents into the AIK PETools folder (c:\program files\Windows AIK\Tools\PETools - if you used the defaults).
3. Download the Microsoft WIM2VHD.WSF script. Now you want to copy WIM2VHD.WSF to a large drive.  This will be the location where your new Windows 7 virtual drive will be created.  Also, go into c:\program files\windows AIK\Tools\ and copy imageex.exe (from the appropriate CPU-type subfolder) to the same drive as WIM2VHD.WSF.
4. Make your Windows 7 32-bit DVD/USB source accessible and run this command from an elevated command line (right-click cmd.exe runas-administrator) from the folder which has WIM2VHD.WSF and imageex.exe:
cscript wim2vhd.wsf /wim:d:\sources\install.wim /sku:{professional|enterprise|ultimate} 
note: d: - current Windows 7 install source location; sku type is Windows version (pick one).
 

5.  When the script successfully completes, it will create the VHD file and place it in the folder where you ran the script.  It will have a name similar to this:
(6.1.7600.16385.x86fre.win7_rtm.090713-1255.Enterprise.en-US.vhd)

6. Download Windows Virtual PC. You'll have to pass a Windows license verification authentication first.  Also, check your computer to ensure it can support a virtual machine.  Your BIOS and components have to possess this capability and download and run this Microsoft tool to test your computer.  After you have tested for compatibility and validated your license, install Windows Virtual PC.  You will have the choice of installing the 32 or 64 bit version.  For some reason, I can only use 32-bit virtual machines even though I have the 64-bit Virtual PC software.  I think it might be a software limitation.  Also, be aware that if you've disabled the Windows Update service, this software will be unable to install.

7.  From the Start Menu, open Windows Virtual PC.  Create a Virtual Machine and select your newly created VHD.  After creating the VM, click on Settings and review/alter the settings to suit your needs.



8.  Open the VM and you'll see it perform sysprep steps as it installs Windows 7 in your Virtual Machine.
9. When finished, it will act like a normal Windows installation and need anti-virus, security patches, and other normal utilities.
10.  Ensure to install the Integration Tools found on the VM's Tools menu.  This will allow you to move your mouse in and out of the VM without it being captured.  To break your mouse out of the VM, press the Windows keyboard key.


This blog entry based on information from:
http://forums.mydigitallife.info/archive/index.php/t-32822.html
http://www.hanselman.com/blog/StepByStepTurningAWindows7DVDOrISOIntoABootableVHD VirtualMachine.aspx

Tuesday, March 20, 2012

Customizing Windows 7 Installations

For those of us who install Windows 7 a bunch, there's stuff we'd like to remove, alter, or update.  Thanks to rt7lite, this can now be performed during the initial installation, saving a lot of repetition.  Take a look to see if this free product can help you create more efficient Windows 7 installations.


http://www.rt7lite.com/rt-se7en-lite.html