ich habe versucht die setup.py für eine Windows 7-X64 Installation anzupassen.
Leider scheint da so einiges schief zu gehen.
In der mitgelieferten Version werden ja mehrere Partitionen angelegt, danach der Rechner heruntergefahren und von der PE-Partition gebootet, auf der vor verschiedene Treiber abgelegt wurden. -> Diese Treiber werden beim nächsten Neustart automatisch geladen, ein Netzlaufwerk wird gemountet und die restl. Windows-Dateien werden für die Installation nachgezogen, wobei die gesamte Partitionierung dann wie folgt aussieht:
X:(Windows)->C:(PE,aktiv,lba)->(DataPartition)->unallozierter Speicherplatz
Meine Idee war aber automatisch eine weitere Partition durch die setup.py erzeugen zu lassen, die hinter der DataPartition liegt:
der Code sieht dafür wie folgt aus:
Code: Alles auswählen
#
# This script requires opsi >= 4.0, opsi-linux-bootimage version >= 20111114
#
#alle Groeßen standardmaeßig in byte -> sollte in MB angegeben sein, so ist dies durch das Kuerzel M am VariablenNamen angegeben
if not bootimageVersion or (int(bootimageVersion) < 20111114):
raise Exception(u"This product requires opsi-linux-bootimage version 20111114")
try:
if not backend.isOpsi4():
raise Exception
except:
raise Exception(u"This is a opsi 4.0 product")
modifyPartitions = []
modifyPartitionTemplate = \
'''
<ModifyPartition wcm:action="add">
<Active>%(active)s</Active>
<Format>%(format)s</Format>
<Label>%(label)s</Label>
<Letter>%(letter)s</Letter>
<Extend>false</Extend>
<Order>%(order)s</Order>
<PartitionID>%(partition)s</PartitionID>
</ModifyPartition>
'''
target = '/mnt/hd'
source = SCRIPT_PATH
srcDriversDir = source + '/drivers'
dstDriversDir = target + '/drv'
dstPeDriversDir = target + '/drvpe'
winpeNetworkMode = True
bootPartitionNumber = 0
bootPartitionSize = productProperties.get('boot_partition_size', '0')
bootPartitionLabel = productProperties.get('boot_partition_label', 'BOOT')
bootPartitionLetter = "S"
bootPartitionHidden = True
if (productProperties.get('boot_partition_letter', '-') != '-'):
bootPartitionLetter = productProperties.get('boot_partition_letter')
bootPartitionHidden = False
windowsPartitionNumber = 1
windowsPartitionSize = productProperties.get('windows_partition_size','100%')
windowsPartitionLabel =productProperties.get('windows_partition_label', 'WINDOWS')
windowsPartitionLetter = "C"
winpePartitionNumber = 2
winpePartitionSize = "4000M"
winpePartitionLabel = "WINPE"
winpePartitionLetter = "X"
#Hole dir die Eigenschaften der D:\ Partition
dataPartitionNumber = 0
datapartioncreate = productProperties.get('data_partition_create', true)
dataPartitionSize = productProperties.get('data_partition_size', 20480)
dataPartitionLabel = productProperties.get('data_partition_label', 'DATA')
dataPartitionLetter = productProperties.get('data_partition_letter', 'D')
#Hole dir die Eigenschaften von E:\
#Idee: aktiviere die Spare-Partition nur, wenn!! diese als aktiviert angegeben ist
sparePartitionNumber = 0
sparepartioncreate = productProperties.get('spare_partition_create', true)
sparePartitionSize = productProperties.get('spare_partition_size', '100%')
sparePartitionLabel = productProperties.get('spare_partition_label', 'Spielwiese')
sparePartitionLetter = productProperties.get('spare_partition_letter', 'E')
blockAlignment = False
if (str(productProperties.get('blockAlignment', 'true')).lower() == 'true'):
blockAlignment = True
if (str(productProperties.get('winpenetworkmode', 'true')).lower() == 'false'):
winpeNetworkMode = False
#Abfrage eigentlich sinnlos, weil unsere Installation immer zwingend eine D:\ Partition vorraussetzt
if (windowsPartitionSize != "100%" and datapartioncreate):
dataPartitionNumber = 3
if (sparepartioncreate):
sparePartitionNumber = 4
activePartition = "true"
if not bootPartitionSize.startswith("0"):
bootPartitionNumber = 1
windowsPartitionNumber += 1
winpePartitionNumber += 1
if (dataPartitionNumber > 0):
dataPartitionNumber += 1
if (sparePartitionNumber > 0):
sparePartitionNumber += 1
modifyPartitions.append(
modifyPartitionTemplate % {
"active": activePartition,
"format": "NTFS",
"label": bootPartitionLabel,
"letter": bootPartitionLetter.upper(),
"order": len(modifyPartitions) + 1,
"partition": bootPartitionNumber,
}
)
activePartition = "false"
modifyPartitions.append(
modifyPartitionTemplate % {
"active": activePartition,
"format": "NTFS",
"label": windowsPartitionLabel,
"letter": windowsPartitionLetter.upper(),
"order": len(modifyPartitions) + 1,
"partition": windowsPartitionNumber,
}
)
modifyPartitions.append(
modifyPartitionTemplate % {
"active": "false",
"format": "",
"label": winpePartitionLabel,
"letter": winpePartitionLetter.upper(),
"order": len(modifyPartitions) + 1,
"partition": winpePartitionNumber,
}
)
if (dataPartitionNumber > 0):
modifyPartitions.append(
modifyPartitionTemplate % {
"active": "false",
"format": "NTFS",
"label": dataPartitionLabel,
"letter": dataPartitionLetter.upper(),
"order": len(modifyPartitions) + 1,
"partition": dataPartitionNumber,
}
)
#lege hier genauso die Spare-Partition als Objekt an
if (sparePartitionNumber > 0):
modifyPartitions.append(
modifyPartitionTemplate % {
"active": "false",
"format": "NTFS",
"label": sparePartitionLabel,
"letter": sparePartitionLetter.upper(),
"order": len(modifyPartitions) + 1,
"partition": sparePartitionNumber,
}
)
pi = open(PATCHA_IN, 'a')
print >> pi, "windows_partition_number=%d" % windowsPartitionNumber
print >> pi, "winpe_partition_letter=%s" % winpePartitionLetter.upper()
print >> pi, "modify_partitions=%s" %''.join(modifyPartitions).replace('\n', '').replace('<Format></Format>', '')
pi.close()
# Do hardware inventory
logger.notice(u"Fetching opsi hw audit configuration")
hwconfig = backend.auditHardware_getConfig()
logger.notice(u"Running hardware inventory")
auditHardwareOnHosts = auditHardware(config = hwconfig, hostId = clientId)
logger.notice(u"Sending hardware information to service")
backend.auditHardwareOnHost_setObsolete(clientId)
backend.auditHardwareOnHost_updateObjects(auditHardwareOnHosts)
# Get harddisks
disks = getHarddisks()
# Use first Harddisk
disk = disks[0]
if blockAlignment:
disk.setBlockAlignment(blockAlignment)
scriptMessageSubject.setMessage(u"Verwende Festplatte %s (%0.0f MB)." %(disk.device, (float(disk.size)/(1024*1024))))
# Check disk size
if (disk.size < 85000*1024*1024):
#Disk smaller than 85000 MB => give up, Anpassung fuers IWW
raise Exception(u"Die Festplatte ist zu klein")
# Get current partitions
partitions = disk.getPartitions()
if not partitions:
# No partition found on harddisk
scriptMessageSubject.setMessage(u"Keine Partitionen auf %s gefunden" % disk.device)
# Create new partitiontable
disk.deletePartitionTable()
# Partition table deleted => delete all netboot product states
backend.backend_setOptions( { 'addProductPropertyStateDefaults': False } )
deletePocs = []
for poc in backend.productOnClient_getObjects(clientId = clientId):
if ((poc.productType == 'NetbootProduct') and (poc.productId != productId)) or \
((poc.productType == 'LocalbootProduct') and (poc.installationStatus == 'not_installed') and (poc.actionRequest == 'none')):
deletePocs.append(poc)
backend.productOnClient_deleteObjects(deletePocs)
# Create partitions
diskSizeM = (float(disk.size)/(1024*1024)) #Angabe in MB
diskTotalSectors = disk.sectors
bootPartitionSizeM = 0
if not bootPartitionSize.startswith("0"):
# Create boot partition
if not blockAlignment:
disk.createPartition(start = "0M", end = bootPartitionSize, fs ="ntfs")
bootPartitionSizeM = int(bootPartitionSize.upper().replace('M','').replace('G', '').replace('B', ''))
if (bootPartitionSize.upper().find('G') != -1):
bootPartitionSizeM *= 1024
logger.notice(u"Boot partition (%d) size is %dM" %(bootPartitionNumber, bootPartitionSizeM))
else:
disk.createPartition(start = "2048S", end = bootPartitionSize, fs = "ntfs")
bootPartitionSizeM = int(bootPartitionSize.upper().replace('M','').replace('G', '').replace('B', ''))
if (bootPartitionSize.upper().find('G') != -1):
bootPartitionSizeM *= 1024
logger.notice(u"Boot partition (%d) size is %dM" % (bootPartitionNumber, bootPartitionSizeM))
peStartM = int(diskSizeM - 4000)
boundaryM = int(diskSizeM)
if (windowsPartitionSize != "100%"):
sizeM = 0
if (windowsPartitionSize.find('%') != -1):
percent = int(windowsPartitionSize.replace('%', ''))
windowsPartitionSizeM =int((float(percent)/100.0)*float(diskSizeM-bootPartitionSizeM))
else:
windowsPartitionSizeM = int(windowsPartitionSize.upper().replace('M','').replace('G', '').replace('B', ''))
if (windowsPartitionSize.upper().find('G') != -1):
windowsPartitionSizeM *= 1024
dataSizeM = diskSizeM - windowsPartitionSizeM
logger.notice(u"Windows partiton (%s) size is %dM, data partition (%d) size is %dM" \
% (windowsPartitionNumber, windowsPartitionSizeM, dataPartitionNumber, dataSizeM))
if (dataSizeM <= 0):
raise Exception(u"Not enough disk space for windows partiton size %dM" % windowsPartitionSizeM)
boundaryM = bootPartitionSizeM + windowsPartitionSizeM
peStartM = boundaryM - 4000
# Create windows partition
disk.createPartition(start = "%dM" % bootPartitionSizeM, end = "%dM" % peStartM, fs = "ntfs")
# Create winpe partition
disk.createPartition(start = "%dM" % peStartM, end = "%dM" % boundaryM, fs = "fat32", boot = True)
if (dataPartitionNumber > 0):
#Berechne als erstes die Groeße der D:\ Partition in ganzen MB
if (dataPartitionSize.find('%') != -1):
percent = int(dataPartitionSize.replace('%', ''))
dataPartitionsizeM =int((float(percent)/100.0)*float(diskSizeM-bootPartitionSizeM-windowsPartitionSizeM))
else:
dataPartitionsizeM = int(dataPartitionSize.upper().replace('M','').replace('G', '').replace('B', ''))
if (dataPartitionSize.upper().find('G') != -1):
dataPartitionsizeM *= 1024
#sollte ausreichend Platz auf der Platte sein, um die volle 20GB Partition anzulegen
if ((boundaryM + dataPartitionSizeM) <= diskSizeM):
# Create data partition
disk.createPartition(start = "%dM" % boundaryM, end = "%dM" % (boundaryM + dataPartitionSizeM), fs = "ntfs")
#wenn noch Platz ist, verschiebe jetzt die BoundaryM um die Groeße der Datenpartition
boundaryM += dataPartitionSizeM
#Falls ueberhaupt kein Platz mehr auf der platte sein sollte, so schreibe das in log, werfe eine Exception und deaktivere die E:\ Partition
elif((boundaryM - diskSizeM) > 0):
logger.notice(u"Es steht auf der ersten Platte nicht genug Speicher fuer D:\ zur Verfuegung")
raise Exception(u"Problem, absolut kein Platz mehr fuer D:\ auf der Platte")
sparePartitionNumber = 0
#ansonsten lege die max. moegliche große Partition D:\ an
else:
disk.createPartition(start = "%dM" % boundaryM, end = "%dM" % diskSizeM, fs = "ntfs")
#Deaktivere die sparePartition E:
sparePartitionNumber = 0
#lege jetzt die SparePartition an, aber nur, wenn vorher D:\ in voller Groeße angelegt werden konnte
if (sparePartitionNumber > 0):
#Berechne als erstes die Groeße der D:\ Partition in ganzen MB
if (sparePartitionSize.find('%') != -1):
percent = int(sparePartitionSize.replace('%', ''))
sparePartitionSizeM =int((float(percent)/100.0)*float(diskSizeM-bootPartitionSizeM-windowsPartitionSizeM-dataPartitionSizeM))
else:
sparePartitionsizeM = int(sparePartitionSize.upper().replace('M','').replace('G', '').replace('B', ''))
if (sparePartitionSize.upper().find('G') != -1):
sparePartitionsizeM *= 1024
#sollte ausreichend Platz auf der Platte sein, um die volle 20GB Partition anzulegen
if ((boundaryM + sparePartitionSizeM) <= diskSizeM):
# Create data partition
disk.createPartition(start = "%dM" % boundaryM, end = "%dM" % (boundaryM + sparePartitionSizeM), fs = "ntfs")
#Falls ueberhaupt kein Platz mehr auf der platte sein sollte, so schreibe das in log, lege kein E:\ an
elif((boundaryM - diskSizeM) > 0):
logger.notice(u"Es steht auf der ersten Platte nicht genug Speicher fuer E:\ zur Verfuegung")
#ansonsten lege die max. moegliche große Partition E:\ an
else:
disk.createPartition(start = "%dM" % boundaryM, end = "%dM" % diskSizeM, fs = "ntfs")
partitions = disk.getPartitions()
# Create fat32 filesystem on winpe partition
disk.createFilesystem(partition = winpePartitionNumber, fs = "fat32")
if (dataPartitionNumber > 0):
# Create ntfs filesystem on data partition
disk.createFilesystem(partition = dataPartitionNumber, fs = "ntfs")
if (sparePartitionNumber > 0):
# Create ntfs filesystem on data partition
disk.createFilesystem(partition = sparePartitionNumber, fs = "ntfs")
# Write Master Boot Record
disk.writeMasterBootRecord(system = 'vista')
# Write Partition Boot Record
disk.writePartitionBootRecord(partition = winpePartitionNumber, fsType ='fat32nt60')
# Mount partition
disk.mountPartition(partition = winpePartitionNumber, mountpoint = target)
# Copy PE files
depot.copy(source + '/winpe/*', target)
if not os.path.exists(os.path.join(target, 'bootmgr')):
raise Exception("bootmgr not found in winpe, please check winpe folder on server")
# Copy Windows installation files
if not winpeNetworkMode:
depot.copy(source + '/installfiles', target)
# Copy opsi files
depot.copy(source + '/opsi', target + '/')
# Copy opsi-client-agent
depot.copy('/opsi-client-agent', target + '/opsi/')
copy(target + '/opsi/opsi-client-agent/files/opsi/postinst.d/*', target + '/opsi/postinst.d/')
# Copy custom files
depot.copy(source + '/custom/unattend.xml', target + '/opsi/')
depot.copy(source + '/custom/postinst.d/*', target + '/opsi/postinst.d/')
# Copy sysconf.ini to opsi-client-agent config dir
copy(SYSCONF_INI , target + '/opsi/opsi-client-agent/files/opsi/cfg')
# Integrate drivers
os.makedirs(dstDriversDir)
os.makedirs(dstPeDriversDir)
if depot.exists(srcDriversDir):
scriptMessageSubject.setMessage("Treiber-Verzeichnis '%s' gefunden, starte Treiberintegration" % srcDriversDir)
additionalDrivers = [ ad.strip() for ad in(u','.join(productPropertyValues.get('additional_drivers',[u'']))).split(u',') ]
integrateAdditionalWindowsDrivers(srcDriversDir + u'/drivers/additional', dstDriversDir, additionalDrivers, messageSubject = scriptMessageSubject, srcRepository = depot, auditHardwareOnHosts = auditHardwareOnHosts)
integrateWindowsHardwareDrivers(srcDriversDir, dstDriversDir, auditHardwareOnHosts, messageSubject = scriptMessageSubject, srcRepository = depot)
# Create work.cmd
logger.notice("Creating work.cmd")
f = open(target + '/opsi/work.cmd', 'w')
print >> f, "@echo off\r"
print >> f, "copy c:\\opsi\\unattend.xml x:\\unattend.xml >nul\r"
print >> f, ":init\r"
print >> f, "set mount_try_count=0\r"
print >> f, "c:\\opsi\\SetWallpaper.exe c:\\opsi\\opsibg.bmp >nul 2>nul\r"
print >> f, "echo Initializing ..... please wait ......\r"
print >> f, "wpeinit\r"
if winpeNetworkMode and (depot._url.startswith('smb:') or depot._url.startswith('cifs:')):
match = re.search('^smb://([^/]+)/([^/]+)(.*)$', depot._url, re.IGNORECASE)
if not match:
raise Exception("Bad depot-URL '%s'" % depot._url)
hn = match.group(1)
sn = match.group(2)
pn = match.group(3)
print >> f, "goto mountshare\r"
print >> f, ":drvloadnetwork\r"
if os.path.exists(dstDriversDir):
storageControllerInfo = disk.getControllerInfo()
for filePath in findFiles(prefix = dstDriversDir, directory = dstDriversDir, includeFile = re.compile('\.inf$', re.IGNORECASE), returnDirs = False):
infFile = InfFile(filePath)
if infFile.isDeviceKnown(usedNetworkDevice['vendorId'], usedNetworkDevice['deviceId']):
logger.info(u"Integrating winpe driver for network controller: %s" % usedNetworkDevice)
filePath = filePath[len(target):]
if filePath.startswith('/'):
filePath = filePath[1:]
filePath = 'c:\\' + filePath.replace('/', '\\')
logger.notice("Adding to work.cmd: drvload %s\r" % filePath )
print >> f, "drvload %s\r" % filePath
if storageControllerInfo and infFile.isDeviceKnown(storageControllerInfo['vendorId'], storageControllerInfo['deviceId']):
logger.info(u"Integrating winpe driver for storage controller: %s" % storageControllerInfo)
copy(os.path.dirname(filePath), dstPeDriversDir)
encodedPcpatchPassword = backend.getPcpatchPassword(hostId = clientId)
print >> f, "goto mountshare\r"
print >> f, ":waitnet\r"
print >> f, "echo Waiting for the network ......\r"
print >> f, "ping -n 5 127.0.0.1 >nul\r"
print >> f, ":mountshare\r"
print >> f, "set /a mount_try_count=%mount_try_count%+1\r"
print >> f, "net use /y /delete * >nul\r"
print >> f, "ping -n 5 127.0.0.1 >nul\r"
print >> f, "c:\\opsi\\opsinetmount.exe --keyfile=c:\\opsi\\opsi-client-agent\\files\\opsi\\cfg\\config.ini --user=%s\\pcpatch --drive=o --share=\\\\%s\\%s --encrypted-pass=%s \r" % (hn, hn, sn, encodedPcpatchPassword)
print >> f, "if not %ERRORLEVEL%==0 (\r"
print >> f, " if %mount_try_count%==5 goto drvloadnetwork\r"
print >> f, " if %mount_try_count%==15 goto init\r"
print >> f, " goto waitnet\r"
print >> f, ")\r"
print >> f, ":install\r"
print >> f, "o:%s\\%s\\installfiles\\setup.exe %s" % (pn.replace('/', '\\'), productId, "/unattend:x:\\unattend.xml\r")
else:
print >> f, ":install\r"
print >> f, "c:\\installfiles\\setup.exe /unattend:x:\\unattend.xml\r"
print >> f, "if not %ERRORLEVEL%==0 goto init\r"
f.close()
# Create startnet.cmd
logger.notice(u"Creating startnet.cmd")
f = open(target + '/opsi/startnet.cmd', 'w')
print >> f, "@echo off\r"
print >> f, "copy c:\\opsi\\work.cmd x:\\work.cmd >nul\r"
print >> f, "x:\\work.cmd"
f.close()
# Create diskpart.txt
logger.notice(u"Creating diskpart.txt")
f = open(target + '/opsi/diskpart.txt', 'w')
f = open(target + '/opsi/diskpart.txt', 'w')
print >> f, "list disk\r"
print >> f, "select disk 0\r"
print >> f, "list partition\r"
print >> f, "list volume\r"
print >> f, "select partition %d\r" % winpePartitionNumber
print >> f, "delete partition noerr override\r"
print >> f, "select partition %d\r" % (winpePartitionNumber - 1)
print >> f, "extend\r"
if bootPartitionNumber and bootPartitionHidden:
print >> f, "select volume %s\r" % bootPartitionLetter
print >> f, "remove letter=%s\r" % bootPartitionLetter
print >> f, "exit\r"
f.close()
# Patch files
logger.notice(u"Patching unattend.xml and config.ini")
for i in ( target + '/opsi/unattend.xml', target + '/opsi/opsi-client-agent/files/opsi/cfg/config.ini' ):
execute('/usr/local/bin/patcha %s' % i)
execute('/usr/local/bin/patcha -f %s %s' % (PATCHA_IN, i))
# Debug output of file content
for fn in ('/opsi/work.cmd', '/opsi/startnet.cmd', '/opsi/diskpart.txt'):
execute("%s '%s'" % (which('cat'), target + fn))
# Umount partition
disk.umountPartition(partition = winpePartitionNumber)
# Reboot
reboot()
die Partitionen sehen dann wie folgt aus:
X:(Windows)->C:(PE,aktiv,lba)->(DataPartition)->(SparePartition)
Leider funktionieren hier jedoch die startnet.cmd und die work.cmd nicht mehr. Da ich nur noch folgende Fehlermeldung im Dosfenster erhalte:
Waiting for Network
Systemfehler 1222 aufgetreten
Das Netzwerk ist nicht vorhanden oder wurde nicht gestartet
mountresult: 1222: Das Netzwerk ist nicht vorhanden oder wurde nicht gestartet
Hat jemand eine Idee, woher dieser Fehler resultiert?
Liegt der Fehler in meinem angepassten Script? Oder ist das eine interne Beschränkung von OPSI?
Besten Dank für eure Antworten
Sebastian